|
26791
|
1115
|
25
|
2026-05-12T13:38:49.058987+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778593129058_m2.jpg...
|
Firefox
|
Claude — Personal
|
True
|
claude.ai/settings/usage
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Screenpipe — Archive
Screenpipe — Archive
All docs Screenpipe — Archive
Screenpipe — Archive
All docs · AFFiNE
All docs · AFFiNE
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
Claude
Claude
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Home
Close sidebar
New chat
New chat
⇧⌘O
Search
Search
⌘K
Chats
Chats
Projects
Projects
Code
Code
Customize
Customize
Design
Design
More
More
Starred
Starred
Bulgarian citizenship application process for EU residents
Bulgarian citizenship application process for EU residents
Dawarich location tracking project
Dawarich location tracking project
Recents Hide
Recents
Hide
Screenpipe data sync and retention management
Screenpipe data sync and retention management
Screenpipe sync script failing after recent migrations...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.5,"top":0.0518755,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.51329786,"top":0.06304868,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"bounds":{"left":0.5,"top":0.08459697,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All docs · AFFiNE","depth":5,"bounds":{"left":0.51329786,"top":0.09577015,"width":0.029587766,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.5,"top":0.11731844,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"bounds":{"left":0.51329786,"top":0.12849163,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.5,"top":0.15003991,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.51329786,"top":0.16121309,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.5,"top":0.18276137,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.51329786,"top":0.19393456,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.5,"top":0.21548285,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.51329786,"top":0.22665602,"width":0.040724736,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.5,"top":0.2482043,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.51329786,"top":0.25937748,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude","depth":4,"bounds":{"left":0.5,"top":0.28092578,"width":0.06881649,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Claude","depth":5,"bounds":{"left":0.51329786,"top":0.29209897,"width":0.012134309,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.55651593,"top":0.28810853,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.5028258,"top":0.31524342,"width":0.06333112,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.5028258,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.51379657,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.5249335,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.53607047,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.5472075,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Home","depth":10,"bounds":{"left":0.57413566,"top":0.06464485,"width":0.022606382,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close sidebar","depth":11,"bounds":{"left":0.65109706,"top":0.058260176,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"New chat","depth":12,"bounds":{"left":0.57147604,"top":0.096568234,"width":0.090259306,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New chat","depth":16,"bounds":{"left":0.5834442,"top":0.10215483,"width":0.020777926,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"⇧⌘O","depth":15,"bounds":{"left":0.6449468,"top":0.10335196,"width":0.010804521,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Search","depth":12,"bounds":{"left":0.57147604,"top":0.12290503,"width":0.090259306,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search","depth":16,"bounds":{"left":0.5834442,"top":0.12849163,"width":0.01512633,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"⌘K","depth":15,"bounds":{"left":0.6492686,"top":0.12968874,"width":0.006482713,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chats","depth":13,"bounds":{"left":0.57147604,"top":0.14924182,"width":0.090259306,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Chats","depth":17,"bounds":{"left":0.5834442,"top":0.15482841,"width":0.013131649,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Projects","depth":13,"bounds":{"left":0.57147604,"top":0.17557861,"width":0.090259306,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Projects","depth":17,"bounds":{"left":0.5834442,"top":0.1811652,"width":0.018284574,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":13,"bounds":{"left":0.57147604,"top":0.20231445,"width":0.090259306,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":17,"bounds":{"left":0.5834442,"top":0.20790103,"width":0.011801862,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Customize","depth":13,"bounds":{"left":0.57147604,"top":0.22865124,"width":0.090259306,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Customize","depth":17,"bounds":{"left":0.5834442,"top":0.23423783,"width":0.023271276,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Design","depth":13,"bounds":{"left":0.57147604,"top":0.25538707,"width":0.090259306,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Design","depth":16,"bounds":{"left":0.5834442,"top":0.26097366,"width":0.01512633,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More","depth":12,"bounds":{"left":0.57147604,"top":0.28172386,"width":0.090259306,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":15,"bounds":{"left":0.5834442,"top":0.28731045,"width":0.011635638,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Starred","depth":13,"bounds":{"left":0.57147604,"top":0.32322428,"width":0.090259306,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Starred","depth":14,"bounds":{"left":0.57413566,"top":0.3236233,"width":0.01412899,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Bulgarian citizenship application process for EU residents","depth":16,"bounds":{"left":0.57147604,"top":0.3423783,"width":0.090259306,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Bulgarian citizenship application process for EU residents","depth":19,"bounds":{"left":0.57413566,"top":0.34796488,"width":0.12533244,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Dawarich location tracking project","depth":16,"bounds":{"left":0.57147604,"top":0.36871508,"width":0.090259306,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dawarich location tracking project","depth":19,"bounds":{"left":0.57413566,"top":0.37430167,"width":0.07480053,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Recents Hide","depth":13,"bounds":{"left":0.57147604,"top":0.4102155,"width":0.032247342,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Recents","depth":14,"bounds":{"left":0.57413566,"top":0.41061452,"width":0.015458777,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Hide","depth":15,"bounds":{"left":0.592254,"top":0.41061452,"width":0.00880984,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Screenpipe data sync and retention management","depth":16,"bounds":{"left":0.57147604,"top":0.4293695,"width":0.090259306,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe data sync and retention management","depth":19,"bounds":{"left":0.57413566,"top":0.4349561,"width":0.10721409,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Screenpipe sync script failing after recent migrations","depth":16,"bounds":{"left":0.57147604,"top":0.4557063,"width":0.090259306,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-7762689051193437192
|
3897192829203826383
|
visual_change
|
accessibility
|
NULL
|
Screenpipe — Archive
Screenpipe — Archive
All docs Screenpipe — Archive
Screenpipe — Archive
All docs · AFFiNE
All docs · AFFiNE
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
Claude
Claude
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Home
Close sidebar
New chat
New chat
⇧⌘O
Search
Search
⌘K
Chats
Chats
Projects
Projects
Code
Code
Customize
Customize
Design
Design
More
More
Starred
Starred
Bulgarian citizenship application process for EU residents
Bulgarian citizenship application process for EU residents
Dawarich location tracking project
Dawarich location tracking project
Recents Hide
Recents
Hide
Screenpipe data sync and retention management
Screenpipe data sync and retention management
Screenpipe sync script failing after recent migrations...
|
26790
|
NULL
|
NULL
|
NULL
|
|
21258
|
930
|
11
|
2026-05-11T17:32:38.691200+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778520758691_m1.jpg...
|
Claude
|
Claude
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Skip to content
Skip to content
Click to collapse
Skip to content
Skip to content
Click to collapse
⌘B
Drag to resize
Collapse sidebar
Search
Chat
Cowork
Code
New chat ⌘N
New chat
⌘N
Projects
Artifacts
Customize
Pinned
Bulgarian citizenship application process for EU residents
More options for Bulgarian citizenship application process for EU residents
Dawarich location tracking project
More options for Dawarich location tracking project
Recents
View all
Screenpipe data sync and retention management
More options for Screenpipe data sync and retention management
Screenpipe sync script failing after recent migrations
More options for Screenpipe sync script failing after recent migrations
Hubspot BadRequest headers debugging
More options for Hubspot BadRequest headers debugging
Monthly expense tracking
More options for Monthly expense tracking
Exporting transaction data from Notion to finance hub
More options for Exporting transaction data from Notion to finance hub
💬 How much have I spent for groc…
More options for 💬 How much have I spent for groc…
April 2026 spending by category
More options for April 2026 spending by category
Code diff review
More options for Code diff review
HubSpot rate limit implementation strategy
More options for HubSpot rate limit implementation strategy
Screenpipe retention policy code location
More options for Screenpipe retention policy code location
Viewing retention policy in screenpipe
More options for Viewing retention policy in screenpipe
Clean shot x video recording termination issue
More options for Clean shot x video recording termination issue
HubSpot rate limit handling with executeRequest
More options for HubSpot rate limit handling with executeRequest
Untitled
More options
💬 Screen pipe. Is there ability…
More options for 💬 Screen pipe. Is there ability…
SMB mount access inconsistency between Finder and iTerm
More options for SMB mount access inconsistency between Finder and iTerm
💬 What is the best switch I can…
More options for 💬 What is the best switch I can…
Permission denied on screenpipe volume
More options for Permission denied on screenpipe volume
Screenpipe sync database attachment error
More options for Screenpipe sync database attachment error
Last swimming outing with Dani
More options for Last swimming outing with Dani
Lukas Pro
Get apps and extensions
Screenpipe data sync and retention management, rename chat
Screenpipe data sync and retention management
More options for Screenpipe data sync and retention management
Share chat
Claude finished the response
You said: Lets start from the beginning with the fresh mind.
You said: Lets start from the beginning with the fresh mind.
Pasted Text, pasted, 495 lines
#!/bin/bash # screenpipe_sync.sh # Syncs Screenpipe SQLite data to a NAS archive database (append-only, no deletions). # Also copies the day's video/frame data folder to the NAS. # # Schema-drift tolerant: if Screenpipe migrations add new columns to the source DB, # the NAS archive gets ALTER TABLE'
PASTED
Lets start from the beginning with the fresh mind. There is a script for screenpipe to copy data for day from mac to nas. There are two issues I want to work with. Firsts if I reinstall the mac version it starts from fresh id 1. That causes some issues. How to make sure the data are valid. I don't want some overcomplicated flow. I was thinking about making new db every 3 months. Secodn issue is that I wan to implement cleanup (retention policy) on mac original screenpipe db. I want script that will remove data that are 7 days old or older for example. ANd lastly I want to extedn the script to work with audio as well. What od you need
20:19
Retry
Edit
Copy
Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…
Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…
Analyzed three technical challenges and identified clarifying questions needed
Analyzed three technical challenges and identified clarifying questions needed
Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether reinstalls have already happened). Before I touch the script, a few things:
Issue 1 — ID collisions / archive rotation
Has a reinstall already happened, or is the current
archive.db
still from one continuous install? If collisions already exist I need to handle that first; if not, we have a clean slate.
Quarterly rotation works, but it doesn't actually solve reinstalls
within
a quarter. A cleaner option that I'd lean toward: add an
install_id
column (UUID generated once and stored in a tiny
_meta
table in the source DB) to every synced table, and make
(install_id, id)
the logical key. FK joins just gain one extra predicate. Reinstall → new install_id → no collisions, ever. You can still rotate the archive DB quarterly for file-size reasons, but it's no longer load-bearing.
Do you ever run cross-period queries (e.g. "every frame mentioning JY-20458 across all time")? That answers whether quarterly sharding is acceptable or whether one growing DB is better.
Issue 2 — Mac-side retention
Your launch command already has
--retention-days 7
. Is that not actually deleting anything, or do you want a separate scripted retention you can trust/observe independently?
Should retention also wipe the matching
~/.screenpipe/data/data/YYYY-MM-DD/
folders, or only DB rows? (CLI flag does both I believe; a script should match.)
Run order matters: sync writes
yesterday
, retention deletes
>7 days old
— no overlap, but I'd still chain them (sync → retention → log) in one cron entry so a failed sync blocks the delete. OK with that?
Issue 3 — Audio
Your current launch flag is
--disable-audio
, so right now there's no audio data to sync. Are you planning to enable it, or is this just to future-proof the script?
I need the audio schema. Could you run this and paste the output:
Copy to clipboard
sqlite3 ~/.screenpipe/db.sqlite ".schema" | grep -iE -A 20 "audio|transcription"
And:
ls ~/.screenpipe/data/data/$(date -v-1d +%Y-%m-%d)/ | head
so I can see what audio files look like on disk alongside the mp4 frames.
Once I have those, I'll restructure the script in one go rather than piecemeal.
Copy
Give positive feedback
Give negative feedback
Retry
Pasted Text, pasted, 208 lines
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ sqlite3 ~/.screenpipe/db.sqlite ".schema" | grep -iE -A 20 "audio|transcription" CREATE TABLE audio_chunks ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_path TEXT NOT NULL , timestamp TIMESTAMP, sync_id TEXT, machine_id TEXT, synced_at DATETIME, ev
PASTED
Remove Pasted Text, pasted, 208 lines
ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well.
ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well.
Add files, connectors, and more
Model: Opus 4.7 Adaptive
Opus 4.7
Adaptive
Send message
Claude is AI and can make mistakes. Please double-check responses.
Claude is AI and can make mistakes. Please double-check responses....
|
[{"role":"AXLink","text":& [{"role":"AXLink","text":"Skip to content","depth":14,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Skip to content","depth":15,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Click to collapse","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"⌘B","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drag to resize","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Collapse sidebar","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Chat","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cowork","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New chat ⌘N","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New chat","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"⌘N","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Projects","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Artifacts","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Customize","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Pinned","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Bulgarian citizenship application process for EU residents","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Bulgarian citizenship application process for EU residents","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Dawarich location tracking project","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Dawarich location tracking project","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Recents","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"View all","depth":16,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe data sync and retention management","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe data sync and retention management","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe sync script failing after recent migrations","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe sync script failing after recent migrations","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hubspot BadRequest headers debugging","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Hubspot BadRequest headers debugging","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Monthly expense tracking","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Monthly expense tracking","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Exporting transaction data from Notion to finance hub","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Exporting transaction data from Notion to finance hub","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"💬 How much have I spent for groc…","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for 💬 How much have I spent for groc…","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"April 2026 spending by category","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for April 2026 spending by category","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code diff review","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Code diff review","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HubSpot rate limit implementation strategy","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for HubSpot rate limit implementation strategy","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe retention policy code location","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe retention policy code location","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Viewing retention policy in screenpipe","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Viewing retention policy in screenpipe","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Clean shot x video recording termination issue","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Clean shot x video recording termination issue","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HubSpot rate limit handling with executeRequest","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for HubSpot rate limit handling with executeRequest","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Untitled","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"💬 Screen pipe. Is there ability…","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for 💬 Screen pipe. Is there ability…","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"SMB mount access inconsistency between Finder and iTerm","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for SMB mount access inconsistency between Finder and iTerm","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"💬 What is the best switch I can…","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for 💬 What is the best switch I can…","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Permission denied on screenpipe volume","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Permission denied on screenpipe volume","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe sync database attachment error","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe sync database attachment error","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Last swimming outing with Dani","depth":18,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Last swimming outing with Dani","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Lukas Pro","depth":15,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Get apps and extensions","depth":15,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe data sync and retention management, rename chat","depth":19,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Screenpipe data sync and retention management","depth":21,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"More options for Screenpipe data sync and retention management","depth":19,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Share chat","depth":21,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Claude finished the response","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"You said: Lets start from the beginning with the fresh mind.","depth":20,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"You said: Lets start from the beginning with the fresh mind.","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Pasted Text, pasted, 495 lines","depth":21,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"#!/bin/bash # screenpipe_sync.sh # Syncs Screenpipe SQLite data to a NAS archive database (append-only, no deletions). # Also copies the day's video/frame data folder to the NAS. # # Schema-drift tolerant: if Screenpipe migrations add new columns to the source DB, # the NAS archive gets ALTER TABLE'","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PASTED","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Lets start from the beginning with the fresh mind. There is a script for screenpipe to copy data for day from mac to nas. There are two issues I want to work with. Firsts if I reinstall the mac version it starts from fresh id 1. That causes some issues. How to make sure the data are valid. I don't want some overcomplicated flow. I was thinking about making new db every 3 months. Secodn issue is that I wan to implement cleanup (retention policy) on mac original screenpipe db. I want script that will remove data that are 7 days old or older for example. ANd lastly I want to extedn the script to work with audio as well. What od you need","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"20:19","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Retry","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Edit","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…","depth":21,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Analyzed three technical challenges and identified clarifying questions needed","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Analyzed three technical challenges and identified clarifying questions needed","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether reinstalls have already happened). Before I touch the script, a few things:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Issue 1 — ID collisions / archive rotation","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Has a reinstall already happened, or is the current","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"archive.db","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"still from one continuous install? If collisions already exist I need to handle that first; if not, we have a clean slate.","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Quarterly rotation works, but it doesn't actually solve reinstalls","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"within","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"a quarter. A cleaner option that I'd lean toward: add an","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"install_id","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"column (UUID generated once and stored in a tiny","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"_meta","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"table in the source DB) to every synced table, and make","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"(install_id, id)","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the logical key. FK joins just gain one extra predicate. Reinstall → new install_id → no collisions, ever. You can still rotate the archive DB quarterly for file-size reasons, but it's no longer load-bearing.","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Do you ever run cross-period queries (e.g. \"every frame mentioning JY-20458 across all time\")? That answers whether quarterly sharding is acceptable or whether one growing DB is better.","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Issue 2 — Mac-side retention","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Your launch command already has","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"--retention-days 7","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":". Is that not actually deleting anything, or do you want a separate scripted retention you can trust/observe independently?","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Should retention also wipe the matching","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"~/.screenpipe/data/data/YYYY-MM-DD/","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"folders, or only DB rows? (CLI flag does both I believe; a script should match.)","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Run order matters: sync writes","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"yesterday","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":", retention deletes","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":">7 days old","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"— no overlap, but I'd still chain them (sync → retention → log) in one cron entry so a failed sync blocks the delete. OK with that?","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Issue 3 — Audio","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Your current launch flag is","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"--disable-audio","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":", so right now there's no audio data to sync. Are you planning to enable it, or is this just to future-proof the script?","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"I need the audio schema. Could you run this and paste the output:","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Copy to clipboard","depth":27,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"sqlite3 ~/.screenpipe/db.sqlite \".schema\" | grep -iE -A 20 \"audio|transcription\"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"And:","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ls ~/.screenpipe/data/data/$(date -v-1d +%Y-%m-%d)/ | head","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"so I can see what audio files look like on disk alongside the mp4 frames.","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Once I have those, I'll restructure the script in one go rather than piecemeal.","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Copy","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give positive feedback","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give negative feedback","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Retry","depth":22,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Pasted Text, pasted, 208 lines","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ sqlite3 ~/.screenpipe/db.sqlite \".schema\" | grep -iE -A 20 \"audio|transcription\" CREATE TABLE audio_chunks ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_path TEXT NOT NULL , timestamp TIMESTAMP, sync_id TEXT, machine_id TEXT, synced_at DATETIME, ev","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"PASTED","depth":29,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove Pasted Text, pasted, 208 lines","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well.","depth":25,"on_screen":true,"value":"ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well.","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well.","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add files, connectors, and more","depth":27,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Model: Opus 4.7 Adaptive","depth":27,"bounds":{"left":0.18125,"top":0.0,"width":0.10902778,"height":0.035555556},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Opus 4.7","depth":29,"bounds":{"left":0.18819444,"top":0.0,"width":0.04027778,"height":0.018888889},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Adaptive","depth":28,"bounds":{"left":0.23194444,"top":0.0,"width":0.041666668,"height":0.018888889},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Send message","depth":26,"bounds":{"left":0.29583332,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Claude is AI and can make mistakes. Please double-check responses.","depth":22,"bounds":{"left":0.0,"top":0.0,"width":0.26805556,"height":0.016666668},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Claude is AI and can make mistakes. Please double-check responses.","depth":23,"bounds":{"left":0.0,"top":0.0,"width":0.26805556,"height":0.016666668},"on_screen":true,"role_description":"text"}]...
|
-7760678345716980173
|
-9075987391042592943
|
visual_change
|
accessibility
|
NULL
|
Skip to content
Skip to content
Click to collapse
Skip to content
Skip to content
Click to collapse
⌘B
Drag to resize
Collapse sidebar
Search
Chat
Cowork
Code
New chat ⌘N
New chat
⌘N
Projects
Artifacts
Customize
Pinned
Bulgarian citizenship application process for EU residents
More options for Bulgarian citizenship application process for EU residents
Dawarich location tracking project
More options for Dawarich location tracking project
Recents
View all
Screenpipe data sync and retention management
More options for Screenpipe data sync and retention management
Screenpipe sync script failing after recent migrations
More options for Screenpipe sync script failing after recent migrations
Hubspot BadRequest headers debugging
More options for Hubspot BadRequest headers debugging
Monthly expense tracking
More options for Monthly expense tracking
Exporting transaction data from Notion to finance hub
More options for Exporting transaction data from Notion to finance hub
💬 How much have I spent for groc…
More options for 💬 How much have I spent for groc…
April 2026 spending by category
More options for April 2026 spending by category
Code diff review
More options for Code diff review
HubSpot rate limit implementation strategy
More options for HubSpot rate limit implementation strategy
Screenpipe retention policy code location
More options for Screenpipe retention policy code location
Viewing retention policy in screenpipe
More options for Viewing retention policy in screenpipe
Clean shot x video recording termination issue
More options for Clean shot x video recording termination issue
HubSpot rate limit handling with executeRequest
More options for HubSpot rate limit handling with executeRequest
Untitled
More options
💬 Screen pipe. Is there ability…
More options for 💬 Screen pipe. Is there ability…
SMB mount access inconsistency between Finder and iTerm
More options for SMB mount access inconsistency between Finder and iTerm
💬 What is the best switch I can…
More options for 💬 What is the best switch I can…
Permission denied on screenpipe volume
More options for Permission denied on screenpipe volume
Screenpipe sync database attachment error
More options for Screenpipe sync database attachment error
Last swimming outing with Dani
More options for Last swimming outing with Dani
Lukas Pro
Get apps and extensions
Screenpipe data sync and retention management, rename chat
Screenpipe data sync and retention management
More options for Screenpipe data sync and retention management
Share chat
Claude finished the response
You said: Lets start from the beginning with the fresh mind.
You said: Lets start from the beginning with the fresh mind.
Pasted Text, pasted, 495 lines
#!/bin/bash # screenpipe_sync.sh # Syncs Screenpipe SQLite data to a NAS archive database (append-only, no deletions). # Also copies the day's video/frame data folder to the NAS. # # Schema-drift tolerant: if Screenpipe migrations add new columns to the source DB, # the NAS archive gets ALTER TABLE'
PASTED
Lets start from the beginning with the fresh mind. There is a script for screenpipe to copy data for day from mac to nas. There are two issues I want to work with. Firsts if I reinstall the mac version it starts from fresh id 1. That causes some issues. How to make sure the data are valid. I don't want some overcomplicated flow. I was thinking about making new db every 3 months. Secodn issue is that I wan to implement cleanup (retention policy) on mac original screenpipe db. I want script that will remove data that are 7 days old or older for example. ANd lastly I want to extedn the script to work with audio as well. What od you need
20:19
Retry
Edit
Copy
Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…
Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…
Analyzed three technical challenges and identified clarifying questions needed
Analyzed three technical challenges and identified clarifying questions needed
Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether reinstalls have already happened). Before I touch the script, a few things:
Issue 1 — ID collisions / archive rotation
Has a reinstall already happened, or is the current
archive.db
still from one continuous install? If collisions already exist I need to handle that first; if not, we have a clean slate.
Quarterly rotation works, but it doesn't actually solve reinstalls
within
a quarter. A cleaner option that I'd lean toward: add an
install_id
column (UUID generated once and stored in a tiny
_meta
table in the source DB) to every synced table, and make
(install_id, id)
the logical key. FK joins just gain one extra predicate. Reinstall → new install_id → no collisions, ever. You can still rotate the archive DB quarterly for file-size reasons, but it's no longer load-bearing.
Do you ever run cross-period queries (e.g. "every frame mentioning JY-20458 across all time")? That answers whether quarterly sharding is acceptable or whether one growing DB is better.
Issue 2 — Mac-side retention
Your launch command already has
--retention-days 7
. Is that not actually deleting anything, or do you want a separate scripted retention you can trust/observe independently?
Should retention also wipe the matching
~/.screenpipe/data/data/YYYY-MM-DD/
folders, or only DB rows? (CLI flag does both I believe; a script should match.)
Run order matters: sync writes
yesterday
, retention deletes
>7 days old
— no overlap, but I'd still chain them (sync → retention → log) in one cron entry so a failed sync blocks the delete. OK with that?
Issue 3 — Audio
Your current launch flag is
--disable-audio
, so right now there's no audio data to sync. Are you planning to enable it, or is this just to future-proof the script?
I need the audio schema. Could you run this and paste the output:
Copy to clipboard
sqlite3 ~/.screenpipe/db.sqlite ".schema" | grep -iE -A 20 "audio|transcription"
And:
ls ~/.screenpipe/data/data/$(date -v-1d +%Y-%m-%d)/ | head
so I can see what audio files look like on disk alongside the mp4 frames.
Once I have those, I'll restructure the script in one go rather than piecemeal.
Copy
Give positive feedback
Give negative feedback
Retry
Pasted Text, pasted, 208 lines
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ sqlite3 ~/.screenpipe/db.sqlite ".schema" | grep -iE -A 20 "audio|transcription" CREATE TABLE audio_chunks ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_path TEXT NOT NULL , timestamp TIMESTAMP, sync_id TEXT, machine_id TEXT, synced_at DATETIME, ev
PASTED
Remove Pasted Text, pasted, 208 lines
ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well.
ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well.
Add files, connectors, and more
Model: Opus 4.7 Adaptive
Opus 4.7
Adaptive
Send message
Claude is AI and can make mistakes. Please double-check responses.
Claude is AI and can make mistakes. Please double-check responses....
|
NULL
|
NULL
|
NULL
|
NULL
|
|
21259
|
931
|
11
|
2026-05-11T17:32:38.783091+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778520758783_m2.jpg...
|
Claude
|
Claude
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Skip to content
Skip to content
Click to collapse
Skip to content
Skip to content
Click to collapse
⌘B
Drag to resize
Collapse sidebar
Search
Chat
Cowork
Code
New chat ⌘N
New chat
⌘N
Projects
Artifacts
Customize
Pinned
Bulgarian citizenship application process for EU residents
More options for Bulgarian citizenship application process for EU residents
Dawarich location tracking project
More options for Dawarich location tracking project
Recents
View all
Screenpipe data sync and retention management
More options for Screenpipe data sync and retention management
Screenpipe sync script failing after recent migrations
More options for Screenpipe sync script failing after recent migrations
Hubspot BadRequest headers debugging
More options for Hubspot BadRequest headers debugging
Monthly expense tracking
More options for Monthly expense tracking
Exporting transaction data from Notion to finance hub
More options for Exporting transaction data from Notion to finance hub
💬 How much have I spent for groc…
More options for 💬 How much have I spent for groc…
April 2026 spending by category
More options for April 2026 spending by category
Code diff review
More options for Code diff review
HubSpot rate limit implementation strategy
More options for HubSpot rate limit implementation strategy
Screenpipe retention policy code location
More options for Screenpipe retention policy code location
Viewing retention policy in screenpipe
More options for Viewing retention policy in screenpipe
Clean shot x video recording termination issue
More options for Clean shot x video recording termination issue
HubSpot rate limit handling with executeRequest
More options for HubSpot rate limit handling with executeRequest
Untitled
More options
💬 Screen pipe. Is there ability…
More options for 💬 Screen pipe. Is there ability…
SMB mount access inconsistency between Finder and iTerm
More options for SMB mount access inconsistency between Finder and iTerm
💬 What is the best switch I can…
More options for 💬 What is the best switch I can…
Permission denied on screenpipe volume
More options for Permission denied on screenpipe volume
Screenpipe sync database attachment error
More options for Screenpipe sync database attachment error
Last swimming outing with Dani
More options for Last swimming outing with Dani
Lukas Pro
Get apps and extensions
Screenpipe data sync and retention management, rename chat
Screenpipe data sync and retention management
More options for Screenpipe data sync and retention management
Share chat
Claude finished the response
You said: Lets start from the beginning with the fresh mind.
You said: Lets start from the beginning with the fresh mind.
Pasted Text, pasted, 495 lines
#!/bin/bash # screenpipe_sync.sh # Syncs Screenpipe SQLite data to a NAS archive database (append-only, no deletions). # Also copies the day's video/frame data folder to the NAS. # # Schema-drift tolerant: if Screenpipe migrations add new columns to the source DB, # the NAS archive gets ALTER TABLE'
PASTED
Lets start from the beginning with the fresh mind. There is a script for screenpipe to copy data for day from mac to nas. There are two issues I want to work with. Firsts if I reinstall the mac version it starts from fresh id 1. That causes some issues. How to make sure the data are valid. I don't want some overcomplicated flow. I was thinking about making new db every 3 months. Secodn issue is that I wan to implement cleanup (retention policy) on mac original screenpipe db. I want script that will remove data that are 7 days old or older for example. ANd lastly I want to extedn the script to work with audio as well. What od you need
20:19
Retry
Edit
Copy
Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…
Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…
Analyzed three technical challenges and identified clarifying questions needed
Analyzed three technical challenges and identified clarifying questions needed
Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether reinstalls have already happened). Before I touch the script, a few things:
Issue 1 — ID collisions / archive rotation
Has a reinstall already happened, or is the current
archive.db
still from one continuous install? If collisions already exist I need to handle that first; if not, we have a clean slate.
Quarterly rotation works, but it doesn't actually solve reinstalls
within
a quarter. A cleaner option that I'd lean toward: add an
install_id
column (UUID generated once and stored in a tiny
_meta
table in the source DB) to every synced table, and make
(install_id, id)
the logical key. FK joins just gain one extra predicate. Reinstall → new install_id → no collisions, ever. You can still rotate the archive DB quarterly for file-size reasons, but it's no longer load-bearing.
Do you ever run cross-period queries (e.g. "every frame mentioning JY-20458 across all time")? That answers whether quarterly sharding is acceptable or whether one growing DB is better.
Issue 2 — Mac-side retention
Your launch command already has
--retention-days 7
. Is that not actually deleting anything, or do you want a separate scripted retention you can trust/observe independently?
Should retention also wipe the matching
~/.screenpipe/data/data/YYYY-MM-DD/
folders, or only DB rows? (CLI flag does both I believe; a script should match.)
Run order matters: sync writes
yesterday
, retention deletes
>7 days old
— no overlap, but I'd still chain them (sync → retention → log) in one cron entry so a failed sync blocks the delete. OK with that?
Issue 3 — Audio
Your current launch flag is
--disable-audio
, so right now there's no audio data to sync. Are you planning to enable it, or is this just to future-proof the script?
I need the audio schema. Could you run this and paste the output:
Copy to clipboard
sqlite3 ~/.screenpipe/db.sqlite ".schema" | grep -iE -A 20 "audio|transcription"
And:
ls ~/.screenpipe/data/data/$(date -v-1d +%Y-%m-%d)/ | head
so I can see what audio files look like on disk alongside the mp4 frames.
Once I have those, I'll restructure the script in one go rather than piecemeal.
Copy
Give positive feedback
Give negative feedback
Retry
Pasted Text, pasted, 208 lines
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ sqlite3 ~/.screenpipe/db.sqlite ".schema" | grep -iE -A 20 "audio|transcription" CREATE TABLE audio_chunks ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_path TEXT NOT NULL , timestamp TIMESTAMP, sync_id TEXT, machine_id TEXT, synced_at DATETIME, ev
PASTED
Remove Pasted Text, pasted, 208 lines
ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well.
ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well.
Add files, connectors, and more
Model: Opus 4.7 Adaptive
Opus 4.7
Adaptive
Send message
Claude is AI and can make mistakes. Please double-check responses.
Claude is AI and can make mistakes. Please double-check responses....
|
[{"role":"AXLink","text":& [{"role":"AXLink","text":"Skip to content","depth":14,"bounds":{"left":0.0023271276,"top":0.025538707,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Skip to content","depth":15,"bounds":{"left":0.0023271276,"top":0.026336791,"width":0.030917553,"height":0.013567438},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.0023271276,"top":0.027134877,"width":0.0026595744,"height":0.012769354}},{"char_start":1,"char_count":14,"bounds":{"left":0.004986702,"top":0.027134877,"width":0.02825798,"height":0.012769354}}],"role_description":"text"},{"role":"AXStaticText","text":"Click to collapse","depth":16,"bounds":{"left":0.10239362,"top":0.782921,"width":0.030585106,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10239362,"top":0.782921,"width":0.0029920214,"height":0.011971269}},{"char_start":1,"char_count":16,"bounds":{"left":0.10538564,"top":0.782921,"width":0.027925532,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"⌘B","depth":16,"bounds":{"left":0.1349734,"top":0.782921,"width":0.0063164895,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drag to resize","depth":16,"bounds":{"left":0.10239362,"top":0.79489225,"width":0.025930852,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10239362,"top":0.79489225,"width":0.0029920214,"height":0.011971269}},{"char_start":1,"char_count":13,"bounds":{"left":0.10538564,"top":0.79489225,"width":0.022938829,"height":0.011971269}}],"role_description":"text"},{"role":"AXButton","text":"Collapse sidebar","depth":15,"bounds":{"left":0.030585106,"top":0.02952913,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search","depth":15,"bounds":{"left":0.03856383,"top":0.02952913,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Chat","depth":16,"bounds":{"left":0.005984043,"top":0.06304868,"width":0.026263298,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cowork","depth":16,"bounds":{"left":0.032579787,"top":0.06304868,"width":0.031914894,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code","depth":16,"bounds":{"left":0.065159574,"top":0.06304868,"width":0.027260639,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New chat ⌘N","depth":15,"bounds":{"left":0.005319149,"top":0.096568234,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"New chat","depth":16,"bounds":{"left":0.015292553,"top":0.09976058,"width":0.019281914,"height":0.013567438},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.015292553,"top":0.10055866,"width":0.0033244682,"height":0.013567438}},{"char_start":1,"char_count":7,"bounds":{"left":0.01861702,"top":0.10055866,"width":0.015957447,"height":0.013567438}}],"role_description":"text"},{"role":"AXStaticText","text":"⌘N","depth":17,"bounds":{"left":0.084109046,"top":0.10055866,"width":0.006981383,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Projects","depth":15,"bounds":{"left":0.005319149,"top":0.11731844,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Artifacts","depth":15,"bounds":{"left":0.005319149,"top":0.13806863,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Customize","depth":15,"bounds":{"left":0.005319149,"top":0.15881884,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Pinned","depth":16,"bounds":{"left":0.00731383,"top":0.19872306,"width":0.08510638,"height":0.012769354},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"Bulgarian citizenship application process for EU residents","depth":18,"bounds":{"left":0.005319149,"top":0.21548285,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Bulgarian citizenship application process for EU residents","depth":19,"bounds":{"left":0.08577128,"top":0.21867518,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Dawarich location tracking project","depth":18,"bounds":{"left":0.005319149,"top":0.23703113,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Dawarich location tracking project","depth":19,"bounds":{"left":0.08577128,"top":0.24022347,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Recents","depth":16,"bounds":{"left":0.00731383,"top":0.26735833,"width":0.064494684,"height":0.012769354},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXButton","text":"View all","depth":16,"bounds":{"left":0.0731383,"top":0.26735833,"width":0.019281914,"height":0.012769354},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe data sync and retention management","depth":18,"bounds":{"left":0.005319149,"top":0.28411812,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe data sync and retention management","depth":19,"bounds":{"left":0.08577128,"top":0.28731045,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe sync script failing after recent migrations","depth":18,"bounds":{"left":0.005319149,"top":0.3056664,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe sync script failing after recent migrations","depth":19,"bounds":{"left":0.08577128,"top":0.30885875,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hubspot BadRequest headers debugging","depth":18,"bounds":{"left":0.005319149,"top":0.3272147,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Hubspot BadRequest headers debugging","depth":19,"bounds":{"left":0.08577128,"top":0.33040702,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Monthly expense tracking","depth":18,"bounds":{"left":0.005319149,"top":0.34876296,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Monthly expense tracking","depth":19,"bounds":{"left":0.08577128,"top":0.3519553,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Exporting transaction data from Notion to finance hub","depth":18,"bounds":{"left":0.005319149,"top":0.37031126,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Exporting transaction data from Notion to finance hub","depth":19,"bounds":{"left":0.08577128,"top":0.3735036,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"💬 How much have I spent for groc…","depth":18,"bounds":{"left":0.005319149,"top":0.39185953,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for 💬 How much have I spent for groc…","depth":19,"bounds":{"left":0.08577128,"top":0.39505187,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"April 2026 spending by category","depth":18,"bounds":{"left":0.005319149,"top":0.41340783,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for April 2026 spending by category","depth":19,"bounds":{"left":0.08577128,"top":0.41660017,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code diff review","depth":18,"bounds":{"left":0.005319149,"top":0.4349561,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Code diff review","depth":19,"bounds":{"left":0.08577128,"top":0.43814844,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HubSpot rate limit implementation strategy","depth":18,"bounds":{"left":0.005319149,"top":0.45650437,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for HubSpot rate limit implementation strategy","depth":19,"bounds":{"left":0.08577128,"top":0.45969674,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe retention policy code location","depth":18,"bounds":{"left":0.005319149,"top":0.47805268,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe retention policy code location","depth":19,"bounds":{"left":0.08577128,"top":0.481245,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Viewing retention policy in screenpipe","depth":18,"bounds":{"left":0.005319149,"top":0.49960095,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Viewing retention policy in screenpipe","depth":19,"bounds":{"left":0.08577128,"top":0.5027933,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Clean shot x video recording termination issue","depth":18,"bounds":{"left":0.005319149,"top":0.5211492,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Clean shot x video recording termination issue","depth":19,"bounds":{"left":0.08577128,"top":0.5243416,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HubSpot rate limit handling with executeRequest","depth":18,"bounds":{"left":0.005319149,"top":0.54269755,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for HubSpot rate limit handling with executeRequest","depth":19,"bounds":{"left":0.08577128,"top":0.54588985,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Untitled","depth":18,"bounds":{"left":0.005319149,"top":0.5642458,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options","depth":19,"bounds":{"left":0.08577128,"top":0.5674381,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"💬 Screen pipe. Is there ability…","depth":18,"bounds":{"left":0.005319149,"top":0.5857941,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for 💬 Screen pipe. Is there ability…","depth":19,"bounds":{"left":0.08577128,"top":0.58898646,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"SMB mount access inconsistency between Finder and iTerm","depth":18,"bounds":{"left":0.005319149,"top":0.60734236,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for SMB mount access inconsistency between Finder and iTerm","depth":19,"bounds":{"left":0.08577128,"top":0.6105347,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"💬 What is the best switch I can…","depth":18,"bounds":{"left":0.005319149,"top":0.62889063,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for 💬 What is the best switch I can…","depth":19,"bounds":{"left":0.08577128,"top":0.632083,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Permission denied on screenpipe volume","depth":18,"bounds":{"left":0.005319149,"top":0.65043896,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Permission denied on screenpipe volume","depth":19,"bounds":{"left":0.08577128,"top":0.65363127,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe sync database attachment error","depth":18,"bounds":{"left":0.005319149,"top":0.67198724,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Screenpipe sync database attachment error","depth":19,"bounds":{"left":0.08577128,"top":0.67517954,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Last swimming outing with Dani","depth":18,"bounds":{"left":0.005319149,"top":0.6935355,"width":0.087765954,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More options for Last swimming outing with Dani","depth":19,"bounds":{"left":0.08577128,"top":0.6967279,"width":0.005984043,"height":0.014365523},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Lukas Pro","depth":15,"bounds":{"left":0.005319149,"top":0.9696728,"width":0.038231384,"height":0.01915403},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Get apps and extensions","depth":15,"bounds":{"left":0.08510638,"top":0.9696728,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Screenpipe data sync and retention management, rename chat","depth":19,"bounds":{"left":0.10239362,"top":0.02793296,"width":0.11070479,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Screenpipe data sync and retention management","depth":21,"bounds":{"left":0.10372341,"top":0.031923383,"width":0.10804521,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10372341,"top":0.031923383,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":44,"bounds":{"left":0.106715426,"top":0.031923383,"width":0.105053194,"height":0.014365523}}],"role_description":"text"},{"role":"AXPopUpButton","text":"More options for Screenpipe data sync and retention management","depth":19,"bounds":{"left":0.21343085,"top":0.02793296,"width":0.0066489363,"height":0.022346368},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Share chat","depth":21,"bounds":{"left":0.48537233,"top":0.026336791,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Claude finished the response","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXHeading","text":"You said: Lets start from the beginning with the fresh mind.","depth":20,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"You said: Lets start from the beginning with the fresh mind.","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Pasted Text, pasted, 495 lines","depth":21,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"#!/bin/bash # screenpipe_sync.sh # Syncs Screenpipe SQLite data to a NAS archive database (append-only, no deletions). # Also copies the day's video/frame data folder to the NAS. # # Schema-drift tolerant: if Screenpipe migrations add new columns to the source DB, # the NAS archive gets ALTER TABLE'","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"PASTED","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Lets start from the beginning with the fresh mind. There is a script for screenpipe to copy data for day from mac to nas. There are two issues I want to work with. Firsts if I reinstall the mac version it starts from fresh id 1. That causes some issues. How to make sure the data are valid. I don't want some overcomplicated flow. I was thinking about making new db every 3 months. Secodn issue is that I wan to implement cleanup (retention policy) on mac original screenpipe db. I want script that will remove data that are 7 days old or older for example. ANd lastly I want to extedn the script to work with audio as well. What od you need","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"20:19","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Retry","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Edit","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…","depth":21,"on_screen":false,"role_description":"heading"},{"role":"AXStaticText","text":"Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…","depth":22,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Analyzed three technical challenges and identified clarifying questions needed","depth":22,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Analyzed three technical challenges and identified clarifying questions needed","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether reinstalls have already happened). Before I touch the script, a few things:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Issue 1 — ID collisions / archive rotation","depth":26,"bounds":{"left":0.17952128,"top":0.019952115,"width":0.10006649,"height":0.007980846},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Has a reinstall already happened, or is the current","depth":26,"bounds":{"left":0.19015957,"top":0.040702313,"width":0.122340426,"height":0.015961692},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.19015957,"top":0.040702313,"width":0.0043218085,"height":0.016759777}},{"char_start":1,"char_count":50,"bounds":{"left":0.19448139,"top":0.040702313,"width":0.11702128,"height":0.016759777}}],"role_description":"text"},{"role":"AXStaticText","text":"archive.db","depth":27,"bounds":{"left":0.31382978,"top":0.0415004,"width":0.028922873,"height":0.015163607},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.31382978,"top":0.042298485,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.3168218,"top":0.042298485,"width":0.025930852,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"still from one continuous install? If collisions already exist I need to handle that first; if not, we have a clean slate.","depth":26,"bounds":{"left":0.19015957,"top":0.040702313,"width":0.21642287,"height":0.035115723},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.34408244,"top":0.040702313,"width":0.0013297872,"height":0.016759777}},{"char_start":1,"char_count":121,"bounds":{"left":0.19015957,"top":0.040702313,"width":0.21642287,"height":0.035913806}}],"role_description":"text"},{"role":"AXStaticText","text":"Quarterly rotation works, but it doesn't actually solve reinstalls","depth":26,"bounds":{"left":0.19015957,"top":0.08220271,"width":0.15458776,"height":0.015961692},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.19015957,"top":0.08220271,"width":0.0043218085,"height":0.016759777}},{"char_start":1,"char_count":65,"bounds":{"left":0.19448139,"top":0.08220271,"width":0.14926861,"height":0.016759777}}],"role_description":"text"},{"role":"AXStaticText","text":"within","depth":27,"bounds":{"left":0.34474733,"top":0.08220271,"width":0.015625,"height":0.015961692},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.34474733,"top":0.08220271,"width":0.0043218085,"height":0.016759777}},{"char_start":1,"char_count":5,"bounds":{"left":0.34906915,"top":0.08220271,"width":0.011303191,"height":0.016759777}}],"role_description":"text"},{"role":"AXStaticText","text":"a quarter. A cleaner option that I'd lean toward: add an","depth":26,"bounds":{"left":0.19015957,"top":0.08220271,"width":0.21908244,"height":0.035115723},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.36037233,"top":0.08220271,"width":0.0009973404,"height":0.016759777}},{"char_start":1,"char_count":55,"bounds":{"left":0.19015957,"top":0.08220271,"width":0.21875,"height":0.035913806}}],"role_description":"text"},{"role":"AXStaticText","text":"install_id","depth":27,"bounds":{"left":0.27593085,"top":0.10215483,"width":0.028922873,"height":0.015163607},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.27593085,"top":0.10295291,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":9,"bounds":{"left":0.2789229,"top":0.10295291,"width":0.025930852,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"column (UUID generated once and stored in a tiny","depth":26,"bounds":{"left":0.19015957,"top":0.101356745,"width":0.21941489,"height":0.035115723},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.30618352,"top":0.101356745,"width":0.0013297872,"height":0.016759777}},{"char_start":1,"char_count":47,"bounds":{"left":0.19015957,"top":0.101356745,"width":0.21941489,"height":0.035913806}}],"role_description":"text"},{"role":"AXStaticText","text":"_meta","depth":27,"bounds":{"left":0.21210106,"top":0.121308856,"width":0.01462766,"height":0.015163607},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.21243352,"top":0.12210695,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":4,"bounds":{"left":0.21509309,"top":0.12210695,"width":0.011635638,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"table in the source DB) to every synced table, and make","depth":26,"bounds":{"left":0.22805852,"top":0.12051077,"width":0.13730054,"height":0.015961692},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.22839096,"top":0.12051077,"width":0.0009973404,"height":0.016759777}},{"char_start":1,"char_count":54,"bounds":{"left":0.2293883,"top":0.12051077,"width":0.13231383,"height":0.016759777}}],"role_description":"text"},{"role":"AXStaticText","text":"(install_id, id)","depth":27,"bounds":{"left":0.19015957,"top":0.121308856,"width":0.21409574,"height":0.03431764},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the logical key. FK joins just gain one extra predicate. Reinstall → new install_id → no collisions, ever. You can still rotate the archive DB quarterly for file-size reasons, but it's no longer load-bearing.","depth":26,"bounds":{"left":0.19015957,"top":0.1396648,"width":0.21941489,"height":0.054269753},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.20013298,"top":0.1396648,"width":0.0013297872,"height":0.016759777}},{"char_start":1,"char_count":207,"bounds":{"left":0.19015957,"top":0.1396648,"width":0.21941489,"height":0.055067837}}],"role_description":"text"},{"role":"AXStaticText","text":"Do you ever run cross-period queries (e.g. \"every frame mentioning JY-20458 across all time\")? That answers whether quarterly sharding is acceptable or whether one growing DB is better.","depth":26,"bounds":{"left":0.19015957,"top":0.20031923,"width":0.21343085,"height":0.054269753},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.19015957,"top":0.20031923,"width":0.0043218085,"height":0.016759777}},{"char_start":1,"char_count":184,"bounds":{"left":0.19015957,"top":0.20031923,"width":0.21343085,"height":0.055067837}}],"role_description":"text"},{"role":"AXStaticText","text":"Issue 2 — Mac-side retention","depth":26,"bounds":{"left":0.17952128,"top":0.27693537,"width":0.0731383,"height":0.015961692},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.17952128,"top":0.27693537,"width":0.0019946808,"height":0.016759777}},{"char_start":1,"char_count":27,"bounds":{"left":0.18151596,"top":0.27693537,"width":0.07114362,"height":0.016759777}}],"role_description":"text"},{"role":"AXStaticText","text":"Your launch command already has","depth":26,"bounds":{"left":0.19015957,"top":0.3056664,"width":0.08610372,"height":0.015961692},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.19015957,"top":0.3056664,"width":0.0033244682,"height":0.016759777}},{"char_start":1,"char_count":30,"bounds":{"left":0.19348404,"top":0.3056664,"width":0.08178192,"height":0.016759777}}],"role_description":"text"},{"role":"AXStaticText","text":"--retention-days 7","depth":27,"bounds":{"left":0.27759308,"top":0.3064645,"width":0.051861703,"height":0.015163607},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.27759308,"top":0.30726257,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":17,"bounds":{"left":0.28025267,"top":0.30726257,"width":0.04920213,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":". Is that not actually deleting anything, or do you want a separate scripted retention you can trust/observe independently?","depth":26,"bounds":{"left":0.19015957,"top":0.3056664,"width":0.21010639,"height":0.054269753},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.3307846,"top":0.3056664,"width":0.0013297872,"height":0.016759777}},{"char_start":1,"char_count":122,"bounds":{"left":0.19015957,"top":0.3056664,"width":0.21010639,"height":0.055067837}}],"role_description":"text"},{"role":"AXStaticText","text":"Should retention also wipe the matching","depth":26,"bounds":{"left":0.19015957,"top":0.36632082,"width":0.100398935,"height":0.015961692},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.19015957,"top":0.36632082,"width":0.0033244682,"height":0.016759777}},{"char_start":1,"char_count":38,"bounds":{"left":0.19348404,"top":0.36632082,"width":0.09607713,"height":0.016759777}}],"role_description":"text"},{"role":"AXStaticText","text":"~/.screenpipe/data/data/YYYY-MM-DD/","depth":27,"bounds":{"left":0.2918883,"top":0.36711892,"width":0.10073138,"height":0.015163607},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.2918883,"top":0.367917,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":34,"bounds":{"left":0.29488033,"top":0.367917,"width":0.09773936,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"folders, or only DB rows? (CLI flag does both I believe; a script should match.)","depth":26,"bounds":{"left":0.19015957,"top":0.38547486,"width":0.18849733,"height":0.015961692},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.19015957,"top":0.38547486,"width":0.0019946808,"height":0.016759777}},{"char_start":1,"char_count":79,"bounds":{"left":0.19215426,"top":0.38547486,"width":0.18650267,"height":0.016759777}}],"role_description":"text"},{"role":"AXStaticText","text":"Run order matters: sync writes","depth":26,"bounds":{"left":0.19015957,"top":0.40782124,"width":0.07579787,"height":0.015961692},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.19015957,"top":0.40782124,"width":0.003656915,"height":0.016759777}},{"char_start":1,"char_count":29,"bounds":{"left":0.19381648,"top":0.40782124,"width":0.07114362,"height":0.016759777}}],"role_description":"text"},{"role":"AXStaticText","text":"yesterday","depth":27,"bounds":{"left":0.26595744,"top":0.40782124,"width":0.024268618,"height":0.015961692},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.26595744,"top":0.40782124,"width":0.0029920214,"height":0.016759777}},{"char_start":1,"char_count":8,"bounds":{"left":0.26894948,"top":0.40782124,"width":0.020944148,"height":0.016759777}}],"role_description":"text"},{"role":"AXStaticText","text":", retention deletes","depth":26,"bounds":{"left":0.28989363,"top":0.40782124,"width":0.045212764,"height":0.015961692},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.28989363,"top":0.40782124,"width":0.0013297872,"height":0.016759777}},{"char_start":1,"char_count":18,"bounds":{"left":0.2912234,"top":0.40782124,"width":0.04288564,"height":0.016759777}}],"role_description":"text"},{"role":"AXStaticText","text":">7 days old","depth":27,"bounds":{"left":0.33477393,"top":0.40782124,"width":0.027593086,"height":0.015961692},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.33477393,"top":0.40782124,"width":0.003656915,"height":0.016759777}},{"char_start":1,"char_count":10,"bounds":{"left":0.3380984,"top":0.40782124,"width":0.024268618,"height":0.016759777}}],"role_description":"text"},{"role":"AXStaticText","text":"— no overlap, but I'd still chain them (sync → retention → log) in one cron entry so a failed sync blocks the delete. OK with that?","depth":26,"bounds":{"left":0.19015957,"top":0.40782124,"width":0.21575798,"height":0.054269753},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.3620346,"top":0.40782124,"width":0.0013297872,"height":0.016759777}},{"char_start":1,"char_count":130,"bounds":{"left":0.19015957,"top":0.40782124,"width":0.21575798,"height":0.055067837}}],"role_description":"text"},{"role":"AXStaticText","text":"Issue 3 — Audio","depth":26,"bounds":{"left":0.17952128,"top":0.48443735,"width":0.040226065,"height":0.015961692},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.17952128,"top":0.48443735,"width":0.0019946808,"height":0.016759777}},{"char_start":1,"char_count":14,"bounds":{"left":0.18151596,"top":0.48443735,"width":0.03856383,"height":0.016759777}}],"role_description":"text"},{"role":"AXStaticText","text":"Your current launch flag is","depth":26,"bounds":{"left":0.19015957,"top":0.5131684,"width":0.06549202,"height":0.015961692},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.19015957,"top":0.5131684,"width":0.0033244682,"height":0.016759777}},{"char_start":1,"char_count":26,"bounds":{"left":0.19348404,"top":0.5131684,"width":0.061170213,"height":0.016759777}}],"role_description":"text"},{"role":"AXStaticText","text":"--disable-audio","depth":27,"bounds":{"left":0.25698137,"top":0.5139665,"width":0.043218084,"height":0.015163607},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.25698137,"top":0.51476455,"width":0.0029920214,"height":0.014365523}},{"char_start":1,"char_count":14,"bounds":{"left":0.2599734,"top":0.51476455,"width":0.040226065,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":", so right now there's no audio data to sync. Are you planning to enable it, or is this just to future-proof the script?","depth":26,"bounds":{"left":0.19015957,"top":0.5131684,"width":0.21542554,"height":0.035115723},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.30152926,"top":0.5131684,"width":0.0013297872,"height":0.016759777}},{"char_start":1,"char_count":119,"bounds":{"left":0.19015957,"top":0.5131684,"width":0.21542554,"height":0.035913806}}],"role_description":"text"},{"role":"AXStaticText","text":"I need the audio schema. Could you run this and paste the output:","depth":26,"bounds":{"left":0.19015957,"top":0.5546688,"width":0.16023937,"height":0.015961692},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.19015957,"top":0.5546688,"width":0.0019946808,"height":0.016759777}},{"char_start":1,"char_count":64,"bounds":{"left":0.19215426,"top":0.5546688,"width":0.15824468,"height":0.016759777}}],"role_description":"text"},{"role":"AXButton","text":"Copy to clipboard","depth":27,"bounds":{"left":0.40824467,"top":0.5977654,"width":0.010638298,"height":0.026336791},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"sqlite3 ~/.screenpipe/db.sqlite \".schema\" | grep -iE -A 20 \"audio|transcription\"","depth":27,"bounds":{"left":0.18151596,"top":0.6049481,"width":0.2293883,"height":0.014365523},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.1818484,"top":0.6049481,"width":0.0026595744,"height":0.014365523}},{"char_start":1,"char_count":79,"bounds":{"left":0.18450798,"top":0.6049481,"width":0.22074468,"height":0.014365523}}],"role_description":"text"},{"role":"AXStaticText","text":"And:","depth":26,"bounds":{"left":0.19015957,"top":0.6432562,"width":0.012965426,"height":0.016759777},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ls ~/.screenpipe/data/data/$(date -v-1d +%Y-%m-%d)/ | head","depth":27,"bounds":{"left":0.2044548,"top":0.64485234,"width":0.1668883,"height":0.014365523},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"so I can see what audio files look like on disk alongside the mp4 frames.","depth":26,"bounds":{"left":0.19015957,"top":0.6432562,"width":0.21143617,"height":0.035913806},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Once I have those, I'll restructure the script in one go rather than piecemeal.","depth":25,"bounds":{"left":0.17952128,"top":0.7007183,"width":0.18450798,"height":0.016759777},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Copy","depth":22,"bounds":{"left":0.1768617,"top":0.7278532,"width":0.010638298,"height":0.026336791},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give positive feedback","depth":22,"bounds":{"left":0.1875,"top":0.7278532,"width":0.010638298,"height":0.026336791},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Give negative feedback","depth":22,"bounds":{"left":0.1981383,"top":0.7278532,"width":0.010638298,"height":0.026336791},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Retry","depth":22,"bounds":{"left":0.2087766,"top":0.7278532,"width":0.010638298,"height":0.026336791},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Pasted Text, pasted, 208 lines","depth":26,"bounds":{"left":0.17652926,"top":0.75339186,"width":0.039893616,"height":0.096568234},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ sqlite3 ~/.screenpipe/db.sqlite \".schema\" | grep -iE -A 20 \"audio|transcription\" CREATE TABLE audio_chunks ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_path TEXT NOT NULL , timestamp TIMESTAMP, sync_id TEXT, machine_id TEXT, synced_at DATETIME, ev","depth":28,"bounds":{"left":0.17985372,"top":0.7613727,"width":0.032912236,"height":0.056664005},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"PASTED","depth":29,"bounds":{"left":0.18151596,"top":0.830008,"width":0.013962766,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Remove Pasted Text, pasted, 208 lines","depth":26,"bounds":{"left":0.17386968,"top":0.7470072,"width":0.0066489363,"height":0.016759777},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well.","depth":25,"bounds":{"left":0.17852394,"top":0.8731046,"width":0.24401596,"height":0.054269753},"on_screen":true,"value":"ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well.","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well.","depth":27,"bounds":{"left":0.17852394,"top":0.8739026,"width":0.23769946,"height":0.052673582},"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add files, connectors, and more","depth":27,"bounds":{"left":0.17719415,"top":0.93695134,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"Model: Opus 4.7 Adaptive","depth":27,"bounds":{"left":0.3570479,"top":0.93695134,"width":0.05219415,"height":0.025538707},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Opus 4.7","depth":29,"bounds":{"left":0.36037233,"top":0.9425379,"width":0.019281914,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Adaptive","depth":28,"bounds":{"left":0.38131648,"top":0.9425379,"width":0.019946808,"height":0.013567438},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Send message","depth":26,"bounds":{"left":0.4119016,"top":0.93695134,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Claude is AI and can make mistakes. Please double-check responses.","depth":22,"bounds":{"left":0.23503989,"top":0.980846,"width":0.12832446,"height":0.011971269},"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Claude is AI and can make mistakes. Please double-check responses.","depth":23,"bounds":{"left":0.23503989,"top":0.980846,"width":0.12832446,"height":0.011971269},"on_screen":true,"role_description":"text"}]...
|
-7760678345716980173
|
-9075987391042592943
|
visual_change
|
accessibility
|
NULL
|
Skip to content
Skip to content
Click to collapse
Skip to content
Skip to content
Click to collapse
⌘B
Drag to resize
Collapse sidebar
Search
Chat
Cowork
Code
New chat ⌘N
New chat
⌘N
Projects
Artifacts
Customize
Pinned
Bulgarian citizenship application process for EU residents
More options for Bulgarian citizenship application process for EU residents
Dawarich location tracking project
More options for Dawarich location tracking project
Recents
View all
Screenpipe data sync and retention management
More options for Screenpipe data sync and retention management
Screenpipe sync script failing after recent migrations
More options for Screenpipe sync script failing after recent migrations
Hubspot BadRequest headers debugging
More options for Hubspot BadRequest headers debugging
Monthly expense tracking
More options for Monthly expense tracking
Exporting transaction data from Notion to finance hub
More options for Exporting transaction data from Notion to finance hub
💬 How much have I spent for groc…
More options for 💬 How much have I spent for groc…
April 2026 spending by category
More options for April 2026 spending by category
Code diff review
More options for Code diff review
HubSpot rate limit implementation strategy
More options for HubSpot rate limit implementation strategy
Screenpipe retention policy code location
More options for Screenpipe retention policy code location
Viewing retention policy in screenpipe
More options for Viewing retention policy in screenpipe
Clean shot x video recording termination issue
More options for Clean shot x video recording termination issue
HubSpot rate limit handling with executeRequest
More options for HubSpot rate limit handling with executeRequest
Untitled
More options
💬 Screen pipe. Is there ability…
More options for 💬 Screen pipe. Is there ability…
SMB mount access inconsistency between Finder and iTerm
More options for SMB mount access inconsistency between Finder and iTerm
💬 What is the best switch I can…
More options for 💬 What is the best switch I can…
Permission denied on screenpipe volume
More options for Permission denied on screenpipe volume
Screenpipe sync database attachment error
More options for Screenpipe sync database attachment error
Last swimming outing with Dani
More options for Last swimming outing with Dani
Lukas Pro
Get apps and extensions
Screenpipe data sync and retention management, rename chat
Screenpipe data sync and retention management
More options for Screenpipe data sync and retention management
Share chat
Claude finished the response
You said: Lets start from the beginning with the fresh mind.
You said: Lets start from the beginning with the fresh mind.
Pasted Text, pasted, 495 lines
#!/bin/bash # screenpipe_sync.sh # Syncs Screenpipe SQLite data to a NAS archive database (append-only, no deletions). # Also copies the day's video/frame data folder to the NAS. # # Schema-drift tolerant: if Screenpipe migrations add new columns to the source DB, # the NAS archive gets ALTER TABLE'
PASTED
Lets start from the beginning with the fresh mind. There is a script for screenpipe to copy data for day from mac to nas. There are two issues I want to work with. Firsts if I reinstall the mac version it starts from fresh id 1. That causes some issues. How to make sure the data are valid. I don't want some overcomplicated flow. I was thinking about making new db every 3 months. Secodn issue is that I wan to implement cleanup (retention policy) on mac original screenpipe db. I want script that will remove data that are 7 days old or older for example. ANd lastly I want to extedn the script to work with audio as well. What od you need
20:19
Retry
Edit
Copy
Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…
Claude responded: Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether…
Analyzed three technical challenges and identified clarifying questions needed
Analyzed three technical challenges and identified clarifying questions needed
Good plan to tackle these together — they interact (retention timing depends on sync timing, audio sync depends on schema shape, ID strategy depends on whether reinstalls have already happened). Before I touch the script, a few things:
Issue 1 — ID collisions / archive rotation
Has a reinstall already happened, or is the current
archive.db
still from one continuous install? If collisions already exist I need to handle that first; if not, we have a clean slate.
Quarterly rotation works, but it doesn't actually solve reinstalls
within
a quarter. A cleaner option that I'd lean toward: add an
install_id
column (UUID generated once and stored in a tiny
_meta
table in the source DB) to every synced table, and make
(install_id, id)
the logical key. FK joins just gain one extra predicate. Reinstall → new install_id → no collisions, ever. You can still rotate the archive DB quarterly for file-size reasons, but it's no longer load-bearing.
Do you ever run cross-period queries (e.g. "every frame mentioning JY-20458 across all time")? That answers whether quarterly sharding is acceptable or whether one growing DB is better.
Issue 2 — Mac-side retention
Your launch command already has
--retention-days 7
. Is that not actually deleting anything, or do you want a separate scripted retention you can trust/observe independently?
Should retention also wipe the matching
~/.screenpipe/data/data/YYYY-MM-DD/
folders, or only DB rows? (CLI flag does both I believe; a script should match.)
Run order matters: sync writes
yesterday
, retention deletes
>7 days old
— no overlap, but I'd still chain them (sync → retention → log) in one cron entry so a failed sync blocks the delete. OK with that?
Issue 3 — Audio
Your current launch flag is
--disable-audio
, so right now there's no audio data to sync. Are you planning to enable it, or is this just to future-proof the script?
I need the audio schema. Could you run this and paste the output:
Copy to clipboard
sqlite3 ~/.screenpipe/db.sqlite ".schema" | grep -iE -A 20 "audio|transcription"
And:
ls ~/.screenpipe/data/data/$(date -v-1d +%Y-%m-%d)/ | head
so I can see what audio files look like on disk alongside the mp4 frames.
Once I have those, I'll restructure the script in one go rather than piecemeal.
Copy
Give positive feedback
Give negative feedback
Retry
Pasted Text, pasted, 208 lines
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ sqlite3 ~/.screenpipe/db.sqlite ".schema" | grep -iE -A 20 "audio|transcription" CREATE TABLE audio_chunks ( id INTEGER PRIMARY KEY AUTOINCREMENT, file_path TEXT NOT NULL , timestamp TIMESTAMP, sync_id TEXT, machine_id TEXT, synced_at DATETIME, ev
PASTED
Remove Pasted Text, pasted, 208 lines
ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well.
ok lets add install_id. Lets add separate script deleting data again from data and it should also remove logs and data. Make it manual script for now. I will remove --disable-audio from alias and run it without. I wan to have audio as well.
Add files, connectors, and more
Model: Opus 4.7 Adaptive
Opus 4.7
Adaptive
Send message
Claude is AI and can make mistakes. Please double-check responses.
Claude is AI and can make mistakes. Please double-check responses....
|
NULL
|
NULL
|
NULL
|
NULL
|
|
19505
|
832
|
19
|
2026-05-11T12:55:56.304641+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778504156304_m1.jpg...
|
Code
|
Review rate limit handli… — app
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G) - 12 pending changes
12
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Testing
Claude Code
EXPLORER
EXPLORER
Explorer Section: app
Explorer Section: app
APP
CheckAndRetryRemoteMatch.php
CreateFollowupActivity.php
CreateNotes.php
MatchActivitiesToNewOpportunity.php
MatchActivityCrmData.php
NoteObject.php
SaveActivity.php
SaveTranscription.php
SetupLayout.php
SyncActivity.php
SyncFieldMetadata.php
SyncHubspotObjects.php
SyncLeads.php
SyncObjects.php
SyncOpportunitiesJob.php
SyncOpportunity.php
SyncProfileMetadata.php
SyncTeamFieldsJob.php
SyncTeamMetadata.php
UpdateOpportunitySpecifications.php
UpdateStage.php
DealRisks
Mailbox
MeetingBot...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Explorer (⇧⌘E)","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":true},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Search (⇧⌘F)","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Source Control (⌃⇧G) - 12 pending changes","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"12","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Run and Debug (⇧⌘D)","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Remote Explorer","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Extensions (⇧⌘X) - 2 require update","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Testing","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Claude Code","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"EXPLORER","depth":17,"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"EXPLORER","depth":18,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Explorer Section: app","depth":21,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"Explorer Section: app","depth":22,"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"APP","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"CheckAndRetryRemoteMatch.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"CreateFollowupActivity.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"CreateNotes.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MatchActivitiesToNewOpportunity.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MatchActivityCrmData.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"NoteObject.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SaveActivity.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SaveTranscription.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SetupLayout.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SyncActivity.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SyncFieldMetadata.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SyncHubspotObjects.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SyncLeads.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SyncObjects.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunitiesJob.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SyncOpportunity.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SyncProfileMetadata.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SyncTeamFieldsJob.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SyncTeamMetadata.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"UpdateOpportunitySpecifications.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"UpdateStage.php","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Mailbox","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":27,"on_screen":true,"role_description":"text"}]...
|
-7760448377268086729
|
-289614928095017213
|
click
|
accessibility
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G) - 12 pending changes
12
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Testing
Claude Code
EXPLORER
EXPLORER
Explorer Section: app
Explorer Section: app
APP
CheckAndRetryRemoteMatch.php
CreateFollowupActivity.php
CreateNotes.php
MatchActivitiesToNewOpportunity.php
MatchActivityCrmData.php
NoteObject.php
SaveActivity.php
SaveTranscription.php
SetupLayout.php
SyncActivity.php
SyncFieldMetadata.php
SyncHubspotObjects.php
SyncLeads.php
SyncObjects.php
SyncOpportunitiesJob.php
SyncOpportunity.php
SyncProfileMetadata.php
SyncTeamFieldsJob.php
SyncTeamMetadata.php
UpdateOpportunitySpecifications.php
UpdateStage.php
DealRisks
Mailbox
MeetingBot...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
5545
|
205
|
3
|
2026-05-07T15:50:06.826641+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778169006826_m1.jpg...
|
PhpStorm
|
faVsco.js – Hubspot/Service.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
FinderFileEditViewGoWindowHelplahl100% <78Thu 7 FinderFileEditViewGoWindowHelplahl100% <78Thu 7 May 18:50:06STAGE (ssh)*3DOCKERDEV (-zsh)882APP (-zsh)DOCKER (-zsh)docker_lamp_1docker_lamp_12026-05-07 14:30:06 Running ['artisan'meeting-bot:schedule-bot] ….6S DONEdocker_1amp_1fd/1'2>&1docker_lamp_14sDONEdocker_1amp_11 '/usr/local/bin/php' 'artisan'meeting-bot: schedule-bot > */proc/1/2026-05-07 14:30:13 Running ['artisan'dialers:monitor-activities]1 '/usr/local/bin/php' 'artisan' dialers:monitor-activities › */proc/1/fd/1'2>&1docker_lamp_12026-05-07 14:30:17 Running ['artisan' jiminny:monitor-social-accountSJ3s DONEdocker_lamp_11 '/usr/local/bin/php' 'artisan' jiminny:monitor-social-accounts > */proc/1/fd/1'2>&1docker_lamp_12sDONEdocker_lamp_12026-05-07 14:30:20 Running ['artisan' mailbox:skip-lists:refresh]1 '/usr/local/bin/php' 'artisan'mailbox: skip-lists:refresh › */proc/1/fd/1'2>&1docker_lamp_112026-05-07 14:30:23 Running ['artisan' mailbox:batch:process --max-batches=15]2s DONEdocker_Lamp_11 '/usr/local/bin/php' 'artisan'mailbox:batch:process --max-batches=15 >*/proc/1/fd/1' 2>&1docker_lamp_112026-05-07 14:30:25 Running ['artisan' conference:monitor: count]1S DONEdocker_lamp_11 '/usr/local/bin/php' 'artisan' conference:monitor: count > */proc/1/fd/1'2>&1docker_lamp_12026-05-07 14:30:27 Running ['artisan' activity:purge-stale]2S DONEdocker_1amp_11 '/usr/local/bin/php' 'artisan' activity:purge-stale › '/proc/1/fd/12>&1docker_lamp_1docker_lamp_1docker_lamp_1-2026-05-07 14:30:30 Running ['artisan' mailbox:text-relay:sync] {"error":"invalid_request""error_description": "Invalidimpersonation \u0026quot; sub\u0026quot;field: @"docker_1amp_11}docker_lamp_14sDONEdocker_lamp_11 '/usr/local/bin/php' 'artisan' mailbox:text-relay:sync › */proc/1/fd/1' 2>&1docker_1amp_12026-05-07 14:30:35 Running ['artisan'conference:pre-meeting-notification]10s DONEdocker_1amp_111 '/usr/local/bin/php' 'artisan' conference:pre-meeting-notification'/proc/1/fd/1' 2>&1unexpected EOFukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/infrastructure/dev/docker (develop) $-zsh• *4screenpipe"XIY2PROD (ssh)Run 'do-release-upgrade' to upgrade to it.• *5-zsh|*** System restart required ***Last login: Mon Apr 27 07:45:272026 from 212.5.153.87lukas@jiminny-prod-bastion:~$ 0X T3 EU (-zsh)Last login: Thu May 7 09:29:14 on consolePoetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parents@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ I|T4STAGE (ssh)Run 'do-release-upgrade' to upgrade to it.*** System restart required ***Last login: Tue Apr 28 06:25:10 2026 from 212.5.153.87in:-$XIQA (-zsh)Last login: Thu May 7 09:44:56on ttys002Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.tomlfile in /Users/lukas or its parents$X 16FE (-zsh)Last login: Thu May 7 09:44:56on ttys004₴6181+PRODSTAGEPoetry could not find a pyproject.toml file in /Users/lukas or its parentsFRONTENDPoetry could not find a pyproject.tomlfile in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ I17 EXT (-zsh)Poetry could not find a pyproject.toml file in /Users/lukas or its parentsEXTENSIONPoetry could not find a pyproject.tomlfile in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ I|...
|
NULL
|
-7758865685555924505
|
NULL
|
click
|
ocr
|
NULL
|
FinderFileEditViewGoWindowHelplahl100% <78Thu 7 FinderFileEditViewGoWindowHelplahl100% <78Thu 7 May 18:50:06STAGE (ssh)*3DOCKERDEV (-zsh)882APP (-zsh)DOCKER (-zsh)docker_lamp_1docker_lamp_12026-05-07 14:30:06 Running ['artisan'meeting-bot:schedule-bot] ….6S DONEdocker_1amp_1fd/1'2>&1docker_lamp_14sDONEdocker_1amp_11 '/usr/local/bin/php' 'artisan'meeting-bot: schedule-bot > */proc/1/2026-05-07 14:30:13 Running ['artisan'dialers:monitor-activities]1 '/usr/local/bin/php' 'artisan' dialers:monitor-activities › */proc/1/fd/1'2>&1docker_lamp_12026-05-07 14:30:17 Running ['artisan' jiminny:monitor-social-accountSJ3s DONEdocker_lamp_11 '/usr/local/bin/php' 'artisan' jiminny:monitor-social-accounts > */proc/1/fd/1'2>&1docker_lamp_12sDONEdocker_lamp_12026-05-07 14:30:20 Running ['artisan' mailbox:skip-lists:refresh]1 '/usr/local/bin/php' 'artisan'mailbox: skip-lists:refresh › */proc/1/fd/1'2>&1docker_lamp_112026-05-07 14:30:23 Running ['artisan' mailbox:batch:process --max-batches=15]2s DONEdocker_Lamp_11 '/usr/local/bin/php' 'artisan'mailbox:batch:process --max-batches=15 >*/proc/1/fd/1' 2>&1docker_lamp_112026-05-07 14:30:25 Running ['artisan' conference:monitor: count]1S DONEdocker_lamp_11 '/usr/local/bin/php' 'artisan' conference:monitor: count > */proc/1/fd/1'2>&1docker_lamp_12026-05-07 14:30:27 Running ['artisan' activity:purge-stale]2S DONEdocker_1amp_11 '/usr/local/bin/php' 'artisan' activity:purge-stale › '/proc/1/fd/12>&1docker_lamp_1docker_lamp_1docker_lamp_1-2026-05-07 14:30:30 Running ['artisan' mailbox:text-relay:sync] {"error":"invalid_request""error_description": "Invalidimpersonation \u0026quot; sub\u0026quot;field: @"docker_1amp_11}docker_lamp_14sDONEdocker_lamp_11 '/usr/local/bin/php' 'artisan' mailbox:text-relay:sync › */proc/1/fd/1' 2>&1docker_1amp_12026-05-07 14:30:35 Running ['artisan'conference:pre-meeting-notification]10s DONEdocker_1amp_111 '/usr/local/bin/php' 'artisan' conference:pre-meeting-notification'/proc/1/fd/1' 2>&1unexpected EOFukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/infrastructure/dev/docker (develop) $-zsh• *4screenpipe"XIY2PROD (ssh)Run 'do-release-upgrade' to upgrade to it.• *5-zsh|*** System restart required ***Last login: Mon Apr 27 07:45:272026 from 212.5.153.87lukas@jiminny-prod-bastion:~$ 0X T3 EU (-zsh)Last login: Thu May 7 09:29:14 on consolePoetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.toml file in /Users/lukas or its parents@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ I|T4STAGE (ssh)Run 'do-release-upgrade' to upgrade to it.*** System restart required ***Last login: Tue Apr 28 06:25:10 2026 from 212.5.153.87in:-$XIQA (-zsh)Last login: Thu May 7 09:44:56on ttys002Poetry could not find a pyproject.toml file in /Users/lukas or its parentsPoetry could not find a pyproject.tomlfile in /Users/lukas or its parents$X 16FE (-zsh)Last login: Thu May 7 09:44:56on ttys004₴6181+PRODSTAGEPoetry could not find a pyproject.toml file in /Users/lukas or its parentsFRONTENDPoetry could not find a pyproject.tomlfile in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ I17 EXT (-zsh)Poetry could not find a pyproject.toml file in /Users/lukas or its parentsEXTENSIONPoetry could not find a pyproject.tomlfile in /Users/lukas or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ I|...
|
5540
|
NULL
|
NULL
|
NULL
|
|
12793
|
564
|
15
|
2026-05-09T09:30:05.120580+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-09/1778 /Users/lukas/.screenpipe/data/data/2026-05-09/1778319005120_m2.jpg...
|
Firefox
|
Finance Hub — Personal
|
True
|
finance-hub.lakylak.xyz/outpost.goauthentik.io/sig finance-hub.lakylak.xyz/outpost.goauthentik.io/sign_out...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
DNS / Nameservers | Hostinger
DNS / Nameservers | Hostinger
Nginx Proxy Manager
Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
Payments Logger
Payments Logger
Inbox - [EMAIL] - Gmail
Inbox - [EMAIL] - Gmail
(25) Quora
(25) Quora
Location Logger
Location Logger
Finance Hub
Finance Hub
Finance Hub
Finance Hub
Close tab
Select: payments - db - Adminer
Select: payments - db - Adminer
Електронно банкиране ДСК Директ от Банка ДСК
Електронно банкиране ДСК Директ от Банка ДСК
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
VIVACOM
VIVACOM
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
VIVACOM
VIVACOM
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Claude Code | Claude Platform
Claude Code | Claude Platform
Claude
Claude
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Finance Hub
Finance Hub
18
transaction
s
Payments
Payments
Upload CSV
Upload CSV
Refresh
Display settings
Sign out
Filters
Filters
Search...
dd
/
mm
/
yyyy
Calendar
dd
/
mm
/
yyyy
Calendar
DATE
RECIPIENT
AMOUNT
TAGS
22 Apr 2026
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
1000.00 EUR
Send
Send
Skip
Skip
Delete
30 Apr 2026
ВЕДА ПЕЙРОЛ ООД
Raw data
4325.26 EUR
Salary
Send
Send
Skip
Skip
Delete
30 Apr 2026
—
Raw data
10.22 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ЧЦДГ МИЛА
Raw data
460.00 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
14.27 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
29.54 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
0.09 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
47.63 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
8.44 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
17.93 EUR
Bills
Send
Send
Skip
Skip
Delete
06 May 2026, 13:16
POL BALICE Lagardere Travel R KR3
Raw data
5.49 EUR
Send
Send
Skip
Skip
Delete
07 May 2026, 09:02
BGR SOFIA CBA EKO MARKET
Raw data
5.51 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026, 19:32
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
67.81 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
9.04 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
15.46 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
5.02 EUR
Send
Send
Skip
Skip
Delete
08 May 2026, 10:00
DSK ATM, SOFIA, BG
Raw data
200.00 EUR
Send
Send
Skip
Skip
Delete
DATE
22 Apr 2026
30 Apr 2026
30 Apr 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
06 May 2026, 13:16
07 May 2026, 09:02
08 May 2026, 19:32
08 May 2026
08 May 2026
08 May 2026
08 May 2026, 10:00
RECIPIENT
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
ВЕДА ПЕЙРОЛ ООД
Raw data
—
Raw data
ЧЦДГ МИЛА
Raw data
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
POL BALICE Lagardere Travel R KR3
Raw data
BGR SOFIA CBA EKO MARKET
Raw data
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
—
Raw data
—
Raw data
—
Raw data
DSK ATM, SOFIA, BG
Raw data
AMOUNT
1000.00 EUR
4325.26 EUR
10.22 EUR
460.00 EUR
14.27 EUR
29.54 EUR
0.09 EUR
47.63 EUR
8.44 EUR
17.93 EUR
5.49 EUR
5.51 EUR
67.81 EUR
9.04 EUR
15.46 EUR
5.02 EUR
200.00 EUR
TAGS
Salary
Bills
Bills
Bills
Bills
Bills
Bills
Groceries
Groceries
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.080784574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DNS / Nameservers | Hostinger","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DNS / Nameservers | Hostinger","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.053856384,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Nginx Proxy Manager","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Nginx Proxy Manager","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.0,"top":0.15003991,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.0,"top":0.18276137,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.040724736,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.0,"top":0.21548285,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.013297873,"top":0.22665602,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.0,"top":0.2482043,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.013297873,"top":0.25937748,"width":0.11469415,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.0,"top":0.28092578,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"bounds":{"left":0.013297873,"top":0.29209897,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AFFiNE - All In One KnowledgeOS","depth":4,"bounds":{"left":0.0,"top":0.31364724,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE - All In One KnowledgeOS","depth":5,"bounds":{"left":0.013297873,"top":0.32482043,"width":0.05851064,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"bounds":{"left":0.0,"top":0.3463687,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All docs · AFFiNE","depth":5,"bounds":{"left":0.013297873,"top":0.3575419,"width":0.029587766,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Payments Logger","depth":4,"bounds":{"left":0.0,"top":0.3790902,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Payments Logger","depth":5,"bounds":{"left":0.013297873,"top":0.39026338,"width":0.030086435,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox - kovaliklukas@gmail.com - Gmail","depth":4,"bounds":{"left":0.0,"top":0.41181165,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox - kovaliklukas@gmail.com - Gmail","depth":5,"bounds":{"left":0.013297873,"top":0.42298484,"width":0.06898271,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"(25) Quora","depth":4,"bounds":{"left":0.0,"top":0.4445331,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"(25) Quora","depth":5,"bounds":{"left":0.013297873,"top":0.4557063,"width":0.018949468,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Location Logger","depth":4,"bounds":{"left":0.0,"top":0.4772546,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Location Logger","depth":5,"bounds":{"left":0.013297873,"top":0.4884278,"width":0.028091755,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"bounds":{"left":0.0,"top":0.509976,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Finance Hub","depth":5,"bounds":{"left":0.013297873,"top":0.5211492,"width":0.021609042,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"bounds":{"left":0.0,"top":0.54269755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Finance Hub","depth":5,"bounds":{"left":0.013297873,"top":0.55387074,"width":0.021609042,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.10139628,"top":0.54988027,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Select: payments - db - Adminer","depth":4,"bounds":{"left":0.0,"top":0.575419,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Select: payments - db - Adminer","depth":5,"bounds":{"left":0.013297873,"top":0.5865922,"width":0.05651596,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Електронно банкиране ДСК Директ от Банка ДСК","depth":4,"bounds":{"left":0.0,"top":0.60814047,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Електронно банкиране ДСК Директ от Банка ДСК","depth":5,"bounds":{"left":0.013297873,"top":0.61931366,"width":0.09059176,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE","depth":4,"bounds":{"left":0.0,"top":0.6408619,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE","depth":5,"bounds":{"left":0.013297873,"top":0.6520351,"width":0.113696806,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"VIVACOM","depth":4,"bounds":{"left":0.0,"top":0.6735834,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"VIVACOM","depth":5,"bounds":{"left":0.013297873,"top":0.6847566,"width":0.016788565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Смартфони с Unlimited план до 120 € отстъпка | Vivacom","depth":4,"bounds":{"left":0.0,"top":0.70630485,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Смартфони с Unlimited план до 120 € отстъпка | Vivacom","depth":5,"bounds":{"left":0.013297873,"top":0.71747804,"width":0.10239362,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"VIVACOM","depth":4,"bounds":{"left":0.0,"top":0.7390263,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"VIVACOM","depth":5,"bounds":{"left":0.013297873,"top":0.7501995,"width":0.016788565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom","depth":4,"bounds":{"left":0.0,"top":0.7717478,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom","depth":5,"bounds":{"left":0.013297873,"top":0.782921,"width":0.098902926,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude Code | Claude Platform","depth":4,"bounds":{"left":0.0,"top":0.8044693,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Claude Code | Claude Platform","depth":5,"bounds":{"left":0.013297873,"top":0.8156425,"width":0.053357713,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude","depth":4,"bounds":{"left":0.0,"top":0.83719075,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Claude","depth":5,"bounds":{"left":0.013297873,"top":0.84836394,"width":0.012134309,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.87150836,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Finance Hub","depth":8,"bounds":{"left":0.22539894,"top":0.0622506,"width":0.032081116,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Finance Hub","depth":9,"bounds":{"left":0.22539894,"top":0.06264964,"width":0.032081116,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18","depth":9,"bounds":{"left":0.22539894,"top":0.07861133,"width":0.0043218085,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"transaction","depth":9,"bounds":{"left":0.22972074,"top":0.07861133,"width":0.02244016,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"s","depth":9,"bounds":{"left":0.2521609,"top":0.07861133,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Payments","depth":8,"bounds":{"left":0.37982047,"top":0.06384677,"width":0.036070477,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Payments","depth":10,"bounds":{"left":0.39045876,"top":0.0698324,"width":0.02144282,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Upload CSV","depth":8,"bounds":{"left":0.41655585,"top":0.06384677,"width":0.04105718,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Upload CSV","depth":10,"bounds":{"left":0.42719415,"top":0.0698324,"width":0.02642952,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Refresh","depth":8,"bounds":{"left":0.57978725,"top":0.06384677,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Display settings","depth":8,"bounds":{"left":0.5924202,"top":0.06384677,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Sign out","depth":8,"bounds":{"left":0.6050532,"top":0.06384677,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Filters","depth":8,"bounds":{"left":0.21708776,"top":0.13168396,"width":0.3929521,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Filters","depth":10,"bounds":{"left":0.22506648,"top":0.13288109,"width":0.013630319,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search...","depth":9,"bounds":{"left":0.21708776,"top":0.16759777,"width":0.075465426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"dd","depth":11,"bounds":{"left":0.23038563,"top":0.21588188,"width":0.0056515955,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"bounds":{"left":0.23703457,"top":0.21588188,"width":0.0013297872,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mm","depth":11,"bounds":{"left":0.2393617,"top":0.21588188,"width":0.007978723,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"bounds":{"left":0.24833776,"top":0.21588188,"width":0.0013297872,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"yyyy","depth":11,"bounds":{"left":0.2506649,"top":0.21588188,"width":0.009973404,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":10,"bounds":{"left":0.40043217,"top":0.21667998,"width":0.006150266,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"dd","depth":11,"bounds":{"left":0.42885637,"top":0.21588188,"width":0.0056515955,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"bounds":{"left":0.43550533,"top":0.21588188,"width":0.0013297872,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mm","depth":11,"bounds":{"left":0.43783244,"top":0.21588188,"width":0.007978723,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"bounds":{"left":0.44680852,"top":0.21588188,"width":0.0013297872,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"yyyy","depth":11,"bounds":{"left":0.44913563,"top":0.21588188,"width":0.009973404,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":10,"bounds":{"left":0.59890294,"top":0.21667998,"width":0.006150266,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DATE","depth":13,"bounds":{"left":0.21708776,"top":0.27813247,"width":0.011136968,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RECIPIENT","depth":13,"bounds":{"left":0.2864029,"top":0.27813247,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AMOUNT","depth":13,"bounds":{"left":0.42785904,"top":0.27813247,"width":0.019448139,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"TAGS","depth":13,"bounds":{"left":0.47855717,"top":0.27813247,"width":0.011469414,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.30766162,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"МАРТИНА СВЕТОСЛАВОВА КОВАЛИК","depth":14,"bounds":{"left":0.2864029,"top":0.30766162,"width":0.0859375,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.37367022,"top":0.30885875,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1000.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.30766162,"width":0.030086435,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.3048683,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.3084597,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.30407023,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.3084597,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.30407023,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.34197924,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ВЕДА ПЕЙРОЛ ООД","depth":14,"bounds":{"left":0.2864029,"top":0.34197924,"width":0.044714097,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.3324468,"top":0.34317636,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4325.26 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.34197924,"width":0.030086435,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Salary","depth":13,"bounds":{"left":0.48055187,"top":0.34277734,"width":0.011968086,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.33918595,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.34277734,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.33838788,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.34277734,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.33838788,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.37629688,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.37629688,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.377494,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10.22 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.37629688,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.3735036,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.37709498,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.37270552,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.37709498,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.37270552,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.41061452,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЧЦДГ МИЛА","depth":14,"bounds":{"left":0.2864029,"top":0.41061452,"width":0.028091755,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.31582448,"top":0.41181165,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"460.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.41061452,"width":0.027094414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.40782124,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.4114126,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.40702313,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.4114126,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.40702313,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.44493216,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА","depth":14,"bounds":{"left":0.2864029,"top":0.44493216,"width":0.1171875,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.40492022,"top":0.4461293,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"14.27 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.44493216,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.44573024,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.44213888,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.44573024,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.44134077,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.44573024,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.44134077,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.4792498,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"bounds":{"left":0.2864029,"top":0.4792498,"width":0.07164229,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.359375,"top":0.48044693,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"29.54 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.4792498,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.48004788,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.4764565,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.48004788,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.47565842,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.48004788,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.47565842,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.51356745,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"bounds":{"left":0.2864029,"top":0.51356745,"width":0.12084442,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.4085771,"top":0.51476455,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0.09 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.51356745,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.5143655,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.51077414,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.5143655,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.509976,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.5143655,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.509976,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.54788506,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"bounds":{"left":0.2864029,"top":0.54788506,"width":0.12084442,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.4085771,"top":0.5490822,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"47.63 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.54788506,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.54868317,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.5450918,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.54868317,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.5442937,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.54868317,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.5442937,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.58220273,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"bounds":{"left":0.2864029,"top":0.58220273,"width":0.07164229,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.359375,"top":0.58339983,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8.44 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.58220273,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.5830008,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.5794094,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.5830008,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.5786113,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.5830008,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.5786113,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.61652035,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ","depth":14,"bounds":{"left":0.2864029,"top":0.61652035,"width":0.08277926,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.37051198,"top":0.6177175,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"17.93 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.61652035,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.61731845,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.61372703,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.61731845,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.612929,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.61731845,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.612929,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"06 May 2026, 13:16","depth":13,"bounds":{"left":0.21708776,"top":0.650838,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"POL BALICE Lagardere Travel R KR3","depth":14,"bounds":{"left":0.2864029,"top":0.650838,"width":0.07795878,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.36569148,"top":0.6520351,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.49 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.650838,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.6480447,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.65163606,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.6472466,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.65163606,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.6472466,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"07 May 2026, 09:02","depth":13,"bounds":{"left":0.21708776,"top":0.68515563,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BGR SOFIA CBA EKO MARKET","depth":14,"bounds":{"left":0.2864029,"top":0.68515563,"width":0.065159574,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.35289228,"top":0.6863527,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.51 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.68515563,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"bounds":{"left":0.48055187,"top":0.68595374,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.6823623,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.68595374,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.6815643,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.68595374,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.6815643,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026, 19:32","depth":13,"bounds":{"left":0.21708776,"top":0.71947324,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR","depth":14,"bounds":{"left":0.2864029,"top":0.71947324,"width":0.10322473,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.39095744,"top":0.7206704,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"67.81 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.71947324,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"bounds":{"left":0.48055187,"top":0.72027135,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.71668,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.72027135,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.7158819,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.72027135,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.7158819,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.7537909,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.7537909,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.754988,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"9.04 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.7537909,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.7509976,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.75458896,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.7501995,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.75458896,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.7501995,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.7881085,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.7881085,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.7893057,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"15.46 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.7881085,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.7853152,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.78890663,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.78451717,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.78890663,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.78451717,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.8224262,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.8224262,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.8236233,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.02 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.8224262,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.8196329,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.82322425,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.8188348,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.82322425,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.8188348,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026, 10:00","depth":13,"bounds":{"left":0.21708776,"top":0.8567438,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DSK ATM, SOFIA, BG","depth":14,"bounds":{"left":0.2864029,"top":0.8567438,"width":0.045212764,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.33294547,"top":0.8579409,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"200.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.8567438,"width":0.027094414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.8539505,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.8575419,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.85315245,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.8575419,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.85315245,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DATE","depth":13,"bounds":{"left":0.21708776,"top":0.27813247,"width":0.011136968,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.30766162,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.34197924,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.37629688,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.41061452,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.44493216,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.4792498,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.51356745,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.54788506,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.58220273,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.61652035,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"06 May 2026, 13:16","depth":13,"bounds":{"left":0.21708776,"top":0.650838,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"07 May 2026, 09:02","depth":13,"bounds":{"left":0.21708776,"top":0.68515563,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026, 19:32","depth":13,"bounds":{"left":0.21708776,"top":0.71947324,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.7537909,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.7881085,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.8224262,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026, 10:00","depth":13,"bounds":{"left":0.21708776,"top":0.8567438,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RECIPIENT","depth":13,"bounds":{"left":0.2864029,"top":0.27813247,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"МАРТИНА СВЕТОСЛАВОВА КОВАЛИК","depth":14,"bounds":{"left":0.2864029,"top":0.30766162,"width":0.0859375,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.37367022,"top":0.30885875,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ВЕДА ПЕЙРОЛ ООД","depth":14,"bounds":{"left":0.2864029,"top":0.34197924,"width":0.044714097,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.3324468,"top":0.34317636,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.37629688,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.377494,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЧЦДГ МИЛА","depth":14,"bounds":{"left":0.2864029,"top":0.41061452,"width":0.028091755,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.31582448,"top":0.41181165,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА","depth":14,"bounds":{"left":0.2864029,"top":0.44493216,"width":0.1171875,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.40492022,"top":0.4461293,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"bounds":{"left":0.2864029,"top":0.4792498,"width":0.07164229,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.359375,"top":0.48044693,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"bounds":{"left":0.2864029,"top":0.51356745,"width":0.12084442,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.4085771,"top":0.51476455,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"bounds":{"left":0.2864029,"top":0.54788506,"width":0.12084442,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.4085771,"top":0.5490822,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"bounds":{"left":0.2864029,"top":0.58220273,"width":0.07164229,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.359375,"top":0.58339983,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ","depth":14,"bounds":{"left":0.2864029,"top":0.61652035,"width":0.08277926,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.37051198,"top":0.6177175,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"POL BALICE Lagardere Travel R KR3","depth":14,"bounds":{"left":0.2864029,"top":0.650838,"width":0.07795878,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.36569148,"top":0.6520351,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BGR SOFIA CBA EKO MARKET","depth":14,"bounds":{"left":0.2864029,"top":0.68515563,"width":0.065159574,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.35289228,"top":0.6863527,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR","depth":14,"bounds":{"left":0.2864029,"top":0.71947324,"width":0.10322473,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.39095744,"top":0.7206704,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.7537909,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.754988,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.7881085,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.7893057,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.8224262,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.8236233,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DSK ATM, SOFIA, BG","depth":14,"bounds":{"left":0.2864029,"top":0.8567438,"width":0.045212764,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.33294547,"top":0.8579409,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AMOUNT","depth":13,"bounds":{"left":0.42785904,"top":0.27813247,"width":0.019448139,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1000.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.30766162,"width":0.030086435,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4325.26 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.34197924,"width":0.030086435,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10.22 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.37629688,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"460.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.41061452,"width":0.027094414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14.27 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.44493216,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"29.54 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.4792498,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0.09 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.51356745,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"47.63 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.54788506,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8.44 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.58220273,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17.93 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.61652035,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.49 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.650838,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.51 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.68515563,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"67.81 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.71947324,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"9.04 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.7537909,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"15.46 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.7881085,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.02 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.8224262,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"200.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.8567438,"width":0.027094414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"TAGS","depth":13,"bounds":{"left":0.47855717,"top":0.27813247,"width":0.011469414,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Salary","depth":13,"bounds":{"left":0.48055187,"top":0.34277734,"width":0.011968086,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.44573024,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.48004788,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.5143655,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.54868317,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.5830008,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.61731845,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"bounds":{"left":0.48055187,"top":0.68595374,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"bounds":{"left":0.48055187,"top":0.72027135,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.3048683,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.3084597,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.30407023,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.3084597,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.30407023,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.33918595,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.34277734,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.33838788,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.34277734,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.33838788,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.3735036,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.37709498,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.37270552,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.37709498,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.37270552,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.40782124,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.4114126,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.40702313,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.4114126,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.40702313,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.44213888,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.44573024,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.44134077,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.44573024,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.44134077,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.4764565,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.48004788,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.47565842,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.48004788,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.47565842,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.51077414,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.5143655,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.509976,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.5143655,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.509976,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.5450918,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.54868317,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.5442937,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.54868317,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.5442937,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.5794094,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.5830008,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.5786113,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.5830008,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.5786113,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.61372703,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.61731845,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.612929,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.61731845,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.612929,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.6480447,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.65163606,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.6472466,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.65163606,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.6472466,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.6823623,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.68595374,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.6815643,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.68595374,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.6815643,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.71668,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.72027135,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.7158819,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.72027135,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.7158819,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.7509976,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.75458896,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.7501995,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.75458896,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.7501995,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.7853152,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.78890663,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.78451717,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.78890663,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.78451717,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.8196329,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.82322425,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.8188348,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.82322425,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.8188348,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.8539505,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.8575419,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.85315245,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.8575419,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.85315245,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-7757773811144613165
|
5044045952359475102
|
visual_change
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
DNS / Nameservers | Hostinger
DNS / Nameservers | Hostinger
Nginx Proxy Manager
Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
Payments Logger
Payments Logger
Inbox - [EMAIL] - Gmail
Inbox - [EMAIL] - Gmail
(25) Quora
(25) Quora
Location Logger
Location Logger
Finance Hub
Finance Hub
Finance Hub
Finance Hub
Close tab
Select: payments - db - Adminer
Select: payments - db - Adminer
Електронно банкиране ДСК Директ от Банка ДСК
Електронно банкиране ДСК Директ от Банка ДСК
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
VIVACOM
VIVACOM
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
VIVACOM
VIVACOM
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Claude Code | Claude Platform
Claude Code | Claude Platform
Claude
Claude
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Finance Hub
Finance Hub
18
transaction
s
Payments
Payments
Upload CSV
Upload CSV
Refresh
Display settings
Sign out
Filters
Filters
Search...
dd
/
mm
/
yyyy
Calendar
dd
/
mm
/
yyyy
Calendar
DATE
RECIPIENT
AMOUNT
TAGS
22 Apr 2026
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
1000.00 EUR
Send
Send
Skip
Skip
Delete
30 Apr 2026
ВЕДА ПЕЙРОЛ ООД
Raw data
4325.26 EUR
Salary
Send
Send
Skip
Skip
Delete
30 Apr 2026
—
Raw data
10.22 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ЧЦДГ МИЛА
Raw data
460.00 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
14.27 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
29.54 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
0.09 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
47.63 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
8.44 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
17.93 EUR
Bills
Send
Send
Skip
Skip
Delete
06 May 2026, 13:16
POL BALICE Lagardere Travel R KR3
Raw data
5.49 EUR
Send
Send
Skip
Skip
Delete
07 May 2026, 09:02
BGR SOFIA CBA EKO MARKET
Raw data
5.51 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026, 19:32
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
67.81 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
9.04 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
15.46 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
5.02 EUR
Send
Send
Skip
Skip
Delete
08 May 2026, 10:00
DSK ATM, SOFIA, BG
Raw data
200.00 EUR
Send
Send
Skip
Skip
Delete
DATE
22 Apr 2026
30 Apr 2026
30 Apr 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
06 May 2026, 13:16
07 May 2026, 09:02
08 May 2026, 19:32
08 May 2026
08 May 2026
08 May 2026
08 May 2026, 10:00
RECIPIENT
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
ВЕДА ПЕЙРОЛ ООД
Raw data
—
Raw data
ЧЦДГ МИЛА
Raw data
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
POL BALICE Lagardere Travel R KR3
Raw data
BGR SOFIA CBA EKO MARKET
Raw data
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
—
Raw data
—
Raw data
—
Raw data
DSK ATM, SOFIA, BG
Raw data
AMOUNT
1000.00 EUR
4325.26 EUR
10.22 EUR
460.00 EUR
14.27 EUR
29.54 EUR
0.09 EUR
47.63 EUR
8.44 EUR
17.93 EUR
5.49 EUR
5.51 EUR
67.81 EUR
9.04 EUR
15.46 EUR
5.02 EUR
200.00 EUR
TAGS
Salary
Bills
Bills
Bills
Bills
Bills
Bills
Groceries
Groceries
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
12794
|
563
|
18
|
2026-05-09T09:30:31.531939+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-09/1778 /Users/lukas/.screenpipe/data/data/2026-05-09/1778319031531_m1.jpg...
|
Firefox
|
Finance Hub — Personal
|
True
|
finance-hub.lakylak.xyz/outpost.goauthentik.io/sig finance-hub.lakylak.xyz/outpost.goauthentik.io/sign_out...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
DNS / Nameservers | Hostinger
DNS / Nameservers | Hostinger
Nginx Proxy Manager
Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
Payments Logger
Payments Logger
Inbox - [EMAIL] - Gmail
Inbox - [EMAIL] - Gmail
(25) Quora
(25) Quora
Location Logger
Location Logger
Finance Hub
Finance Hub
Finance Hub
Finance Hub
Close tab
Select: payments - db - Adminer
Select: payments - db - Adminer
Електронно банкиране ДСК Директ от Банка ДСК
Електронно банкиране ДСК Директ от Банка ДСК
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
VIVACOM
VIVACOM
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
VIVACOM
VIVACOM
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Claude Code | Claude Platform
Claude Code | Claude Platform
Claude
Claude
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Finance Hub
Finance Hub
18
transaction
s
Payments
Payments
Upload CSV
Upload CSV
Refresh
Display settings
Sign out
Filters
Filters
Search...
dd
/
mm
/
yyyy
Calendar
dd
/
mm
/
yyyy
Calendar
DATE
RECIPIENT
AMOUNT
TAGS
22 Apr 2026
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
1000.00 EUR
Send
Send
Skip
Skip
Delete
30 Apr 2026
ВЕДА ПЕЙРОЛ ООД
Raw data
4325.26 EUR
Salary
Send
Send
Skip
Skip
Delete
30 Apr 2026
—
Raw data
10.22 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ЧЦДГ МИЛА
Raw data
460.00 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
14.27 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
29.54 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
0.09 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
47.63 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
8.44 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
17.93 EUR
Bills
Send
Send
Skip
Skip
Delete
06 May 2026, 13:16
POL BALICE Lagardere Travel R KR3
Raw data
5.49 EUR
Send
Send
Skip
Skip
Delete
07 May 2026, 09:02
BGR SOFIA CBA EKO MARKET
Raw data
5.51 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026, 19:32
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
67.81 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
9.04 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
15.46 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
5.02 EUR
Send
Send
Skip
Skip
Delete
08 May 2026, 10:00
DSK ATM, SOFIA, BG
Raw data
200.00 EUR
Send
Send
Skip
Skip
Delete
DATE
22 Apr 2026
30 Apr 2026
30 Apr 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
06 May 2026, 13:16
07 May 2026, 09:02
08 May 2026, 19:32
08 May 2026
08 May 2026
08 May 2026
08 May 2026, 10:00
RECIPIENT
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
ВЕДА ПЕЙРОЛ ООД
Raw data
—
Raw data
ЧЦДГ МИЛА
Raw data
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
POL BALICE Lagardere Travel R KR3
Raw data
BGR SOFIA CBA EKO MARKET
Raw data
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
—
Raw data
—
Raw data
—
Raw data
DSK ATM, SOFIA, BG
Raw data
AMOUNT
1000.00 EUR
4325.26 EUR
10.22 EUR
460.00 EUR
14.27 EUR
29.54 EUR
0.09 EUR
47.63 EUR
8.44 EUR
17.93 EUR
5.49 EUR
5.51 EUR
67.81 EUR
9.04 EUR
15.46 EUR
5.02 EUR
200.00 EUR
TAGS
Salary
Bills
Bills
Bills
Bills
Bills
Bills
Groceries
Groceries
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DNS / Nameservers | Hostinger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DNS / Nameservers | Hostinger","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Nginx Proxy Manager","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Nginx Proxy Manager","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AFFiNE - All In One KnowledgeOS","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE - All In One KnowledgeOS","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All docs · AFFiNE","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Payments Logger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Payments Logger","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox - kovaliklukas@gmail.com - Gmail","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox - kovaliklukas@gmail.com - Gmail","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"(25) Quora","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"(25) Quora","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Location Logger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Location Logger","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Finance Hub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Finance Hub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Select: payments - db - Adminer","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Select: payments - db - Adminer","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Електронно банкиране ДСК Директ от Банка ДСК","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Електронно банкиране ДСК Директ от Банка ДСК","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"VIVACOM","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"VIVACOM","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Смартфони с Unlimited план до 120 € отстъпка | Vivacom","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Смартфони с Unlimited план до 120 € отстъпка | Vivacom","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"VIVACOM","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"VIVACOM","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude Code | Claude Platform","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Claude Code | Claude Platform","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Claude","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Finance Hub","depth":8,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Finance Hub","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"transaction","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"s","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Payments","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Payments","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Upload CSV","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Upload CSV","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Refresh","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Display settings","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Sign out","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Filters","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Filters","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search...","depth":9,"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"dd","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mm","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"yyyy","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"dd","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mm","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"yyyy","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DATE","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RECIPIENT","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AMOUNT","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"TAGS","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"МАРТИНА СВЕТОСЛАВОВА КОВАЛИК","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1000.00 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ВЕДА ПЕЙРОЛ ООД","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4325.26 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Salary","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10.22 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЧЦДГ МИЛА","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"460.00 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"14.27 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"29.54 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0.09 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"47.63 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8.44 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"17.93 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"06 May 2026, 13:16","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"POL BALICE Lagardere Travel R KR3","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.49 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"07 May 2026, 09:02","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BGR SOFIA CBA EKO MARKET","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.51 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026, 19:32","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"67.81 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"9.04 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"15.46 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.02 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026, 10:00","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DSK ATM, SOFIA, BG","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"200.00 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DATE","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"06 May 2026, 13:16","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"07 May 2026, 09:02","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026, 19:32","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026, 10:00","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RECIPIENT","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"МАРТИНА СВЕТОСЛАВОВА КОВАЛИК","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ВЕДА ПЕЙРОЛ ООД","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЧЦДГ МИЛА","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"POL BALICE Lagardere Travel R KR3","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BGR SOFIA CBA EKO MARKET","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DSK ATM, SOFIA, BG","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AMOUNT","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1000.00 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4325.26 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10.22 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"460.00 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14.27 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"29.54 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0.09 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"47.63 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8.44 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17.93 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.49 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.51 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"67.81 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"9.04 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"15.46 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.02 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"200.00 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"TAGS","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Salary","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-7757773811144613165
|
5044045952359475102
|
idle
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
DNS / Nameservers | Hostinger
DNS / Nameservers | Hostinger
Nginx Proxy Manager
Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
Payments Logger
Payments Logger
Inbox - [EMAIL] - Gmail
Inbox - [EMAIL] - Gmail
(25) Quora
(25) Quora
Location Logger
Location Logger
Finance Hub
Finance Hub
Finance Hub
Finance Hub
Close tab
Select: payments - db - Adminer
Select: payments - db - Adminer
Електронно банкиране ДСК Директ от Банка ДСК
Електронно банкиране ДСК Директ от Банка ДСК
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
VIVACOM
VIVACOM
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
VIVACOM
VIVACOM
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Claude Code | Claude Platform
Claude Code | Claude Platform
Claude
Claude
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Finance Hub
Finance Hub
18
transaction
s
Payments
Payments
Upload CSV
Upload CSV
Refresh
Display settings
Sign out
Filters
Filters
Search...
dd
/
mm
/
yyyy
Calendar
dd
/
mm
/
yyyy
Calendar
DATE
RECIPIENT
AMOUNT
TAGS
22 Apr 2026
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
1000.00 EUR
Send
Send
Skip
Skip
Delete
30 Apr 2026
ВЕДА ПЕЙРОЛ ООД
Raw data
4325.26 EUR
Salary
Send
Send
Skip
Skip
Delete
30 Apr 2026
—
Raw data
10.22 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ЧЦДГ МИЛА
Raw data
460.00 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
14.27 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
29.54 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
0.09 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
47.63 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
8.44 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
17.93 EUR
Bills
Send
Send
Skip
Skip
Delete
06 May 2026, 13:16
POL BALICE Lagardere Travel R KR3
Raw data
5.49 EUR
Send
Send
Skip
Skip
Delete
07 May 2026, 09:02
BGR SOFIA CBA EKO MARKET
Raw data
5.51 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026, 19:32
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
67.81 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
9.04 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
15.46 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
5.02 EUR
Send
Send
Skip
Skip
Delete
08 May 2026, 10:00
DSK ATM, SOFIA, BG
Raw data
200.00 EUR
Send
Send
Skip
Skip
Delete
DATE
22 Apr 2026
30 Apr 2026
30 Apr 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
06 May 2026, 13:16
07 May 2026, 09:02
08 May 2026, 19:32
08 May 2026
08 May 2026
08 May 2026
08 May 2026, 10:00
RECIPIENT
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
ВЕДА ПЕЙРОЛ ООД
Raw data
—
Raw data
ЧЦДГ МИЛА
Raw data
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
POL BALICE Lagardere Travel R KR3
Raw data
BGR SOFIA CBA EKO MARKET
Raw data
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
—
Raw data
—
Raw data
—
Raw data
DSK ATM, SOFIA, BG
Raw data
AMOUNT
1000.00 EUR
4325.26 EUR
10.22 EUR
460.00 EUR
14.27 EUR
29.54 EUR
0.09 EUR
47.63 EUR
8.44 EUR
17.93 EUR
5.49 EUR
5.51 EUR
67.81 EUR
9.04 EUR
15.46 EUR
5.02 EUR
200.00 EUR
TAGS
Salary
Bills
Bills
Bills
Bills
Bills
Bills
Groceries
Groceries
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete...
|
12792
|
NULL
|
NULL
|
NULL
|
|
12795
|
564
|
16
|
2026-05-09T09:30:35.997591+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-09/1778 /Users/lukas/.screenpipe/data/data/2026-05-09/1778319035997_m2.jpg...
|
Firefox
|
Finance Hub — Personal
|
True
|
finance-hub.lakylak.xyz/outpost.goauthentik.io/sig finance-hub.lakylak.xyz/outpost.goauthentik.io/sign_out...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
DNS / Nameservers | Hostinger
DNS / Nameservers | Hostinger
Nginx Proxy Manager
Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
Payments Logger
Payments Logger
Inbox - [EMAIL] - Gmail
Inbox - [EMAIL] - Gmail
(25) Quora
(25) Quora
Location Logger
Location Logger
Finance Hub
Finance Hub
Finance Hub
Finance Hub
Close tab
Select: payments - db - Adminer
Select: payments - db - Adminer
Електронно банкиране ДСК Директ от Банка ДСК
Електронно банкиране ДСК Директ от Банка ДСК
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
VIVACOM
VIVACOM
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
VIVACOM
VIVACOM
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Claude Code | Claude Platform
Claude Code | Claude Platform
Claude
Claude
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Finance Hub
Finance Hub
18
transaction
s
Payments
Payments
Upload CSV
Upload CSV
Refresh
Display settings
Sign out
Filters
Filters
Search...
dd
/
mm
/
yyyy
Calendar
dd
/
mm
/
yyyy
Calendar
DATE
RECIPIENT
AMOUNT
TAGS
22 Apr 2026
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
1000.00 EUR
Send
Send
Skip
Skip
Delete
30 Apr 2026
ВЕДА ПЕЙРОЛ ООД
Raw data
4325.26 EUR
Salary
Send
Send
Skip
Skip
Delete
30 Apr 2026
—
Raw data
10.22 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ЧЦДГ МИЛА
Raw data
460.00 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
14.27 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
29.54 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
0.09 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
47.63 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
8.44 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
17.93 EUR
Bills
Send
Send
Skip
Skip
Delete
06 May 2026, 13:16
POL BALICE Lagardere Travel R KR3
Raw data
5.49 EUR
Send
Send
Skip
Skip
Delete
07 May 2026, 09:02
BGR SOFIA CBA EKO MARKET
Raw data
5.51 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026, 19:32
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
67.81 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
9.04 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
15.46 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
5.02 EUR
Send
Send
Skip
Skip
Delete
08 May 2026, 10:00
DSK ATM, SOFIA, BG
Raw data
200.00 EUR
Send
Send
Skip
Skip
Delete
DATE
22 Apr 2026
30 Apr 2026
30 Apr 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
06 May 2026, 13:16
07 May 2026, 09:02
08 May 2026, 19:32
08 May 2026
08 May 2026
08 May 2026
08 May 2026, 10:00
RECIPIENT
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
ВЕДА ПЕЙРОЛ ООД
Raw data
—
Raw data
ЧЦДГ МИЛА
Raw data
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
POL BALICE Lagardere Travel R KR3
Raw data
BGR SOFIA CBA EKO MARKET
Raw data
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
—
Raw data
—
Raw data
—
Raw data
DSK ATM, SOFIA, BG
Raw data
AMOUNT
1000.00 EUR
4325.26 EUR
10.22 EUR
460.00 EUR
14.27 EUR
29.54 EUR
0.09 EUR
47.63 EUR
8.44 EUR
17.93 EUR
5.49 EUR
5.51 EUR
67.81 EUR
9.04 EUR
15.46 EUR
5.02 EUR
200.00 EUR
TAGS
Salary
Bills
Bills
Bills
Bills
Bills
Bills
Groceries
Groceries
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.080784574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DNS / Nameservers | Hostinger","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DNS / Nameservers | Hostinger","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.053856384,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Nginx Proxy Manager","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Nginx Proxy Manager","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.0,"top":0.15003991,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.0,"top":0.18276137,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.040724736,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.0,"top":0.21548285,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.013297873,"top":0.22665602,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.0,"top":0.2482043,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.013297873,"top":0.25937748,"width":0.11469415,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.0,"top":0.28092578,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"bounds":{"left":0.013297873,"top":0.29209897,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AFFiNE - All In One KnowledgeOS","depth":4,"bounds":{"left":0.0,"top":0.31364724,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE - All In One KnowledgeOS","depth":5,"bounds":{"left":0.013297873,"top":0.32482043,"width":0.05851064,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"bounds":{"left":0.0,"top":0.3463687,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All docs · AFFiNE","depth":5,"bounds":{"left":0.013297873,"top":0.3575419,"width":0.029587766,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Payments Logger","depth":4,"bounds":{"left":0.0,"top":0.3790902,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Payments Logger","depth":5,"bounds":{"left":0.013297873,"top":0.39026338,"width":0.030086435,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox - kovaliklukas@gmail.com - Gmail","depth":4,"bounds":{"left":0.0,"top":0.41181165,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox - kovaliklukas@gmail.com - Gmail","depth":5,"bounds":{"left":0.013297873,"top":0.42298484,"width":0.06898271,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"(25) Quora","depth":4,"bounds":{"left":0.0,"top":0.4445331,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"(25) Quora","depth":5,"bounds":{"left":0.013297873,"top":0.4557063,"width":0.018949468,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Location Logger","depth":4,"bounds":{"left":0.0,"top":0.4772546,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Location Logger","depth":5,"bounds":{"left":0.013297873,"top":0.4884278,"width":0.028091755,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"bounds":{"left":0.0,"top":0.509976,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Finance Hub","depth":5,"bounds":{"left":0.013297873,"top":0.5211492,"width":0.021609042,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"bounds":{"left":0.0,"top":0.54269755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Finance Hub","depth":5,"bounds":{"left":0.013297873,"top":0.55387074,"width":0.021609042,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.10139628,"top":0.54988027,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Select: payments - db - Adminer","depth":4,"bounds":{"left":0.0,"top":0.575419,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Select: payments - db - Adminer","depth":5,"bounds":{"left":0.013297873,"top":0.5865922,"width":0.05651596,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Електронно банкиране ДСК Директ от Банка ДСК","depth":4,"bounds":{"left":0.0,"top":0.60814047,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Електронно банкиране ДСК Директ от Банка ДСК","depth":5,"bounds":{"left":0.013297873,"top":0.61931366,"width":0.09059176,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE","depth":4,"bounds":{"left":0.0,"top":0.6408619,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE","depth":5,"bounds":{"left":0.013297873,"top":0.6520351,"width":0.113696806,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"VIVACOM","depth":4,"bounds":{"left":0.0,"top":0.6735834,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"VIVACOM","depth":5,"bounds":{"left":0.013297873,"top":0.6847566,"width":0.016788565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Смартфони с Unlimited план до 120 € отстъпка | Vivacom","depth":4,"bounds":{"left":0.0,"top":0.70630485,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Смартфони с Unlimited план до 120 € отстъпка | Vivacom","depth":5,"bounds":{"left":0.013297873,"top":0.71747804,"width":0.10239362,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"VIVACOM","depth":4,"bounds":{"left":0.0,"top":0.7390263,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"VIVACOM","depth":5,"bounds":{"left":0.013297873,"top":0.7501995,"width":0.016788565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom","depth":4,"bounds":{"left":0.0,"top":0.7717478,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom","depth":5,"bounds":{"left":0.013297873,"top":0.782921,"width":0.098902926,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude Code | Claude Platform","depth":4,"bounds":{"left":0.0,"top":0.8044693,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Claude Code | Claude Platform","depth":5,"bounds":{"left":0.013297873,"top":0.8156425,"width":0.053357713,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude","depth":4,"bounds":{"left":0.0,"top":0.83719075,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Claude","depth":5,"bounds":{"left":0.013297873,"top":0.84836394,"width":0.012134309,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.87150836,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Finance Hub","depth":8,"bounds":{"left":0.22539894,"top":0.0622506,"width":0.032081116,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Finance Hub","depth":9,"bounds":{"left":0.22539894,"top":0.06264964,"width":0.032081116,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18","depth":9,"bounds":{"left":0.22539894,"top":0.07861133,"width":0.0043218085,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"transaction","depth":9,"bounds":{"left":0.22972074,"top":0.07861133,"width":0.02244016,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"s","depth":9,"bounds":{"left":0.2521609,"top":0.07861133,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Payments","depth":8,"bounds":{"left":0.37982047,"top":0.06384677,"width":0.036070477,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Payments","depth":10,"bounds":{"left":0.39045876,"top":0.0698324,"width":0.02144282,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Upload CSV","depth":8,"bounds":{"left":0.41655585,"top":0.06384677,"width":0.04105718,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Upload CSV","depth":10,"bounds":{"left":0.42719415,"top":0.0698324,"width":0.02642952,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Refresh","depth":8,"bounds":{"left":0.57978725,"top":0.06384677,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Display settings","depth":8,"bounds":{"left":0.5924202,"top":0.06384677,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Sign out","depth":8,"bounds":{"left":0.6050532,"top":0.06384677,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Filters","depth":8,"bounds":{"left":0.21708776,"top":0.13168396,"width":0.3929521,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Filters","depth":10,"bounds":{"left":0.22506648,"top":0.13288109,"width":0.013630319,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search...","depth":9,"bounds":{"left":0.21708776,"top":0.16759777,"width":0.075465426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"dd","depth":11,"bounds":{"left":0.23038563,"top":0.21588188,"width":0.0056515955,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"bounds":{"left":0.23703457,"top":0.21588188,"width":0.0013297872,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mm","depth":11,"bounds":{"left":0.2393617,"top":0.21588188,"width":0.007978723,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"bounds":{"left":0.24833776,"top":0.21588188,"width":0.0013297872,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"yyyy","depth":11,"bounds":{"left":0.2506649,"top":0.21588188,"width":0.009973404,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":10,"bounds":{"left":0.40043217,"top":0.21667998,"width":0.006150266,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"dd","depth":11,"bounds":{"left":0.42885637,"top":0.21588188,"width":0.0056515955,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"bounds":{"left":0.43550533,"top":0.21588188,"width":0.0013297872,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mm","depth":11,"bounds":{"left":0.43783244,"top":0.21588188,"width":0.007978723,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"bounds":{"left":0.44680852,"top":0.21588188,"width":0.0013297872,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"yyyy","depth":11,"bounds":{"left":0.44913563,"top":0.21588188,"width":0.009973404,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":10,"bounds":{"left":0.59890294,"top":0.21667998,"width":0.006150266,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DATE","depth":13,"bounds":{"left":0.21708776,"top":0.27813247,"width":0.011136968,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RECIPIENT","depth":13,"bounds":{"left":0.2864029,"top":0.27813247,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AMOUNT","depth":13,"bounds":{"left":0.42785904,"top":0.27813247,"width":0.019448139,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"TAGS","depth":13,"bounds":{"left":0.47855717,"top":0.27813247,"width":0.011469414,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.30766162,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"МАРТИНА СВЕТОСЛАВОВА КОВАЛИК","depth":14,"bounds":{"left":0.2864029,"top":0.30766162,"width":0.0859375,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.37367022,"top":0.30885875,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1000.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.30766162,"width":0.030086435,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.3048683,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.3084597,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.30407023,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.3084597,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.30407023,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.34197924,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ВЕДА ПЕЙРОЛ ООД","depth":14,"bounds":{"left":0.2864029,"top":0.34197924,"width":0.044714097,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.3324468,"top":0.34317636,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4325.26 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.34197924,"width":0.030086435,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Salary","depth":13,"bounds":{"left":0.48055187,"top":0.34277734,"width":0.011968086,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.33918595,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.34277734,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.33838788,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.34277734,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.33838788,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.37629688,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.37629688,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.377494,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10.22 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.37629688,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.3735036,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.37709498,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.37270552,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.37709498,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.37270552,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.41061452,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЧЦДГ МИЛА","depth":14,"bounds":{"left":0.2864029,"top":0.41061452,"width":0.028091755,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.31582448,"top":0.41181165,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"460.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.41061452,"width":0.027094414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.40782124,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.4114126,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.40702313,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.4114126,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.40702313,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.44493216,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА","depth":14,"bounds":{"left":0.2864029,"top":0.44493216,"width":0.1171875,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.40492022,"top":0.4461293,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"14.27 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.44493216,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.44573024,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.44213888,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.44573024,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.44134077,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.44573024,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.44134077,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.4792498,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"bounds":{"left":0.2864029,"top":0.4792498,"width":0.07164229,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.359375,"top":0.48044693,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"29.54 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.4792498,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.48004788,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.4764565,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.48004788,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.47565842,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.48004788,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.47565842,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.51356745,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"bounds":{"left":0.2864029,"top":0.51356745,"width":0.12084442,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.4085771,"top":0.51476455,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0.09 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.51356745,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.5143655,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.51077414,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.5143655,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.509976,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.5143655,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.509976,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.54788506,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"bounds":{"left":0.2864029,"top":0.54788506,"width":0.12084442,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.4085771,"top":0.5490822,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"47.63 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.54788506,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.54868317,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.5450918,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.54868317,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.5442937,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.54868317,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.5442937,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.58220273,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"bounds":{"left":0.2864029,"top":0.58220273,"width":0.07164229,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.359375,"top":0.58339983,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8.44 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.58220273,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.5830008,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.5794094,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.5830008,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.5786113,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.5830008,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.5786113,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.61652035,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ","depth":14,"bounds":{"left":0.2864029,"top":0.61652035,"width":0.08277926,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.37051198,"top":0.6177175,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"17.93 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.61652035,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.61731845,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.61372703,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.61731845,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.612929,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.61731845,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.612929,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"06 May 2026, 13:16","depth":13,"bounds":{"left":0.21708776,"top":0.650838,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"POL BALICE Lagardere Travel R KR3","depth":14,"bounds":{"left":0.2864029,"top":0.650838,"width":0.07795878,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.36569148,"top":0.6520351,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.49 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.650838,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.6480447,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.65163606,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.6472466,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.65163606,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.6472466,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"07 May 2026, 09:02","depth":13,"bounds":{"left":0.21708776,"top":0.68515563,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BGR SOFIA CBA EKO MARKET","depth":14,"bounds":{"left":0.2864029,"top":0.68515563,"width":0.065159574,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.35289228,"top":0.6863527,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.51 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.68515563,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"bounds":{"left":0.48055187,"top":0.68595374,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.6823623,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.68595374,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.6815643,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.68595374,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.6815643,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026, 19:32","depth":13,"bounds":{"left":0.21708776,"top":0.71947324,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR","depth":14,"bounds":{"left":0.2864029,"top":0.71947324,"width":0.10322473,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.39095744,"top":0.7206704,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"67.81 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.71947324,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"bounds":{"left":0.48055187,"top":0.72027135,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.71668,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.72027135,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.7158819,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.72027135,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.7158819,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.7537909,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.7537909,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.754988,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"9.04 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.7537909,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.7509976,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.75458896,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.7501995,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.75458896,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.7501995,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.7881085,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.7881085,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.7893057,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"15.46 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.7881085,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.7853152,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.78890663,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.78451717,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.78890663,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.78451717,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.8224262,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.8224262,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.8236233,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.02 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.8224262,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.8196329,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.82322425,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.8188348,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.82322425,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.8188348,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026, 10:00","depth":13,"bounds":{"left":0.21708776,"top":0.8567438,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DSK ATM, SOFIA, BG","depth":14,"bounds":{"left":0.2864029,"top":0.8567438,"width":0.045212764,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.33294547,"top":0.8579409,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"200.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.8567438,"width":0.027094414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.8539505,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.8575419,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.85315245,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.8575419,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.85315245,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DATE","depth":13,"bounds":{"left":0.21708776,"top":0.27813247,"width":0.011136968,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.30766162,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.34197924,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.37629688,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.41061452,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.44493216,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.4792498,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.51356745,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.54788506,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.58220273,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.61652035,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"06 May 2026, 13:16","depth":13,"bounds":{"left":0.21708776,"top":0.650838,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"07 May 2026, 09:02","depth":13,"bounds":{"left":0.21708776,"top":0.68515563,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026, 19:32","depth":13,"bounds":{"left":0.21708776,"top":0.71947324,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.7537909,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.7881085,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.8224262,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026, 10:00","depth":13,"bounds":{"left":0.21708776,"top":0.8567438,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RECIPIENT","depth":13,"bounds":{"left":0.2864029,"top":0.27813247,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"МАРТИНА СВЕТОСЛАВОВА КОВАЛИК","depth":14,"bounds":{"left":0.2864029,"top":0.30766162,"width":0.0859375,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.37367022,"top":0.30885875,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ВЕДА ПЕЙРОЛ ООД","depth":14,"bounds":{"left":0.2864029,"top":0.34197924,"width":0.044714097,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.3324468,"top":0.34317636,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.37629688,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.377494,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЧЦДГ МИЛА","depth":14,"bounds":{"left":0.2864029,"top":0.41061452,"width":0.028091755,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.31582448,"top":0.41181165,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА","depth":14,"bounds":{"left":0.2864029,"top":0.44493216,"width":0.1171875,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.40492022,"top":0.4461293,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"bounds":{"left":0.2864029,"top":0.4792498,"width":0.07164229,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.359375,"top":0.48044693,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"bounds":{"left":0.2864029,"top":0.51356745,"width":0.12084442,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.4085771,"top":0.51476455,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"bounds":{"left":0.2864029,"top":0.54788506,"width":0.12084442,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.4085771,"top":0.5490822,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"bounds":{"left":0.2864029,"top":0.58220273,"width":0.07164229,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.359375,"top":0.58339983,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ","depth":14,"bounds":{"left":0.2864029,"top":0.61652035,"width":0.08277926,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.37051198,"top":0.6177175,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"POL BALICE Lagardere Travel R KR3","depth":14,"bounds":{"left":0.2864029,"top":0.650838,"width":0.07795878,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.36569148,"top":0.6520351,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BGR SOFIA CBA EKO MARKET","depth":14,"bounds":{"left":0.2864029,"top":0.68515563,"width":0.065159574,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.35289228,"top":0.6863527,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR","depth":14,"bounds":{"left":0.2864029,"top":0.71947324,"width":0.10322473,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.39095744,"top":0.7206704,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.7537909,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.754988,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.7881085,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.7893057,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.8224262,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.8236233,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DSK ATM, SOFIA, BG","depth":14,"bounds":{"left":0.2864029,"top":0.8567438,"width":0.045212764,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.33294547,"top":0.8579409,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AMOUNT","depth":13,"bounds":{"left":0.42785904,"top":0.27813247,"width":0.019448139,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1000.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.30766162,"width":0.030086435,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4325.26 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.34197924,"width":0.030086435,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10.22 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.37629688,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"460.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.41061452,"width":0.027094414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14.27 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.44493216,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"29.54 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.4792498,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0.09 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.51356745,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"47.63 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.54788506,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8.44 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.58220273,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17.93 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.61652035,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.49 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.650838,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.51 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.68515563,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"67.81 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.71947324,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"9.04 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.7537909,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"15.46 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.7881085,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.02 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.8224262,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"200.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.8567438,"width":0.027094414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"TAGS","depth":13,"bounds":{"left":0.47855717,"top":0.27813247,"width":0.011469414,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Salary","depth":13,"bounds":{"left":0.48055187,"top":0.34277734,"width":0.011968086,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.44573024,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.48004788,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.5143655,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.54868317,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.5830008,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.61731845,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"bounds":{"left":0.48055187,"top":0.68595374,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"bounds":{"left":0.48055187,"top":0.72027135,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.3048683,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.3084597,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.30407023,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.3084597,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.30407023,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.33918595,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.34277734,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.33838788,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.34277734,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.33838788,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.3735036,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.37709498,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.37270552,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.37709498,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.37270552,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.40782124,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.4114126,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.40702313,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.4114126,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.40702313,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.44213888,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.44573024,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.44134077,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.44573024,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.44134077,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.4764565,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.48004788,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.47565842,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.48004788,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.47565842,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.51077414,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.5143655,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.509976,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.5143655,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.509976,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.5450918,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.54868317,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.5442937,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.54868317,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.5442937,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.5794094,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.5830008,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.5786113,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.5830008,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.5786113,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.61372703,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.61731845,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.612929,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.61731845,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.612929,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.6480447,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.65163606,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.6472466,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.65163606,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.6472466,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.6823623,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.68595374,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.6815643,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.68595374,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.6815643,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.71668,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.72027135,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.7158819,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.72027135,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.7158819,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.7509976,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.75458896,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.7501995,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.75458896,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.7501995,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.7853152,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.78890663,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.78451717,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.78890663,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.78451717,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.8196329,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.82322425,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.8188348,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.82322425,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.8188348,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.8539505,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.8575419,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.85315245,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.8575419,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.85315245,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-7757773811144613165
|
5044045952359475102
|
idle
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
DNS / Nameservers | Hostinger
DNS / Nameservers | Hostinger
Nginx Proxy Manager
Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
Payments Logger
Payments Logger
Inbox - [EMAIL] - Gmail
Inbox - [EMAIL] - Gmail
(25) Quora
(25) Quora
Location Logger
Location Logger
Finance Hub
Finance Hub
Finance Hub
Finance Hub
Close tab
Select: payments - db - Adminer
Select: payments - db - Adminer
Електронно банкиране ДСК Директ от Банка ДСК
Електронно банкиране ДСК Директ от Банка ДСК
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
VIVACOM
VIVACOM
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
VIVACOM
VIVACOM
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Claude Code | Claude Platform
Claude Code | Claude Platform
Claude
Claude
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Finance Hub
Finance Hub
18
transaction
s
Payments
Payments
Upload CSV
Upload CSV
Refresh
Display settings
Sign out
Filters
Filters
Search...
dd
/
mm
/
yyyy
Calendar
dd
/
mm
/
yyyy
Calendar
DATE
RECIPIENT
AMOUNT
TAGS
22 Apr 2026
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
1000.00 EUR
Send
Send
Skip
Skip
Delete
30 Apr 2026
ВЕДА ПЕЙРОЛ ООД
Raw data
4325.26 EUR
Salary
Send
Send
Skip
Skip
Delete
30 Apr 2026
—
Raw data
10.22 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ЧЦДГ МИЛА
Raw data
460.00 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
14.27 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
29.54 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
0.09 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
47.63 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
8.44 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
17.93 EUR
Bills
Send
Send
Skip
Skip
Delete
06 May 2026, 13:16
POL BALICE Lagardere Travel R KR3
Raw data
5.49 EUR
Send
Send
Skip
Skip
Delete
07 May 2026, 09:02
BGR SOFIA CBA EKO MARKET
Raw data
5.51 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026, 19:32
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
67.81 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
9.04 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
15.46 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
5.02 EUR
Send
Send
Skip
Skip
Delete
08 May 2026, 10:00
DSK ATM, SOFIA, BG
Raw data
200.00 EUR
Send
Send
Skip
Skip
Delete
DATE
22 Apr 2026
30 Apr 2026
30 Apr 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
06 May 2026, 13:16
07 May 2026, 09:02
08 May 2026, 19:32
08 May 2026
08 May 2026
08 May 2026
08 May 2026, 10:00
RECIPIENT
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
ВЕДА ПЕЙРОЛ ООД
Raw data
—
Raw data
ЧЦДГ МИЛА
Raw data
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
POL BALICE Lagardere Travel R KR3
Raw data
BGR SOFIA CBA EKO MARKET
Raw data
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
—
Raw data
—
Raw data
—
Raw data
DSK ATM, SOFIA, BG
Raw data
AMOUNT
1000.00 EUR
4325.26 EUR
10.22 EUR
460.00 EUR
14.27 EUR
29.54 EUR
0.09 EUR
47.63 EUR
8.44 EUR
17.93 EUR
5.49 EUR
5.51 EUR
67.81 EUR
9.04 EUR
15.46 EUR
5.02 EUR
200.00 EUR
TAGS
Salary
Bills
Bills
Bills
Bills
Bills
Bills
Groceries
Groceries
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete...
|
12793
|
NULL
|
NULL
|
NULL
|
|
12796
|
563
|
19
|
2026-05-09T09:31:02.418996+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-09/1778 /Users/lukas/.screenpipe/data/data/2026-05-09/1778319062418_m1.jpg...
|
Firefox
|
Finance Hub — Personal
|
True
|
finance-hub.lakylak.xyz/outpost.goauthentik.io/sig finance-hub.lakylak.xyz/outpost.goauthentik.io/sign_out...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
DNS / Nameservers | Hostinger
DNS / Nameservers | Hostinger
Nginx Proxy Manager
Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
Payments Logger
Payments Logger
Inbox - [EMAIL] - Gmail
Inbox - [EMAIL] - Gmail
(25) Quora
(25) Quora
Location Logger
Location Logger
Finance Hub
Finance Hub
Finance Hub
Finance Hub
Close tab
Select: payments - db - Adminer
Select: payments - db - Adminer
Електронно банкиране ДСК Директ от Банка ДСК
Електронно банкиране ДСК Директ от Банка ДСК
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
VIVACOM
VIVACOM
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
VIVACOM
VIVACOM
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Claude Code | Claude Platform
Claude Code | Claude Platform
Claude
Claude
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Finance Hub
Finance Hub
18
transaction
s
Payments
Payments
Upload CSV
Upload CSV
Refresh
Display settings
Sign out
Filters
Filters
Search...
dd
/
mm
/
yyyy
Calendar
dd
/
mm
/
yyyy
Calendar
DATE
RECIPIENT
AMOUNT
TAGS
22 Apr 2026
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
1000.00 EUR
Send
Send
Skip
Skip
Delete
30 Apr 2026
ВЕДА ПЕЙРОЛ ООД
Raw data
4325.26 EUR
Salary
Send
Send
Skip
Skip
Delete
30 Apr 2026
—
Raw data
10.22 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ЧЦДГ МИЛА
Raw data
460.00 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
14.27 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
29.54 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
0.09 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
47.63 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
8.44 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
17.93 EUR
Bills
Send
Send
Skip
Skip
Delete
06 May 2026, 13:16
POL BALICE Lagardere Travel R KR3
Raw data
5.49 EUR
Send
Send
Skip
Skip
Delete
07 May 2026, 09:02
BGR SOFIA CBA EKO MARKET
Raw data
5.51 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026, 19:32
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
67.81 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
9.04 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
15.46 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
5.02 EUR
Send
Send
Skip
Skip
Delete
08 May 2026, 10:00
DSK ATM, SOFIA, BG
Raw data
200.00 EUR
Send
Send
Skip
Skip
Delete
DATE
22 Apr 2026
30 Apr 2026
30 Apr 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
06 May 2026, 13:16
07 May 2026, 09:02
08 May 2026, 19:32
08 May 2026
08 May 2026
08 May 2026
08 May 2026, 10:00
RECIPIENT
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
ВЕДА ПЕЙРОЛ ООД
Raw data
—
Raw data
ЧЦДГ МИЛА
Raw data
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
POL BALICE Lagardere Travel R KR3
Raw data
BGR SOFIA CBA EKO MARKET
Raw data
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
—
Raw data
—
Raw data
—
Raw data
DSK ATM, SOFIA, BG
Raw data
AMOUNT
1000.00 EUR
4325.26 EUR
10.22 EUR
460.00 EUR
14.27 EUR
29.54 EUR
0.09 EUR
47.63 EUR
8.44 EUR
17.93 EUR
5.49 EUR
5.51 EUR
67.81 EUR
9.04 EUR
15.46 EUR
5.02 EUR
200.00 EUR
TAGS
Salary
Bills
Bills
Bills
Bills
Bills
Bills
Groceries
Groceries
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DNS / Nameservers | Hostinger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DNS / Nameservers | Hostinger","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Nginx Proxy Manager","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Nginx Proxy Manager","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AFFiNE - All In One KnowledgeOS","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE - All In One KnowledgeOS","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All docs · AFFiNE","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Payments Logger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Payments Logger","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox - kovaliklukas@gmail.com - Gmail","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox - kovaliklukas@gmail.com - Gmail","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"(25) Quora","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"(25) Quora","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Location Logger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Location Logger","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Finance Hub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Finance Hub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Select: payments - db - Adminer","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Select: payments - db - Adminer","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Електронно банкиране ДСК Директ от Банка ДСК","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Електронно банкиране ДСК Директ от Банка ДСК","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"VIVACOM","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"VIVACOM","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Смартфони с Unlimited план до 120 € отстъпка | Vivacom","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Смартфони с Unlimited план до 120 € отстъпка | Vivacom","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"VIVACOM","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"VIVACOM","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude Code | Claude Platform","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Claude Code | Claude Platform","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Claude","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Finance Hub","depth":8,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Finance Hub","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"transaction","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"s","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Payments","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Payments","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Upload CSV","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Upload CSV","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Refresh","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Display settings","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Sign out","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Filters","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Filters","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search...","depth":9,"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"dd","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mm","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"yyyy","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"dd","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mm","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"yyyy","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DATE","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RECIPIENT","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AMOUNT","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"TAGS","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"МАРТИНА СВЕТОСЛАВОВА КОВАЛИК","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1000.00 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ВЕДА ПЕЙРОЛ ООД","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4325.26 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Salary","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10.22 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЧЦДГ МИЛА","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"460.00 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"14.27 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"29.54 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0.09 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"47.63 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8.44 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"17.93 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"06 May 2026, 13:16","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"POL BALICE Lagardere Travel R KR3","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.49 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"07 May 2026, 09:02","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BGR SOFIA CBA EKO MARKET","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.51 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026, 19:32","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"67.81 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"9.04 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"15.46 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.02 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026, 10:00","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DSK ATM, SOFIA, BG","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"200.00 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DATE","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"06 May 2026, 13:16","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"07 May 2026, 09:02","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026, 19:32","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026, 10:00","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RECIPIENT","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"МАРТИНА СВЕТОСЛАВОВА КОВАЛИК","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ВЕДА ПЕЙРОЛ ООД","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЧЦДГ МИЛА","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"POL BALICE Lagardere Travel R KR3","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BGR SOFIA CBA EKO MARKET","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DSK ATM, SOFIA, BG","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AMOUNT","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1000.00 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4325.26 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10.22 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"460.00 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14.27 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"29.54 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0.09 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"47.63 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8.44 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17.93 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.49 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.51 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"67.81 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"9.04 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"15.46 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.02 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"200.00 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"TAGS","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Salary","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-7757773811144613165
|
5044045952359475102
|
idle
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
DNS / Nameservers | Hostinger
DNS / Nameservers | Hostinger
Nginx Proxy Manager
Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
Payments Logger
Payments Logger
Inbox - [EMAIL] - Gmail
Inbox - [EMAIL] - Gmail
(25) Quora
(25) Quora
Location Logger
Location Logger
Finance Hub
Finance Hub
Finance Hub
Finance Hub
Close tab
Select: payments - db - Adminer
Select: payments - db - Adminer
Електронно банкиране ДСК Директ от Банка ДСК
Електронно банкиране ДСК Директ от Банка ДСК
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
VIVACOM
VIVACOM
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
VIVACOM
VIVACOM
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Claude Code | Claude Platform
Claude Code | Claude Platform
Claude
Claude
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Finance Hub
Finance Hub
18
transaction
s
Payments
Payments
Upload CSV
Upload CSV
Refresh
Display settings
Sign out
Filters
Filters
Search...
dd
/
mm
/
yyyy
Calendar
dd
/
mm
/
yyyy
Calendar
DATE
RECIPIENT
AMOUNT
TAGS
22 Apr 2026
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
1000.00 EUR
Send
Send
Skip
Skip
Delete
30 Apr 2026
ВЕДА ПЕЙРОЛ ООД
Raw data
4325.26 EUR
Salary
Send
Send
Skip
Skip
Delete
30 Apr 2026
—
Raw data
10.22 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ЧЦДГ МИЛА
Raw data
460.00 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
14.27 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
29.54 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
0.09 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
47.63 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
8.44 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
17.93 EUR
Bills
Send
Send
Skip
Skip
Delete
06 May 2026, 13:16
POL BALICE Lagardere Travel R KR3
Raw data
5.49 EUR
Send
Send
Skip
Skip
Delete
07 May 2026, 09:02
BGR SOFIA CBA EKO MARKET
Raw data
5.51 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026, 19:32
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
67.81 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
9.04 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
15.46 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
5.02 EUR
Send
Send
Skip
Skip
Delete
08 May 2026, 10:00
DSK ATM, SOFIA, BG
Raw data
200.00 EUR
Send
Send
Skip
Skip
Delete
DATE
22 Apr 2026
30 Apr 2026
30 Apr 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
06 May 2026, 13:16
07 May 2026, 09:02
08 May 2026, 19:32
08 May 2026
08 May 2026
08 May 2026
08 May 2026, 10:00
RECIPIENT
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
ВЕДА ПЕЙРОЛ ООД
Raw data
—
Raw data
ЧЦДГ МИЛА
Raw data
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
POL BALICE Lagardere Travel R KR3
Raw data
BGR SOFIA CBA EKO MARKET
Raw data
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
—
Raw data
—
Raw data
—
Raw data
DSK ATM, SOFIA, BG
Raw data
AMOUNT
1000.00 EUR
4325.26 EUR
10.22 EUR
460.00 EUR
14.27 EUR
29.54 EUR
0.09 EUR
47.63 EUR
8.44 EUR
17.93 EUR
5.49 EUR
5.51 EUR
67.81 EUR
9.04 EUR
15.46 EUR
5.02 EUR
200.00 EUR
TAGS
Salary
Bills
Bills
Bills
Bills
Bills
Bills
Groceries
Groceries
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
12797
|
564
|
17
|
2026-05-09T09:31:07.230680+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-09/1778 /Users/lukas/.screenpipe/data/data/2026-05-09/1778319067230_m2.jpg...
|
Firefox
|
Finance Hub — Personal
|
True
|
finance-hub.lakylak.xyz/outpost.goauthentik.io/sig finance-hub.lakylak.xyz/outpost.goauthentik.io/sign_out...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
DNS / Nameservers | Hostinger
DNS / Nameservers | Hostinger
Nginx Proxy Manager
Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
Payments Logger
Payments Logger
Inbox - [EMAIL] - Gmail
Inbox - [EMAIL] - Gmail
(25) Quora
(25) Quora
Location Logger
Location Logger
Finance Hub
Finance Hub
Finance Hub
Finance Hub
Close tab
Select: payments - db - Adminer
Select: payments - db - Adminer
Електронно банкиране ДСК Директ от Банка ДСК
Електронно банкиране ДСК Директ от Банка ДСК
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
VIVACOM
VIVACOM
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
VIVACOM
VIVACOM
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Claude Code | Claude Platform
Claude Code | Claude Platform
Claude
Claude
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Finance Hub
Finance Hub
18
transaction
s
Payments
Payments
Upload CSV
Upload CSV
Refresh
Display settings
Sign out
Filters
Filters
Search...
dd
/
mm
/
yyyy
Calendar
dd
/
mm
/
yyyy
Calendar
DATE
RECIPIENT
AMOUNT
TAGS
22 Apr 2026
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
1000.00 EUR
Send
Send
Skip
Skip
Delete
30 Apr 2026
ВЕДА ПЕЙРОЛ ООД
Raw data
4325.26 EUR
Salary
Send
Send
Skip
Skip
Delete
30 Apr 2026
—
Raw data
10.22 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ЧЦДГ МИЛА
Raw data
460.00 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
14.27 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
29.54 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
0.09 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
47.63 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
8.44 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
17.93 EUR
Bills
Send
Send
Skip
Skip
Delete
06 May 2026, 13:16
POL BALICE Lagardere Travel R KR3
Raw data
5.49 EUR
Send
Send
Skip
Skip
Delete
07 May 2026, 09:02
BGR SOFIA CBA EKO MARKET
Raw data
5.51 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026, 19:32
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
67.81 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
9.04 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
15.46 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
5.02 EUR
Send
Send
Skip
Skip
Delete
08 May 2026, 10:00
DSK ATM, SOFIA, BG
Raw data
200.00 EUR
Send
Send
Skip
Skip
Delete
DATE
22 Apr 2026
30 Apr 2026
30 Apr 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
06 May 2026, 13:16
07 May 2026, 09:02
08 May 2026, 19:32
08 May 2026
08 May 2026
08 May 2026
08 May 2026, 10:00
RECIPIENT
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
ВЕДА ПЕЙРОЛ ООД
Raw data
—
Raw data
ЧЦДГ МИЛА
Raw data
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
POL BALICE Lagardere Travel R KR3
Raw data
BGR SOFIA CBA EKO MARKET
Raw data
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
—
Raw data
—
Raw data
—
Raw data
DSK ATM, SOFIA, BG
Raw data
AMOUNT
1000.00 EUR
4325.26 EUR
10.22 EUR
460.00 EUR
14.27 EUR
29.54 EUR
0.09 EUR
47.63 EUR
8.44 EUR
17.93 EUR
5.49 EUR
5.51 EUR
67.81 EUR
9.04 EUR
15.46 EUR
5.02 EUR
200.00 EUR
TAGS
Salary
Bills
Bills
Bills
Bills
Bills
Bills
Groceries
Groceries
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.080784574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DNS / Nameservers | Hostinger","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DNS / Nameservers | Hostinger","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.053856384,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Nginx Proxy Manager","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Nginx Proxy Manager","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.0,"top":0.15003991,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.0,"top":0.18276137,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.040724736,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.0,"top":0.21548285,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.013297873,"top":0.22665602,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.0,"top":0.2482043,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.013297873,"top":0.25937748,"width":0.11469415,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.0,"top":0.28092578,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"bounds":{"left":0.013297873,"top":0.29209897,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AFFiNE - All In One KnowledgeOS","depth":4,"bounds":{"left":0.0,"top":0.31364724,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE - All In One KnowledgeOS","depth":5,"bounds":{"left":0.013297873,"top":0.32482043,"width":0.05851064,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"bounds":{"left":0.0,"top":0.3463687,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All docs · AFFiNE","depth":5,"bounds":{"left":0.013297873,"top":0.3575419,"width":0.029587766,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Payments Logger","depth":4,"bounds":{"left":0.0,"top":0.3790902,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Payments Logger","depth":5,"bounds":{"left":0.013297873,"top":0.39026338,"width":0.030086435,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox - kovaliklukas@gmail.com - Gmail","depth":4,"bounds":{"left":0.0,"top":0.41181165,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox - kovaliklukas@gmail.com - Gmail","depth":5,"bounds":{"left":0.013297873,"top":0.42298484,"width":0.06898271,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"(25) Quora","depth":4,"bounds":{"left":0.0,"top":0.4445331,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"(25) Quora","depth":5,"bounds":{"left":0.013297873,"top":0.4557063,"width":0.018949468,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Location Logger","depth":4,"bounds":{"left":0.0,"top":0.4772546,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Location Logger","depth":5,"bounds":{"left":0.013297873,"top":0.4884278,"width":0.028091755,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"bounds":{"left":0.0,"top":0.509976,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Finance Hub","depth":5,"bounds":{"left":0.013297873,"top":0.5211492,"width":0.021609042,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"bounds":{"left":0.0,"top":0.54269755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Finance Hub","depth":5,"bounds":{"left":0.013297873,"top":0.55387074,"width":0.021609042,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.10139628,"top":0.54988027,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Select: payments - db - Adminer","depth":4,"bounds":{"left":0.0,"top":0.575419,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Select: payments - db - Adminer","depth":5,"bounds":{"left":0.013297873,"top":0.5865922,"width":0.05651596,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Електронно банкиране ДСК Директ от Банка ДСК","depth":4,"bounds":{"left":0.0,"top":0.60814047,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Електронно банкиране ДСК Директ от Банка ДСК","depth":5,"bounds":{"left":0.013297873,"top":0.61931366,"width":0.09059176,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE","depth":4,"bounds":{"left":0.0,"top":0.6408619,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE","depth":5,"bounds":{"left":0.013297873,"top":0.6520351,"width":0.113696806,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"VIVACOM","depth":4,"bounds":{"left":0.0,"top":0.6735834,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"VIVACOM","depth":5,"bounds":{"left":0.013297873,"top":0.6847566,"width":0.016788565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Смартфони с Unlimited план до 120 € отстъпка | Vivacom","depth":4,"bounds":{"left":0.0,"top":0.70630485,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Смартфони с Unlimited план до 120 € отстъпка | Vivacom","depth":5,"bounds":{"left":0.013297873,"top":0.71747804,"width":0.10239362,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"VIVACOM","depth":4,"bounds":{"left":0.0,"top":0.7390263,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"VIVACOM","depth":5,"bounds":{"left":0.013297873,"top":0.7501995,"width":0.016788565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom","depth":4,"bounds":{"left":0.0,"top":0.7717478,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom","depth":5,"bounds":{"left":0.013297873,"top":0.782921,"width":0.098902926,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude Code | Claude Platform","depth":4,"bounds":{"left":0.0,"top":0.8044693,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Claude Code | Claude Platform","depth":5,"bounds":{"left":0.013297873,"top":0.8156425,"width":0.053357713,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude","depth":4,"bounds":{"left":0.0,"top":0.83719075,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Claude","depth":5,"bounds":{"left":0.013297873,"top":0.84836394,"width":0.012134309,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.87150836,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Finance Hub","depth":8,"bounds":{"left":0.22539894,"top":0.0622506,"width":0.032081116,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Finance Hub","depth":9,"bounds":{"left":0.22539894,"top":0.06264964,"width":0.032081116,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18","depth":9,"bounds":{"left":0.22539894,"top":0.07861133,"width":0.0043218085,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"transaction","depth":9,"bounds":{"left":0.22972074,"top":0.07861133,"width":0.02244016,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"s","depth":9,"bounds":{"left":0.2521609,"top":0.07861133,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Payments","depth":8,"bounds":{"left":0.37982047,"top":0.06384677,"width":0.036070477,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Payments","depth":10,"bounds":{"left":0.39045876,"top":0.0698324,"width":0.02144282,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Upload CSV","depth":8,"bounds":{"left":0.41655585,"top":0.06384677,"width":0.04105718,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Upload CSV","depth":10,"bounds":{"left":0.42719415,"top":0.0698324,"width":0.02642952,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Refresh","depth":8,"bounds":{"left":0.57978725,"top":0.06384677,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Display settings","depth":8,"bounds":{"left":0.5924202,"top":0.06384677,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Sign out","depth":8,"bounds":{"left":0.6050532,"top":0.06384677,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Filters","depth":8,"bounds":{"left":0.21708776,"top":0.13168396,"width":0.3929521,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Filters","depth":10,"bounds":{"left":0.22506648,"top":0.13288109,"width":0.013630319,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search...","depth":9,"bounds":{"left":0.21708776,"top":0.16759777,"width":0.075465426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"dd","depth":11,"bounds":{"left":0.23038563,"top":0.21588188,"width":0.0056515955,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"bounds":{"left":0.23703457,"top":0.21588188,"width":0.0013297872,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mm","depth":11,"bounds":{"left":0.2393617,"top":0.21588188,"width":0.007978723,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"bounds":{"left":0.24833776,"top":0.21588188,"width":0.0013297872,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"yyyy","depth":11,"bounds":{"left":0.2506649,"top":0.21588188,"width":0.009973404,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":10,"bounds":{"left":0.40043217,"top":0.21667998,"width":0.006150266,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"dd","depth":11,"bounds":{"left":0.42885637,"top":0.21588188,"width":0.0056515955,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"bounds":{"left":0.43550533,"top":0.21588188,"width":0.0013297872,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mm","depth":11,"bounds":{"left":0.43783244,"top":0.21588188,"width":0.007978723,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"bounds":{"left":0.44680852,"top":0.21588188,"width":0.0013297872,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"yyyy","depth":11,"bounds":{"left":0.44913563,"top":0.21588188,"width":0.009973404,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":10,"bounds":{"left":0.59890294,"top":0.21667998,"width":0.006150266,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DATE","depth":13,"bounds":{"left":0.21708776,"top":0.27813247,"width":0.011136968,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RECIPIENT","depth":13,"bounds":{"left":0.2864029,"top":0.27813247,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AMOUNT","depth":13,"bounds":{"left":0.42785904,"top":0.27813247,"width":0.019448139,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"TAGS","depth":13,"bounds":{"left":0.47855717,"top":0.27813247,"width":0.011469414,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.30766162,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"МАРТИНА СВЕТОСЛАВОВА КОВАЛИК","depth":14,"bounds":{"left":0.2864029,"top":0.30766162,"width":0.0859375,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.37367022,"top":0.30885875,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1000.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.30766162,"width":0.030086435,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.3048683,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.3084597,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.30407023,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.3084597,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.30407023,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.34197924,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ВЕДА ПЕЙРОЛ ООД","depth":14,"bounds":{"left":0.2864029,"top":0.34197924,"width":0.044714097,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.3324468,"top":0.34317636,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4325.26 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.34197924,"width":0.030086435,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Salary","depth":13,"bounds":{"left":0.48055187,"top":0.34277734,"width":0.011968086,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.33918595,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.34277734,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.33838788,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.34277734,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.33838788,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.37629688,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.37629688,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.377494,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10.22 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.37629688,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.3735036,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.37709498,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.37270552,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.37709498,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.37270552,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.41061452,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЧЦДГ МИЛА","depth":14,"bounds":{"left":0.2864029,"top":0.41061452,"width":0.028091755,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.31582448,"top":0.41181165,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"460.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.41061452,"width":0.027094414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.40782124,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.4114126,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.40702313,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.4114126,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.40702313,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.44493216,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА","depth":14,"bounds":{"left":0.2864029,"top":0.44493216,"width":0.1171875,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.40492022,"top":0.4461293,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"14.27 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.44493216,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.44573024,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.44213888,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.44573024,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.44134077,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.44573024,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.44134077,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.4792498,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"bounds":{"left":0.2864029,"top":0.4792498,"width":0.07164229,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.359375,"top":0.48044693,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"29.54 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.4792498,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.48004788,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.4764565,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.48004788,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.47565842,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.48004788,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.47565842,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.51356745,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"bounds":{"left":0.2864029,"top":0.51356745,"width":0.12084442,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.4085771,"top":0.51476455,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0.09 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.51356745,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.5143655,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.51077414,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.5143655,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.509976,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.5143655,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.509976,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.54788506,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"bounds":{"left":0.2864029,"top":0.54788506,"width":0.12084442,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.4085771,"top":0.5490822,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"47.63 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.54788506,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.54868317,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.5450918,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.54868317,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.5442937,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.54868317,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.5442937,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.58220273,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"bounds":{"left":0.2864029,"top":0.58220273,"width":0.07164229,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.359375,"top":0.58339983,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8.44 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.58220273,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.5830008,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.5794094,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.5830008,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.5786113,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.5830008,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.5786113,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.61652035,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ","depth":14,"bounds":{"left":0.2864029,"top":0.61652035,"width":0.08277926,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.37051198,"top":0.6177175,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"17.93 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.61652035,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.61731845,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.61372703,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.61731845,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.612929,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.61731845,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.612929,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"06 May 2026, 13:16","depth":13,"bounds":{"left":0.21708776,"top":0.650838,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"POL BALICE Lagardere Travel R KR3","depth":14,"bounds":{"left":0.2864029,"top":0.650838,"width":0.07795878,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.36569148,"top":0.6520351,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.49 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.650838,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.6480447,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.65163606,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.6472466,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.65163606,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.6472466,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"07 May 2026, 09:02","depth":13,"bounds":{"left":0.21708776,"top":0.68515563,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BGR SOFIA CBA EKO MARKET","depth":14,"bounds":{"left":0.2864029,"top":0.68515563,"width":0.065159574,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.35289228,"top":0.6863527,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.51 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.68515563,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"bounds":{"left":0.48055187,"top":0.68595374,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.6823623,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.68595374,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.6815643,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.68595374,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.6815643,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026, 19:32","depth":13,"bounds":{"left":0.21708776,"top":0.71947324,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR","depth":14,"bounds":{"left":0.2864029,"top":0.71947324,"width":0.10322473,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.39095744,"top":0.7206704,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"67.81 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.71947324,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"bounds":{"left":0.48055187,"top":0.72027135,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.71668,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.72027135,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.7158819,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.72027135,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.7158819,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.7537909,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.7537909,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.754988,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"9.04 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.7537909,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.7509976,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.75458896,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.7501995,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.75458896,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.7501995,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.7881085,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.7881085,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.7893057,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"15.46 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.7881085,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.7853152,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.78890663,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.78451717,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.78890663,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.78451717,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.8224262,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.8224262,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.8236233,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.02 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.8224262,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.8196329,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.82322425,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.8188348,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.82322425,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.8188348,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026, 10:00","depth":13,"bounds":{"left":0.21708776,"top":0.8567438,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DSK ATM, SOFIA, BG","depth":14,"bounds":{"left":0.2864029,"top":0.8567438,"width":0.045212764,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.33294547,"top":0.8579409,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"200.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.8567438,"width":0.027094414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.8539505,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.8575419,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.85315245,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.8575419,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.85315245,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DATE","depth":13,"bounds":{"left":0.21708776,"top":0.27813247,"width":0.011136968,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.30766162,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.34197924,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.37629688,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.41061452,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.44493216,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.4792498,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.51356745,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.54788506,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.58220273,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.61652035,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"06 May 2026, 13:16","depth":13,"bounds":{"left":0.21708776,"top":0.650838,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"07 May 2026, 09:02","depth":13,"bounds":{"left":0.21708776,"top":0.68515563,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026, 19:32","depth":13,"bounds":{"left":0.21708776,"top":0.71947324,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.7537909,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.7881085,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.8224262,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026, 10:00","depth":13,"bounds":{"left":0.21708776,"top":0.8567438,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RECIPIENT","depth":13,"bounds":{"left":0.2864029,"top":0.27813247,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"МАРТИНА СВЕТОСЛАВОВА КОВАЛИК","depth":14,"bounds":{"left":0.2864029,"top":0.30766162,"width":0.0859375,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.37367022,"top":0.30885875,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ВЕДА ПЕЙРОЛ ООД","depth":14,"bounds":{"left":0.2864029,"top":0.34197924,"width":0.044714097,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.3324468,"top":0.34317636,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.37629688,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.377494,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЧЦДГ МИЛА","depth":14,"bounds":{"left":0.2864029,"top":0.41061452,"width":0.028091755,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.31582448,"top":0.41181165,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА","depth":14,"bounds":{"left":0.2864029,"top":0.44493216,"width":0.1171875,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.40492022,"top":0.4461293,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"bounds":{"left":0.2864029,"top":0.4792498,"width":0.07164229,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.359375,"top":0.48044693,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"bounds":{"left":0.2864029,"top":0.51356745,"width":0.12084442,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.4085771,"top":0.51476455,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"bounds":{"left":0.2864029,"top":0.54788506,"width":0.12084442,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.4085771,"top":0.5490822,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"bounds":{"left":0.2864029,"top":0.58220273,"width":0.07164229,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.359375,"top":0.58339983,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ","depth":14,"bounds":{"left":0.2864029,"top":0.61652035,"width":0.08277926,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.37051198,"top":0.6177175,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"POL BALICE Lagardere Travel R KR3","depth":14,"bounds":{"left":0.2864029,"top":0.650838,"width":0.07795878,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.36569148,"top":0.6520351,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BGR SOFIA CBA EKO MARKET","depth":14,"bounds":{"left":0.2864029,"top":0.68515563,"width":0.065159574,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.35289228,"top":0.6863527,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR","depth":14,"bounds":{"left":0.2864029,"top":0.71947324,"width":0.10322473,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.39095744,"top":0.7206704,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.7537909,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.754988,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.7881085,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.7893057,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.8224262,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.8236233,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DSK ATM, SOFIA, BG","depth":14,"bounds":{"left":0.2864029,"top":0.8567438,"width":0.045212764,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.33294547,"top":0.8579409,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AMOUNT","depth":13,"bounds":{"left":0.42785904,"top":0.27813247,"width":0.019448139,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1000.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.30766162,"width":0.030086435,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4325.26 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.34197924,"width":0.030086435,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10.22 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.37629688,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"460.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.41061452,"width":0.027094414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14.27 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.44493216,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"29.54 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.4792498,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0.09 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.51356745,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"47.63 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.54788506,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8.44 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.58220273,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17.93 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.61652035,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.49 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.650838,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.51 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.68515563,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"67.81 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.71947324,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"9.04 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.7537909,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"15.46 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.7881085,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.02 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.8224262,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"200.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.8567438,"width":0.027094414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"TAGS","depth":13,"bounds":{"left":0.47855717,"top":0.27813247,"width":0.011469414,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Salary","depth":13,"bounds":{"left":0.48055187,"top":0.34277734,"width":0.011968086,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.44573024,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.48004788,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.5143655,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.54868317,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.5830008,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.61731845,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"bounds":{"left":0.48055187,"top":0.68595374,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"bounds":{"left":0.48055187,"top":0.72027135,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.3048683,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.3084597,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.30407023,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.3084597,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.30407023,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.33918595,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.34277734,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.33838788,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.34277734,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.33838788,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.3735036,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.37709498,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.37270552,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.37709498,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.37270552,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.40782124,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.4114126,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.40702313,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.4114126,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.40702313,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.44213888,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.44573024,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.44134077,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.44573024,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.44134077,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.4764565,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.48004788,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.47565842,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.48004788,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.47565842,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.51077414,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.5143655,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.509976,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.5143655,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.509976,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.5450918,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.54868317,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.5442937,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.54868317,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.5442937,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.5794094,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.5830008,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.5786113,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.5830008,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.5786113,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.61372703,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.61731845,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.612929,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.61731845,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.612929,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.6480447,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.65163606,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.6472466,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.65163606,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.6472466,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.6823623,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.68595374,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.6815643,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.68595374,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.6815643,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.71668,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.72027135,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.7158819,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.72027135,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.7158819,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.7509976,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.75458896,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.7501995,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.75458896,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.7501995,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.7853152,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.78890663,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.78451717,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.78890663,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.78451717,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.8196329,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.82322425,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.8188348,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.82322425,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.8188348,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.8539505,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.8575419,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.85315245,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.8575419,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.85315245,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-7757773811144613165
|
5044045952359475102
|
idle
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
DNS / Nameservers | Hostinger
DNS / Nameservers | Hostinger
Nginx Proxy Manager
Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
Payments Logger
Payments Logger
Inbox - [EMAIL] - Gmail
Inbox - [EMAIL] - Gmail
(25) Quora
(25) Quora
Location Logger
Location Logger
Finance Hub
Finance Hub
Finance Hub
Finance Hub
Close tab
Select: payments - db - Adminer
Select: payments - db - Adminer
Електронно банкиране ДСК Директ от Банка ДСК
Електронно банкиране ДСК Директ от Банка ДСК
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
VIVACOM
VIVACOM
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
VIVACOM
VIVACOM
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Claude Code | Claude Platform
Claude Code | Claude Platform
Claude
Claude
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Finance Hub
Finance Hub
18
transaction
s
Payments
Payments
Upload CSV
Upload CSV
Refresh
Display settings
Sign out
Filters
Filters
Search...
dd
/
mm
/
yyyy
Calendar
dd
/
mm
/
yyyy
Calendar
DATE
RECIPIENT
AMOUNT
TAGS
22 Apr 2026
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
1000.00 EUR
Send
Send
Skip
Skip
Delete
30 Apr 2026
ВЕДА ПЕЙРОЛ ООД
Raw data
4325.26 EUR
Salary
Send
Send
Skip
Skip
Delete
30 Apr 2026
—
Raw data
10.22 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ЧЦДГ МИЛА
Raw data
460.00 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
14.27 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
29.54 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
0.09 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
47.63 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
8.44 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
17.93 EUR
Bills
Send
Send
Skip
Skip
Delete
06 May 2026, 13:16
POL BALICE Lagardere Travel R KR3
Raw data
5.49 EUR
Send
Send
Skip
Skip
Delete
07 May 2026, 09:02
BGR SOFIA CBA EKO MARKET
Raw data
5.51 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026, 19:32
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
67.81 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
9.04 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
15.46 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
5.02 EUR
Send
Send
Skip
Skip
Delete
08 May 2026, 10:00
DSK ATM, SOFIA, BG
Raw data
200.00 EUR
Send
Send
Skip
Skip
Delete
DATE
22 Apr 2026
30 Apr 2026
30 Apr 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
06 May 2026, 13:16
07 May 2026, 09:02
08 May 2026, 19:32
08 May 2026
08 May 2026
08 May 2026
08 May 2026, 10:00
RECIPIENT
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
ВЕДА ПЕЙРОЛ ООД
Raw data
—
Raw data
ЧЦДГ МИЛА
Raw data
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
POL BALICE Lagardere Travel R KR3
Raw data
BGR SOFIA CBA EKO MARKET
Raw data
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
—
Raw data
—
Raw data
—
Raw data
DSK ATM, SOFIA, BG
Raw data
AMOUNT
1000.00 EUR
4325.26 EUR
10.22 EUR
460.00 EUR
14.27 EUR
29.54 EUR
0.09 EUR
47.63 EUR
8.44 EUR
17.93 EUR
5.49 EUR
5.51 EUR
67.81 EUR
9.04 EUR
15.46 EUR
5.02 EUR
200.00 EUR
TAGS
Salary
Bills
Bills
Bills
Bills
Bills
Bills
Groceries
Groceries
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete...
|
12793
|
NULL
|
NULL
|
NULL
|
|
12798
|
563
|
20
|
2026-05-09T09:31:33.175574+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-09/1778 /Users/lukas/.screenpipe/data/data/2026-05-09/1778319093175_m1.jpg...
|
Firefox
|
Finance Hub — Personal
|
True
|
finance-hub.lakylak.xyz/outpost.goauthentik.io/sig finance-hub.lakylak.xyz/outpost.goauthentik.io/sign_out...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
DNS / Nameservers | Hostinger
DNS / Nameservers | Hostinger
Nginx Proxy Manager
Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
Payments Logger
Payments Logger
Inbox - [EMAIL] - Gmail
Inbox - [EMAIL] - Gmail
(25) Quora
(25) Quora
Location Logger
Location Logger
Finance Hub
Finance Hub
Finance Hub
Finance Hub
Close tab
Select: payments - db - Adminer
Select: payments - db - Adminer
Електронно банкиране ДСК Директ от Банка ДСК
Електронно банкиране ДСК Директ от Банка ДСК
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
VIVACOM
VIVACOM
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
VIVACOM
VIVACOM
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Claude Code | Claude Platform
Claude Code | Claude Platform
Claude
Claude
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Finance Hub
Finance Hub
18
transaction
s
Payments
Payments
Upload CSV
Upload CSV
Refresh
Display settings
Sign out
Filters
Filters
Search...
dd
/
mm
/
yyyy
Calendar
dd
/
mm
/
yyyy
Calendar
DATE
RECIPIENT
AMOUNT
TAGS
22 Apr 2026
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
1000.00 EUR
Send
Send
Skip
Skip
Delete
30 Apr 2026
ВЕДА ПЕЙРОЛ ООД
Raw data
4325.26 EUR
Salary
Send
Send
Skip
Skip
Delete
30 Apr 2026
—
Raw data
10.22 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ЧЦДГ МИЛА
Raw data
460.00 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
14.27 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
29.54 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
0.09 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
47.63 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
8.44 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
17.93 EUR
Bills
Send
Send
Skip
Skip
Delete
06 May 2026, 13:16
POL BALICE Lagardere Travel R KR3
Raw data
5.49 EUR
Send
Send
Skip
Skip
Delete
07 May 2026, 09:02
BGR SOFIA CBA EKO MARKET
Raw data
5.51 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026, 19:32
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
67.81 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
9.04 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
15.46 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
5.02 EUR
Send
Send
Skip
Skip
Delete
08 May 2026, 10:00
DSK ATM, SOFIA, BG
Raw data
200.00 EUR
Send
Send
Skip
Skip
Delete
DATE
22 Apr 2026
30 Apr 2026
30 Apr 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
06 May 2026, 13:16
07 May 2026, 09:02
08 May 2026, 19:32
08 May 2026
08 May 2026
08 May 2026
08 May 2026, 10:00
RECIPIENT
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
ВЕДА ПЕЙРОЛ ООД
Raw data
—
Raw data
ЧЦДГ МИЛА
Raw data
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
POL BALICE Lagardere Travel R KR3
Raw data
BGR SOFIA CBA EKO MARKET
Raw data
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
—
Raw data
—
Raw data
—
Raw data
DSK ATM, SOFIA, BG
Raw data
AMOUNT
1000.00 EUR
4325.26 EUR
10.22 EUR
460.00 EUR
14.27 EUR
29.54 EUR
0.09 EUR
47.63 EUR
8.44 EUR
17.93 EUR
5.49 EUR
5.51 EUR
67.81 EUR
9.04 EUR
15.46 EUR
5.02 EUR
200.00 EUR
TAGS
Salary
Bills
Bills
Bills
Bills
Bills
Bills
Groceries
Groceries
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DNS / Nameservers | Hostinger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DNS / Nameservers | Hostinger","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Nginx Proxy Manager","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Nginx Proxy Manager","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AFFiNE - All In One KnowledgeOS","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE - All In One KnowledgeOS","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All docs · AFFiNE","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Payments Logger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Payments Logger","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox - kovaliklukas@gmail.com - Gmail","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox - kovaliklukas@gmail.com - Gmail","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"(25) Quora","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"(25) Quora","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Location Logger","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Location Logger","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Finance Hub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Finance Hub","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Select: payments - db - Adminer","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Select: payments - db - Adminer","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Електронно банкиране ДСК Директ от Банка ДСК","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Електронно банкиране ДСК Директ от Банка ДСК","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"VIVACOM","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"VIVACOM","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Смартфони с Unlimited план до 120 € отстъпка | Vivacom","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Смартфони с Unlimited план до 120 € отстъпка | Vivacom","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"VIVACOM","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"VIVACOM","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude Code | Claude Platform","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Claude Code | Claude Platform","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Claude","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Finance Hub","depth":8,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Finance Hub","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"transaction","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"s","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Payments","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Payments","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Upload CSV","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Upload CSV","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Refresh","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Display settings","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Sign out","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Filters","depth":8,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Filters","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search...","depth":9,"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"dd","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mm","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"yyyy","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"dd","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mm","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"yyyy","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DATE","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RECIPIENT","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AMOUNT","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"TAGS","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"МАРТИНА СВЕТОСЛАВОВА КОВАЛИК","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1000.00 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ВЕДА ПЕЙРОЛ ООД","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4325.26 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Salary","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10.22 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЧЦДГ МИЛА","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"460.00 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"14.27 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"29.54 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0.09 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"47.63 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8.44 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"17.93 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"06 May 2026, 13:16","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"POL BALICE Lagardere Travel R KR3","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.49 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"07 May 2026, 09:02","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BGR SOFIA CBA EKO MARKET","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.51 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026, 19:32","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"67.81 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"9.04 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"15.46 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.02 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026, 10:00","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DSK ATM, SOFIA, BG","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"200.00 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DATE","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"06 May 2026, 13:16","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"07 May 2026, 09:02","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026, 19:32","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026, 10:00","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RECIPIENT","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"МАРТИНА СВЕТОСЛАВОВА КОВАЛИК","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ВЕДА ПЕЙРОЛ ООД","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЧЦДГ МИЛА","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"POL BALICE Lagardere Travel R KR3","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BGR SOFIA CBA EKO MARKET","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DSK ATM, SOFIA, BG","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AMOUNT","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1000.00 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4325.26 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10.22 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"460.00 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14.27 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"29.54 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0.09 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"47.63 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8.44 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17.93 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.49 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.51 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"67.81 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"9.04 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"15.46 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.02 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"200.00 EUR","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"TAGS","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Salary","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-7757773811144613165
|
5044045952359475102
|
idle
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
DNS / Nameservers | Hostinger
DNS / Nameservers | Hostinger
Nginx Proxy Manager
Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
Payments Logger
Payments Logger
Inbox - [EMAIL] - Gmail
Inbox - [EMAIL] - Gmail
(25) Quora
(25) Quora
Location Logger
Location Logger
Finance Hub
Finance Hub
Finance Hub
Finance Hub
Close tab
Select: payments - db - Adminer
Select: payments - db - Adminer
Електронно банкиране ДСК Директ от Банка ДСК
Електронно банкиране ДСК Директ от Банка ДСК
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
VIVACOM
VIVACOM
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
VIVACOM
VIVACOM
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Claude Code | Claude Platform
Claude Code | Claude Platform
Claude
Claude
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Finance Hub
Finance Hub
18
transaction
s
Payments
Payments
Upload CSV
Upload CSV
Refresh
Display settings
Sign out
Filters
Filters
Search...
dd
/
mm
/
yyyy
Calendar
dd
/
mm
/
yyyy
Calendar
DATE
RECIPIENT
AMOUNT
TAGS
22 Apr 2026
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
1000.00 EUR
Send
Send
Skip
Skip
Delete
30 Apr 2026
ВЕДА ПЕЙРОЛ ООД
Raw data
4325.26 EUR
Salary
Send
Send
Skip
Skip
Delete
30 Apr 2026
—
Raw data
10.22 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ЧЦДГ МИЛА
Raw data
460.00 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
14.27 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
29.54 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
0.09 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
47.63 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
8.44 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
17.93 EUR
Bills
Send
Send
Skip
Skip
Delete
06 May 2026, 13:16
POL BALICE Lagardere Travel R KR3
Raw data
5.49 EUR
Send
Send
Skip
Skip
Delete
07 May 2026, 09:02
BGR SOFIA CBA EKO MARKET
Raw data
5.51 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026, 19:32
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
67.81 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
9.04 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
15.46 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
5.02 EUR
Send
Send
Skip
Skip
Delete
08 May 2026, 10:00
DSK ATM, SOFIA, BG
Raw data
200.00 EUR
Send
Send
Skip
Skip
Delete
DATE
22 Apr 2026
30 Apr 2026
30 Apr 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
06 May 2026, 13:16
07 May 2026, 09:02
08 May 2026, 19:32
08 May 2026
08 May 2026
08 May 2026
08 May 2026, 10:00
RECIPIENT
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
ВЕДА ПЕЙРОЛ ООД
Raw data
—
Raw data
ЧЦДГ МИЛА
Raw data
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
POL BALICE Lagardere Travel R KR3
Raw data
BGR SOFIA CBA EKO MARKET
Raw data
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
—
Raw data
—
Raw data
—
Raw data
DSK ATM, SOFIA, BG
Raw data
AMOUNT
1000.00 EUR
4325.26 EUR
10.22 EUR
460.00 EUR
14.27 EUR
29.54 EUR
0.09 EUR
47.63 EUR
8.44 EUR
17.93 EUR
5.49 EUR
5.51 EUR
67.81 EUR
9.04 EUR
15.46 EUR
5.02 EUR
200.00 EUR
TAGS
Salary
Bills
Bills
Bills
Bills
Bills
Bills
Groceries
Groceries
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete...
|
12796
|
NULL
|
NULL
|
NULL
|
|
12799
|
564
|
18
|
2026-05-09T09:31:38.311571+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-09/1778 /Users/lukas/.screenpipe/data/data/2026-05-09/1778319098311_m2.jpg...
|
Firefox
|
Finance Hub — Personal
|
True
|
finance-hub.lakylak.xyz/outpost.goauthentik.io/sig finance-hub.lakylak.xyz/outpost.goauthentik.io/sign_out...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
DNS / Nameservers | Hostinger
DNS / Nameservers | Hostinger
Nginx Proxy Manager
Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
Payments Logger
Payments Logger
Inbox - [EMAIL] - Gmail
Inbox - [EMAIL] - Gmail
(25) Quora
(25) Quora
Location Logger
Location Logger
Finance Hub
Finance Hub
Finance Hub
Finance Hub
Close tab
Select: payments - db - Adminer
Select: payments - db - Adminer
Електронно банкиране ДСК Директ от Банка ДСК
Електронно банкиране ДСК Директ от Банка ДСК
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
VIVACOM
VIVACOM
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
VIVACOM
VIVACOM
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Claude Code | Claude Platform
Claude Code | Claude Platform
Claude
Claude
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Finance Hub
Finance Hub
18
transaction
s
Payments
Payments
Upload CSV
Upload CSV
Refresh
Display settings
Sign out
Filters
Filters
Search...
dd
/
mm
/
yyyy
Calendar
dd
/
mm
/
yyyy
Calendar
DATE
RECIPIENT
AMOUNT
TAGS
22 Apr 2026
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
1000.00 EUR
Send
Send
Skip
Skip
Delete
30 Apr 2026
ВЕДА ПЕЙРОЛ ООД
Raw data
4325.26 EUR
Salary
Send
Send
Skip
Skip
Delete
30 Apr 2026
—
Raw data
10.22 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ЧЦДГ МИЛА
Raw data
460.00 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
14.27 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
29.54 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
0.09 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
47.63 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
8.44 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
17.93 EUR
Bills
Send
Send
Skip
Skip
Delete
06 May 2026, 13:16
POL BALICE Lagardere Travel R KR3
Raw data
5.49 EUR
Send
Send
Skip
Skip
Delete
07 May 2026, 09:02
BGR SOFIA CBA EKO MARKET
Raw data
5.51 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026, 19:32
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
67.81 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
9.04 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
15.46 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
5.02 EUR
Send
Send
Skip
Skip
Delete
08 May 2026, 10:00
DSK ATM, SOFIA, BG
Raw data
200.00 EUR
Send
Send
Skip
Skip
Delete
DATE
22 Apr 2026
30 Apr 2026
30 Apr 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
06 May 2026, 13:16
07 May 2026, 09:02
08 May 2026, 19:32
08 May 2026
08 May 2026
08 May 2026
08 May 2026, 10:00
RECIPIENT
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
ВЕДА ПЕЙРОЛ ООД
Raw data
—
Raw data
ЧЦДГ МИЛА
Raw data
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
POL BALICE Lagardere Travel R KR3
Raw data
BGR SOFIA CBA EKO MARKET
Raw data
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
—
Raw data
—
Raw data
—
Raw data
DSK ATM, SOFIA, BG
Raw data
AMOUNT
1000.00 EUR
4325.26 EUR
10.22 EUR
460.00 EUR
14.27 EUR
29.54 EUR
0.09 EUR
47.63 EUR
8.44 EUR
17.93 EUR
5.49 EUR
5.51 EUR
67.81 EUR
9.04 EUR
15.46 EUR
5.02 EUR
200.00 EUR
TAGS
Salary
Bills
Bills
Bills
Bills
Bills
Bills
Groceries
Groceries
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.080784574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DNS / Nameservers | Hostinger","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DNS / Nameservers | Hostinger","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.053856384,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Nginx Proxy Manager","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Nginx Proxy Manager","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.0,"top":0.15003991,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"bounds":{"left":0.0,"top":0.18276137,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.040724736,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"bounds":{"left":0.0,"top":0.21548285,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"bounds":{"left":0.013297873,"top":0.22665602,"width":0.03756649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":4,"bounds":{"left":0.0,"top":0.2482043,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub","depth":5,"bounds":{"left":0.013297873,"top":0.25937748,"width":0.11469415,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"bounds":{"left":0.0,"top":0.28092578,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"bounds":{"left":0.013297873,"top":0.29209897,"width":0.036901597,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AFFiNE - All In One KnowledgeOS","depth":4,"bounds":{"left":0.0,"top":0.31364724,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AFFiNE - All In One KnowledgeOS","depth":5,"bounds":{"left":0.013297873,"top":0.32482043,"width":0.05851064,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"bounds":{"left":0.0,"top":0.3463687,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All docs · AFFiNE","depth":5,"bounds":{"left":0.013297873,"top":0.3575419,"width":0.029587766,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Payments Logger","depth":4,"bounds":{"left":0.0,"top":0.3790902,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Payments Logger","depth":5,"bounds":{"left":0.013297873,"top":0.39026338,"width":0.030086435,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Inbox - kovaliklukas@gmail.com - Gmail","depth":4,"bounds":{"left":0.0,"top":0.41181165,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Inbox - kovaliklukas@gmail.com - Gmail","depth":5,"bounds":{"left":0.013297873,"top":0.42298484,"width":0.06898271,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"(25) Quora","depth":4,"bounds":{"left":0.0,"top":0.4445331,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"(25) Quora","depth":5,"bounds":{"left":0.013297873,"top":0.4557063,"width":0.018949468,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Location Logger","depth":4,"bounds":{"left":0.0,"top":0.4772546,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Location Logger","depth":5,"bounds":{"left":0.013297873,"top":0.4884278,"width":0.028091755,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"bounds":{"left":0.0,"top":0.509976,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Finance Hub","depth":5,"bounds":{"left":0.013297873,"top":0.5211492,"width":0.021609042,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Finance Hub","depth":4,"bounds":{"left":0.0,"top":0.54269755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Finance Hub","depth":5,"bounds":{"left":0.013297873,"top":0.55387074,"width":0.021609042,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.10139628,"top":0.54988027,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Select: payments - db - Adminer","depth":4,"bounds":{"left":0.0,"top":0.575419,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Select: payments - db - Adminer","depth":5,"bounds":{"left":0.013297873,"top":0.5865922,"width":0.05651596,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Електронно банкиране ДСК Директ от Банка ДСК","depth":4,"bounds":{"left":0.0,"top":0.60814047,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Електронно банкиране ДСК Директ от Банка ДСК","depth":5,"bounds":{"left":0.013297873,"top":0.61931366,"width":0.09059176,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE","depth":4,"bounds":{"left":0.0,"top":0.6408619,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE","depth":5,"bounds":{"left":0.013297873,"top":0.6520351,"width":0.113696806,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"VIVACOM","depth":4,"bounds":{"left":0.0,"top":0.6735834,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"VIVACOM","depth":5,"bounds":{"left":0.013297873,"top":0.6847566,"width":0.016788565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Смартфони с Unlimited план до 120 € отстъпка | Vivacom","depth":4,"bounds":{"left":0.0,"top":0.70630485,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Смартфони с Unlimited план до 120 € отстъпка | Vivacom","depth":5,"bounds":{"left":0.013297873,"top":0.71747804,"width":0.10239362,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"VIVACOM","depth":4,"bounds":{"left":0.0,"top":0.7390263,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"VIVACOM","depth":5,"bounds":{"left":0.013297873,"top":0.7501995,"width":0.016788565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom","depth":4,"bounds":{"left":0.0,"top":0.7717478,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom","depth":5,"bounds":{"left":0.013297873,"top":0.782921,"width":0.098902926,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude Code | Claude Platform","depth":4,"bounds":{"left":0.0,"top":0.8044693,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Claude Code | Claude Platform","depth":5,"bounds":{"left":0.013297873,"top":0.8156425,"width":0.053357713,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude","depth":4,"bounds":{"left":0.0,"top":0.83719075,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Claude","depth":5,"bounds":{"left":0.013297873,"top":0.84836394,"width":0.012134309,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.87150836,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Finance Hub","depth":8,"bounds":{"left":0.22539894,"top":0.0622506,"width":0.032081116,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Finance Hub","depth":9,"bounds":{"left":0.22539894,"top":0.06264964,"width":0.032081116,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18","depth":9,"bounds":{"left":0.22539894,"top":0.07861133,"width":0.0043218085,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"transaction","depth":9,"bounds":{"left":0.22972074,"top":0.07861133,"width":0.02244016,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"s","depth":9,"bounds":{"left":0.2521609,"top":0.07861133,"width":0.0019946808,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Payments","depth":8,"bounds":{"left":0.37982047,"top":0.06384677,"width":0.036070477,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Payments","depth":10,"bounds":{"left":0.39045876,"top":0.0698324,"width":0.02144282,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Upload CSV","depth":8,"bounds":{"left":0.41655585,"top":0.06384677,"width":0.04105718,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Upload CSV","depth":10,"bounds":{"left":0.42719415,"top":0.0698324,"width":0.02642952,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Refresh","depth":8,"bounds":{"left":0.57978725,"top":0.06384677,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Display settings","depth":8,"bounds":{"left":0.5924202,"top":0.06384677,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Sign out","depth":8,"bounds":{"left":0.6050532,"top":0.06384677,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Filters","depth":8,"bounds":{"left":0.21708776,"top":0.13168396,"width":0.3929521,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Filters","depth":10,"bounds":{"left":0.22506648,"top":0.13288109,"width":0.013630319,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search...","depth":9,"bounds":{"left":0.21708776,"top":0.16759777,"width":0.075465426,"height":0.030327214},"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"dd","depth":11,"bounds":{"left":0.23038563,"top":0.21588188,"width":0.0056515955,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"bounds":{"left":0.23703457,"top":0.21588188,"width":0.0013297872,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mm","depth":11,"bounds":{"left":0.2393617,"top":0.21588188,"width":0.007978723,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"bounds":{"left":0.24833776,"top":0.21588188,"width":0.0013297872,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"yyyy","depth":11,"bounds":{"left":0.2506649,"top":0.21588188,"width":0.009973404,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":10,"bounds":{"left":0.40043217,"top":0.21667998,"width":0.006150266,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"dd","depth":11,"bounds":{"left":0.42885637,"top":0.21588188,"width":0.0056515955,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"bounds":{"left":0.43550533,"top":0.21588188,"width":0.0013297872,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"mm","depth":11,"bounds":{"left":0.43783244,"top":0.21588188,"width":0.007978723,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":10,"bounds":{"left":0.44680852,"top":0.21588188,"width":0.0013297872,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"yyyy","depth":11,"bounds":{"left":0.44913563,"top":0.21588188,"width":0.009973404,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":10,"bounds":{"left":0.59890294,"top":0.21667998,"width":0.006150266,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DATE","depth":13,"bounds":{"left":0.21708776,"top":0.27813247,"width":0.011136968,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RECIPIENT","depth":13,"bounds":{"left":0.2864029,"top":0.27813247,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AMOUNT","depth":13,"bounds":{"left":0.42785904,"top":0.27813247,"width":0.019448139,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"TAGS","depth":13,"bounds":{"left":0.47855717,"top":0.27813247,"width":0.011469414,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.30766162,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"МАРТИНА СВЕТОСЛАВОВА КОВАЛИК","depth":14,"bounds":{"left":0.2864029,"top":0.30766162,"width":0.0859375,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.37367022,"top":0.30885875,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1000.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.30766162,"width":0.030086435,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.3048683,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.3084597,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.30407023,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.3084597,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.30407023,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.34197924,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ВЕДА ПЕЙРОЛ ООД","depth":14,"bounds":{"left":0.2864029,"top":0.34197924,"width":0.044714097,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.3324468,"top":0.34317636,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4325.26 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.34197924,"width":0.030086435,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Salary","depth":13,"bounds":{"left":0.48055187,"top":0.34277734,"width":0.011968086,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.33918595,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.34277734,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.33838788,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.34277734,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.33838788,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.37629688,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.37629688,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.377494,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10.22 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.37629688,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.3735036,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.37709498,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.37270552,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.37709498,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.37270552,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.41061452,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЧЦДГ МИЛА","depth":14,"bounds":{"left":0.2864029,"top":0.41061452,"width":0.028091755,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.31582448,"top":0.41181165,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"460.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.41061452,"width":0.027094414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.40782124,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.4114126,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.40702313,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.4114126,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.40702313,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.44493216,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА","depth":14,"bounds":{"left":0.2864029,"top":0.44493216,"width":0.1171875,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.40492022,"top":0.4461293,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"14.27 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.44493216,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.44573024,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.44213888,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.44573024,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.44134077,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.44573024,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.44134077,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.4792498,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"bounds":{"left":0.2864029,"top":0.4792498,"width":0.07164229,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.359375,"top":0.48044693,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"29.54 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.4792498,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.48004788,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.4764565,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.48004788,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.47565842,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.48004788,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.47565842,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.51356745,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"bounds":{"left":0.2864029,"top":0.51356745,"width":0.12084442,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.4085771,"top":0.51476455,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0.09 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.51356745,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.5143655,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.51077414,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.5143655,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.509976,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.5143655,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.509976,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.54788506,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"bounds":{"left":0.2864029,"top":0.54788506,"width":0.12084442,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.4085771,"top":0.5490822,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"47.63 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.54788506,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.54868317,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.5450918,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.54868317,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.5442937,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.54868317,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.5442937,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.58220273,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"bounds":{"left":0.2864029,"top":0.58220273,"width":0.07164229,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.359375,"top":0.58339983,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"8.44 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.58220273,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.5830008,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.5794094,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.5830008,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.5786113,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.5830008,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.5786113,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.61652035,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ","depth":14,"bounds":{"left":0.2864029,"top":0.61652035,"width":0.08277926,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.37051198,"top":0.6177175,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"17.93 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.61652035,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.61731845,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.61372703,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.61731845,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.612929,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.61731845,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.612929,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"06 May 2026, 13:16","depth":13,"bounds":{"left":0.21708776,"top":0.650838,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"POL BALICE Lagardere Travel R KR3","depth":14,"bounds":{"left":0.2864029,"top":0.650838,"width":0.07795878,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.36569148,"top":0.6520351,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.49 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.650838,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.6480447,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.65163606,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.6472466,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.65163606,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.6472466,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"07 May 2026, 09:02","depth":13,"bounds":{"left":0.21708776,"top":0.68515563,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BGR SOFIA CBA EKO MARKET","depth":14,"bounds":{"left":0.2864029,"top":0.68515563,"width":0.065159574,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.35289228,"top":0.6863527,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.51 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.68515563,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"bounds":{"left":0.48055187,"top":0.68595374,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.6823623,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.68595374,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.6815643,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.68595374,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.6815643,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026, 19:32","depth":13,"bounds":{"left":0.21708776,"top":0.71947324,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR","depth":14,"bounds":{"left":0.2864029,"top":0.71947324,"width":0.10322473,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.39095744,"top":0.7206704,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"67.81 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.71947324,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"bounds":{"left":0.48055187,"top":0.72027135,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.71668,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.72027135,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.7158819,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.72027135,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.7158819,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.7537909,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.7537909,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.754988,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"9.04 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.7537909,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.7509976,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.75458896,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.7501995,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.75458896,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.7501995,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.7881085,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.7881085,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.7893057,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"15.46 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.7881085,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.7853152,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.78890663,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.78451717,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.78890663,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.78451717,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.8224262,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.8224262,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.8236233,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5.02 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.8224262,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.8196329,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.82322425,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.8188348,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.82322425,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.8188348,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08 May 2026, 10:00","depth":13,"bounds":{"left":0.21708776,"top":0.8567438,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DSK ATM, SOFIA, BG","depth":14,"bounds":{"left":0.2864029,"top":0.8567438,"width":0.045212764,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.33294547,"top":0.8579409,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"200.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.8567438,"width":0.027094414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.8539505,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.8575419,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.85315245,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.8575419,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.85315245,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DATE","depth":13,"bounds":{"left":0.21708776,"top":0.27813247,"width":0.011136968,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.30766162,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.34197924,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30 Apr 2026","depth":13,"bounds":{"left":0.21708776,"top":0.37629688,"width":0.027426861,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.41061452,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.44493216,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.4792498,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.51356745,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.54788506,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.58220273,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"04 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.61652035,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"06 May 2026, 13:16","depth":13,"bounds":{"left":0.21708776,"top":0.650838,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"07 May 2026, 09:02","depth":13,"bounds":{"left":0.21708776,"top":0.68515563,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026, 19:32","depth":13,"bounds":{"left":0.21708776,"top":0.71947324,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.7537909,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.7881085,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026","depth":13,"bounds":{"left":0.21708776,"top":0.8224262,"width":0.028756648,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"08 May 2026, 10:00","depth":13,"bounds":{"left":0.21708776,"top":0.8567438,"width":0.044215426,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RECIPIENT","depth":13,"bounds":{"left":0.2864029,"top":0.27813247,"width":0.023105053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"МАРТИНА СВЕТОСЛАВОВА КОВАЛИК","depth":14,"bounds":{"left":0.2864029,"top":0.30766162,"width":0.0859375,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.37367022,"top":0.30885875,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ВЕДА ПЕЙРОЛ ООД","depth":14,"bounds":{"left":0.2864029,"top":0.34197924,"width":0.044714097,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.3324468,"top":0.34317636,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.37629688,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.377494,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЧЦДГ МИЛА","depth":14,"bounds":{"left":0.2864029,"top":0.41061452,"width":0.028091755,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.31582448,"top":0.41181165,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА","depth":14,"bounds":{"left":0.2864029,"top":0.44493216,"width":0.1171875,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.40492022,"top":0.4461293,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"bounds":{"left":0.2864029,"top":0.4792498,"width":0.07164229,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.359375,"top":0.48044693,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"bounds":{"left":0.2864029,"top":0.51356745,"width":0.12084442,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.4085771,"top":0.51476455,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ","depth":14,"bounds":{"left":0.2864029,"top":0.54788506,"width":0.12084442,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.4085771,"top":0.5490822,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"С0ФИЙСКА ВОДА ДСК ДИРЕКТ","depth":14,"bounds":{"left":0.2864029,"top":0.58220273,"width":0.07164229,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.359375,"top":0.58339983,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ","depth":14,"bounds":{"left":0.2864029,"top":0.61652035,"width":0.08277926,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.37051198,"top":0.6177175,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"POL BALICE Lagardere Travel R KR3","depth":14,"bounds":{"left":0.2864029,"top":0.650838,"width":0.07795878,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.36569148,"top":0.6520351,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BGR SOFIA CBA EKO MARKET","depth":14,"bounds":{"left":0.2864029,"top":0.68515563,"width":0.065159574,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.35289228,"top":0.6863527,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR","depth":14,"bounds":{"left":0.2864029,"top":0.71947324,"width":0.10322473,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.39095744,"top":0.7206704,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.7537909,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.754988,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.7881085,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.7893057,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"—","depth":14,"bounds":{"left":0.2864029,"top":0.8224262,"width":0.0039893617,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.2917221,"top":0.8236233,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DSK ATM, SOFIA, BG","depth":14,"bounds":{"left":0.2864029,"top":0.8567438,"width":0.045212764,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Raw data","depth":13,"bounds":{"left":0.33294547,"top":0.8579409,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AMOUNT","depth":13,"bounds":{"left":0.42785904,"top":0.27813247,"width":0.019448139,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1000.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.30766162,"width":0.030086435,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4325.26 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.34197924,"width":0.030086435,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10.22 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.37629688,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"460.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.41061452,"width":0.027094414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14.27 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.44493216,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"29.54 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.4792498,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0.09 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.51356745,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"47.63 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.54788506,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8.44 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.58220273,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17.93 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.61652035,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.49 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.650838,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.51 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.68515563,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"67.81 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.71947324,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"9.04 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.7537909,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"15.46 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.7881085,"width":0.024102394,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5.02 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.8224262,"width":0.021110373,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"200.00 EUR","depth":13,"bounds":{"left":0.42785904,"top":0.8567438,"width":0.027094414,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"TAGS","depth":13,"bounds":{"left":0.47855717,"top":0.27813247,"width":0.011469414,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Salary","depth":13,"bounds":{"left":0.48055187,"top":0.34277734,"width":0.011968086,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.44573024,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.48004788,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.5143655,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.54868317,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.5830008,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bills","depth":13,"bounds":{"left":0.48055187,"top":0.61731845,"width":0.007978723,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"bounds":{"left":0.48055187,"top":0.68595374,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Groceries","depth":13,"bounds":{"left":0.48055187,"top":0.72027135,"width":0.01861702,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.3048683,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.3084597,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.30407023,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.3084597,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.30407023,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.33918595,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.34277734,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.33838788,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.34277734,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.33838788,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.3735036,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.37709498,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.37270552,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.37709498,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.37270552,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.40782124,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.4114126,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.40702313,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.4114126,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.40702313,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.44213888,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.44573024,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.44134077,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.44573024,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.44134077,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.4764565,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.48004788,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.47565842,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.48004788,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.47565842,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.51077414,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.5143655,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.509976,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.5143655,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.509976,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.5450918,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.54868317,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.5442937,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.54868317,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.5442937,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.5794094,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.5830008,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.5786113,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.5830008,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.5786113,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.61372703,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.61731845,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.612929,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.61731845,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.612929,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.6480447,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.65163606,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.6472466,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.65163606,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.6472466,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.6823623,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.68595374,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.6815643,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.68595374,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.6815643,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.71668,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.72027135,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.7158819,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.72027135,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.7158819,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.7509976,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.75458896,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.7501995,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.75458896,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.7501995,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.7853152,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.78890663,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.78451717,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.78890663,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.78451717,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.8196329,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.82322425,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.8188348,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.82322425,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.8188348,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send","depth":13,"bounds":{"left":0.5369016,"top":0.8539505,"width":0.021775266,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Send","depth":14,"bounds":{"left":0.5455452,"top":0.8575419,"width":0.009807181,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Skip","depth":13,"bounds":{"left":0.5600067,"top":0.85315245,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip","depth":14,"bounds":{"left":0.5689827,"top":0.8575419,"width":0.00831117,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Delete","depth":13,"bounds":{"left":0.5822806,"top":0.85315245,"width":0.008643617,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-7757773811144613165
|
5044045952359475102
|
idle
|
accessibility
|
NULL
|
Pull requests · screenpipe/screenpipe · GitHub
Pul Pull requests · screenpipe/screenpipe · GitHub
Pull requests · screenpipe/screenpipe · GitHub
DNS / Nameservers | Hostinger
DNS / Nameservers | Hostinger
Nginx Proxy Manager
Nginx Proxy Manager
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
screenpipe/.claude/skills at main · screenpipe/screenpipe · GitHub
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
AFFiNE - All In One KnowledgeOS
AFFiNE - All In One KnowledgeOS
All docs · AFFiNE
All docs · AFFiNE
Payments Logger
Payments Logger
Inbox - [EMAIL] - Gmail
Inbox - [EMAIL] - Gmail
(25) Quora
(25) Quora
Location Logger
Location Logger
Finance Hub
Finance Hub
Finance Hub
Finance Hub
Close tab
Select: payments - db - Adminer
Select: payments - db - Adminer
Електронно банкиране ДСК Директ от Банка ДСК
Електронно банкиране ДСК Директ от Банка ДСК
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
Stop Losing Notes: Pick A Cross-Device App That Syncs | AFFiNE
VIVACOM
VIVACOM
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
Смартфони с Unlimited план до 120 € отстъпка | Vivacom
VIVACOM
VIVACOM
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Смартфон SAMSUNG GALAXY A57 5G 256GB | Vivacom
Claude Code | Claude Platform
Claude Code | Claude Platform
Claude
Claude
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Finance Hub
Finance Hub
18
transaction
s
Payments
Payments
Upload CSV
Upload CSV
Refresh
Display settings
Sign out
Filters
Filters
Search...
dd
/
mm
/
yyyy
Calendar
dd
/
mm
/
yyyy
Calendar
DATE
RECIPIENT
AMOUNT
TAGS
22 Apr 2026
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
1000.00 EUR
Send
Send
Skip
Skip
Delete
30 Apr 2026
ВЕДА ПЕЙРОЛ ООД
Raw data
4325.26 EUR
Salary
Send
Send
Skip
Skip
Delete
30 Apr 2026
—
Raw data
10.22 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ЧЦДГ МИЛА
Raw data
460.00 EUR
Send
Send
Skip
Skip
Delete
04 May 2026
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
14.27 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
29.54 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
0.09 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
47.63 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
8.44 EUR
Bills
Send
Send
Skip
Skip
Delete
04 May 2026
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
17.93 EUR
Bills
Send
Send
Skip
Skip
Delete
06 May 2026, 13:16
POL BALICE Lagardere Travel R KR3
Raw data
5.49 EUR
Send
Send
Skip
Skip
Delete
07 May 2026, 09:02
BGR SOFIA CBA EKO MARKET
Raw data
5.51 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026, 19:32
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
67.81 EUR
Groceries
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
9.04 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
15.46 EUR
Send
Send
Skip
Skip
Delete
08 May 2026
—
Raw data
5.02 EUR
Send
Send
Skip
Skip
Delete
08 May 2026, 10:00
DSK ATM, SOFIA, BG
Raw data
200.00 EUR
Send
Send
Skip
Skip
Delete
DATE
22 Apr 2026
30 Apr 2026
30 Apr 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
04 May 2026
06 May 2026, 13:16
07 May 2026, 09:02
08 May 2026, 19:32
08 May 2026
08 May 2026
08 May 2026
08 May 2026, 10:00
RECIPIENT
МАРТИНА СВЕТОСЛАВОВА КОВАЛИК
Raw data
ВЕДА ПЕЙРОЛ ООД
Raw data
—
Raw data
ЧЦДГ МИЛА
Raw data
ОВЕГАЗ МРЕЖИ АД-ЕЛЕКТРОННИ КАНАЛИ И КАСА
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
ЕЛЕКТPОХОЛДПPОДАЖБИ/ДСКДИРЕКТ/ЕЛ.ЕНЕРГИЯ
Raw data
С0ФИЙСКА ВОДА ДСК ДИРЕКТ
Raw data
КОМУНАЛНИ РАЗХОДИ ЕЛ. КАНАЛИ
Raw data
POL BALICE Lagardere Travel R KR3
Raw data
BGR SOFIA CBA EKO MARKET
Raw data
BGR SOFIYA LIDL BALGARIYA EOOD UL TODOR
Raw data
—
Raw data
—
Raw data
—
Raw data
DSK ATM, SOFIA, BG
Raw data
AMOUNT
1000.00 EUR
4325.26 EUR
10.22 EUR
460.00 EUR
14.27 EUR
29.54 EUR
0.09 EUR
47.63 EUR
8.44 EUR
17.93 EUR
5.49 EUR
5.51 EUR
67.81 EUR
9.04 EUR
15.46 EUR
5.02 EUR
200.00 EUR
TAGS
Salary
Bills
Bills
Bills
Bills
Bills
Bills
Groceries
Groceries
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete
Send
Send
Skip
Skip
Delete...
|
12793
|
NULL
|
NULL
|
NULL
|
|
5492
|
201
|
0
|
2026-05-07T15:38:39.604964+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778168319604_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
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
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
6
1
6
Previous Highlighted Error
Next Highlighted Error
# [PASSWORD_DOTS] HS [PASSWORD_DOTS]
select * from teams where id = 2; # 2
select * from features; # 2
select * from team_features where team_id = 2; # 2
select * from crm_configurations where id = 2; # 2
select * from users where team_id = 2; #
select * from playbooks where team_id = 2; # event 38
select * from playbook_categories where playbook_id = 38; #
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;
[URL_WITH_CREDENTIALS] CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
if (! $this->rateLimiter->canMakeRequest($this->config)) {
$retryAfter = $this->rateLimiter->requestAvailableIn($this->config);
$this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
]);
throw new RateLimitException(
'Hubspot rate limit reached for configuration ' . $this->config->getId(),
$retryAfter,
);
}
$this->rateLimiter->incrementRequestCount($this->config);
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
public function isHubspotRateLimit(Throwable $e): bool
{
return method_exists($e, 'getCode') && (int) $e->getCode() === 429;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info("parseRetryAfter");
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$current = $e;
while ($current !== null) {
if (method_exists($current, 'getResponse')) {
$response = $current->getResponse();
if ($response !== null) {
$headers = $response->getHeaders();
}
}
$current = $current->getPrevious();
}
$this->log->info('[Hubspot] DEBUG Getting headers', [
'headers' => $headers ?? [],
]);
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
$response = $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
$response = $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
$max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // "110"
$remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // "109"
$interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"
$body = json_decode((string) $response->getBody(), true);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));
return $response;
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options...
|
[{"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":"Execute","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"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},{"role":"AXStaticText","text":"6","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"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":"# **************************** HS **************************************\n\nselect * from teams where id = 2; # 2\nselect * from features; # 2\nselect * from team_features where team_id = 2; # 2\nselect * from crm_configurations where id = 2; # 2\nselect * from users where team_id = 2; #\nselect * from playbooks where team_id = 2; # event 38\nselect * from playbook_categories where playbook_id = 38; #\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;\nhttps://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624\n https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0\n\nSELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;\n# 609126 softphone tr. 11241\n\nSELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;\n# 608874 conference tr. 11226 crmId: 103422236596\n\nselect * from ai_prompts where transcription_id IN (11241, 11226);\nselect * from activity_summary_logs where activity_id = 608874;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nselect * from crm_field_data where activity_id = 1223;\n\nselect * from crm_layouts where crm_configuration_id = 2;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);\nselect * from crm_fields where crm_configuration_id = 11 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);\n\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u\n on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 2 and sa.provider = 'hubspot';\n\nselect * from social_accounts where id = 1499;\n\nselect * from opportunities where team_id = 2\nand crm_provider_id IN ('51317301383');\n\nselect * from contacts where id = 85;\n\nselect * from opportunities where team_id = 2 order by id desc;\nselect * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112\nselect * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112\nselect * from opportunity_contacts where opportunity_id = 5117;\nselect * from crm_field_data where object_id = 1365;\nSELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);\n\nselect * from features;\nselect * from team_features where team_id IN (1);\nselect * from team_features where feature_id IN (36);\n\nSHOW CREATE TABLE opportunity_contacts;\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';\n\n# $slug = 'HUBSPOT_WEBHOOK_SYNC';\n# $team = Jiminny\\Models\\Team::find(2);\n# $feature = Feature::query()->where('slug', $slug)->first();\n# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);\n\n# hubspot_webhook_metrics\n\nselect * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365\nSELECT * FROM opportunity_contacts WHERE opportunity_id = '414';\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';\nselect * from contacts where id in (414, 464);\n\nselect * from activities where crm_configuration_id = 2;\n\nselect settings from crm_configurations where id = 11;\n\nselect * from teams; # 1, 2\nselect * from users;\nselect * from crm_configurations where id = 39;\nselect * from team_features where team_id = 2;\nselect * from features;\n# SELECT * FROM opportunities WHERE crm_configuration_id = 2\n# order by id desc;\n# and crm_provider_id = '49908861993';\n\n\nselect * from activity_providers where id IN (443, 202, 203, 227);\n\nselect * from activity_imports where id = 795889;\n\nselect c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id\nwhere c.provider = 'hubspot';\n\nselect * from crm_configurations crm JOIN teams t on crm.team_id = t.id\nwhere provider = 'hubspot';\nSELECT * FROM teams WHERE id = 31;\nSELECT * FROM users WHERE id = 257;\nSELECT * FROM opportunities WHERE team_id = 2;\n\nselect * from opportunity_contacts where opportunity_id = 5124;\nselect * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)\n\nselect * from activities where crm_configuration_id = 13;\n\nSELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141\n\n\nselect id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;\nSELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 order by id desc;\nselect * from opportunity_contacts where contact_id = 6223;\nSELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;\n\nselect * from crm_profiles where crm_configuration_id = 2;\n\nselect * from activities where account_id = 46;","depth":4,"on_screen":true,"value":"# **************************** HS **************************************\n\nselect * from teams where id = 2; # 2\nselect * from features; # 2\nselect * from team_features where team_id = 2; # 2\nselect * from crm_configurations where id = 2; # 2\nselect * from users where team_id = 2; #\nselect * from playbooks where team_id = 2; # event 38\nselect * from playbook_categories where playbook_id = 38; #\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;\nhttps://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624\n https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0\n\nSELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;\n# 609126 softphone tr. 11241\n\nSELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;\n# 608874 conference tr. 11226 crmId: 103422236596\n\nselect * from ai_prompts where transcription_id IN (11241, 11226);\nselect * from activity_summary_logs where activity_id = 608874;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nselect * from crm_field_data where activity_id = 1223;\n\nselect * from crm_layouts where crm_configuration_id = 2;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);\nselect * from crm_fields where crm_configuration_id = 11 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);\n\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u\n on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 2 and sa.provider = 'hubspot';\n\nselect * from social_accounts where id = 1499;\n\nselect * from opportunities where team_id = 2\nand crm_provider_id IN ('51317301383');\n\nselect * from contacts where id = 85;\n\nselect * from opportunities where team_id = 2 order by id desc;\nselect * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112\nselect * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112\nselect * from opportunity_contacts where opportunity_id = 5117;\nselect * from crm_field_data where object_id = 1365;\nSELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);\n\nselect * from features;\nselect * from team_features where team_id IN (1);\nselect * from team_features where feature_id IN (36);\n\nSHOW CREATE TABLE opportunity_contacts;\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';\n\n# $slug = 'HUBSPOT_WEBHOOK_SYNC';\n# $team = Jiminny\\Models\\Team::find(2);\n# $feature = Feature::query()->where('slug', $slug)->first();\n# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);\n\n# hubspot_webhook_metrics\n\nselect * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365\nSELECT * FROM opportunity_contacts WHERE opportunity_id = '414';\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';\nselect * from contacts where id in (414, 464);\n\nselect * from activities where crm_configuration_id = 2;\n\nselect settings from crm_configurations where id = 11;\n\nselect * from teams; # 1, 2\nselect * from users;\nselect * from crm_configurations where id = 39;\nselect * from team_features where team_id = 2;\nselect * from features;\n# SELECT * FROM opportunities WHERE crm_configuration_id = 2\n# order by id desc;\n# and crm_provider_id = '49908861993';\n\n\nselect * from activity_providers where id IN (443, 202, 203, 227);\n\nselect * from activity_imports where id = 795889;\n\nselect c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id\nwhere c.provider = 'hubspot';\n\nselect * from crm_configurations crm JOIN teams t on crm.team_id = t.id\nwhere provider = 'hubspot';\nSELECT * FROM teams WHERE id = 31;\nSELECT * FROM users WHERE id = 257;\nSELECT * FROM opportunities WHERE team_id = 2;\n\nselect * from opportunity_contacts where opportunity_id = 5124;\nselect * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)\n\nselect * from activities where crm_configuration_id = 13;\n\nSELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141\n\n\nselect id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;\nSELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 order by id desc;\nselect * from opportunity_contacts where contact_id = 6223;\nSELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;\n\nselect * from crm_profiles where crm_configuration_id = 2;\n\nselect * from activities where account_id = 46;","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":"2","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.016666668,"height":0.02111111},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"70","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.020833334,"height":0.02111111},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.016666668,"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\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Component\\Utility\\Service\\ProviderRateLimiter;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n private ProviderRateLimiter $rateLimiter;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n ProviderRateLimiter $rateLimiter,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n $this->rateLimiter = $rateLimiter;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Single entry point for every HubSpot API call. Enforces the per-portal\n * rate limit configured in the rate_limits table (morphed to the current\n * Configuration) and reacts to a real 429 from HubSpot by translating it\n * into a RateLimitException carrying Retry-After.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n if (! $this->rateLimiter->canMakeRequest($this->config)) {\n $retryAfter = $this->rateLimiter->requestAvailableIn($this->config);\n\n $this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n ]);\n\n throw new RateLimitException(\n 'Hubspot rate limit reached for configuration ' . $this->config->getId(),\n $retryAfter,\n );\n }\n\n $this->rateLimiter->incrementRequestCount($this->config);\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n return method_exists($e, 'getCode') && (int) $e->getCode() === 429;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info(\"parseRetryAfter\");\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $current = $e;\n while ($current !== null) {\n if (method_exists($current, 'getResponse')) {\n $response = $current->getResponse();\n if ($response !== null) {\n $headers = $response->getHeaders();\n }\n }\n $current = $current->getPrevious();\n }\n\n $this->log->info('[Hubspot] DEBUG Getting headers', [\n 'headers' => $headers ?? [],\n ]);\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n\n $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n $body = json_decode((string) $response->getBody(), true);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Component\\Utility\\Service\\ProviderRateLimiter;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n private ProviderRateLimiter $rateLimiter;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n ProviderRateLimiter $rateLimiter,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n $this->rateLimiter = $rateLimiter;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Single entry point for every HubSpot API call. Enforces the per-portal\n * rate limit configured in the rate_limits table (morphed to the current\n * Configuration) and reacts to a real 429 from HubSpot by translating it\n * into a RateLimitException carrying Retry-After.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n if (! $this->rateLimiter->canMakeRequest($this->config)) {\n $retryAfter = $this->rateLimiter->requestAvailableIn($this->config);\n\n $this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n ]);\n\n throw new RateLimitException(\n 'Hubspot rate limit reached for configuration ' . $this->config->getId(),\n $retryAfter,\n );\n }\n\n $this->rateLimiter->incrementRequestCount($this->config);\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n return method_exists($e, 'getCode') && (int) $e->getCode() === 429;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info(\"parseRetryAfter\");\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $current = $e;\n while ($current !== null) {\n if (method_exists($current, 'getResponse')) {\n $response = $current->getResponse();\n if ($response !== null) {\n $headers = $response->getHeaders();\n }\n }\n $current = $current->getPrevious();\n }\n\n $this->log->info('[Hubspot] DEBUG Getting headers', [\n 'headers' => $headers ?? [],\n ]);\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n\n $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n $body = json_decode((string) $response->getBody(), true);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","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}]...
|
-7757371020216563101
|
6684458809013180517
|
click
|
accessibility
|
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
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
6
1
6
Previous Highlighted Error
Next Highlighted Error
# [PASSWORD_DOTS] HS [PASSWORD_DOTS]
select * from teams where id = 2; # 2
select * from features; # 2
select * from team_features where team_id = 2; # 2
select * from crm_configurations where id = 2; # 2
select * from users where team_id = 2; #
select * from playbooks where team_id = 2; # event 38
select * from playbook_categories where playbook_id = 38; #
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;
[URL_WITH_CREDENTIALS] CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
if (! $this->rateLimiter->canMakeRequest($this->config)) {
$retryAfter = $this->rateLimiter->requestAvailableIn($this->config);
$this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
]);
throw new RateLimitException(
'Hubspot rate limit reached for configuration ' . $this->config->getId(),
$retryAfter,
);
}
$this->rateLimiter->incrementRequestCount($this->config);
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
public function isHubspotRateLimit(Throwable $e): bool
{
return method_exists($e, 'getCode') && (int) $e->getCode() === 429;
}
public function parseRetryAfter(Throwable $e): int
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info("parseRetryAfter");
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$current = $e;
while ($current !== null) {
if (method_exists($current, 'getResponse')) {
$response = $current->getResponse();
if ($response !== null) {
$headers = $response->getHeaders();
}
}
$current = $current->getPrevious();
}
$this->log->info('[Hubspot] DEBUG Getting headers', [
'headers' => $headers ?? [],
]);
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
$response = $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
$response = $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
$max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // "110"
$remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // "109"
$interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"
$body = json_decode((string) $response->getBody(), true);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));
return $response;
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options...
|
5490
|
NULL
|
NULL
|
NULL
|
|
23737
|
1000
|
37
|
2026-05-12T08:24:29.501946+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778574269501_m1.jpg...
|
PhpStorm
|
faVsco.js – console [PROD]
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
=+SlackFileEditViewGoHistoryWindowHelp→ws.planhat. =+SlackFileEditViewGoHistoryWindowHelp→ws.planhat.com/jiminny/home/data-explorer/usageJiminnySearch JiminnyContent Explorer7 Metric |Datasetautomated-reports-traEnd UserData ExplorerQ autactivities.automated-reports-CalendarNotificationsNameOverviewRaw DataTral*• Morev EndUser 1Metricsautomated-reports-track-Sections +CS Day-to-day2 Getting started GuideJust CS Data* Daily Operations05 May06 May07• Weekly prep© Renewals and Upsell:= € Risk and Churn An...Implementation -Impl ProjectsTrial Opps (Under Rev...Stoyan's clientsCommentsAdd a commentHomeDMsActivityFilesLater..•More(aolSupport Daily • in 3 h 36 m100% C73• Tue 12 May 11:24:29→Describe what you are looking forJiminny ...eam+ More unreadsChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi..0 Direct messagesPetko KashinskiR. Steliyan Georgiev%. Galya Dimitrovae. Aneliya Angelova&. Stefka Stoyanova€. Vasil Vasilev. Nikolay IvanovSteliyan Georgiev6 0• Messagest Add canvasO Files+AutomaTodayPreview in wawnStatusBacklogPriority= MediumAssigneeUnassignedAs of today at 10:46 AM RefreshOpen in JiraSummariseпроблем беше че няма pdf_url сега ще серазровя за конкретен репорти идеята е на РНР да не го пробваме през час ноГаля попита за регенериранепредполагам че е нещо случайно най-вероятносамо един репортза бъдеще може да в самия пропхет има липроверка дали има всичко преди да върнеresponse, или пак от РНР да се провери предипращане и да се пусне отновоSteliyan Georgiev 10:51 AMможе да направя профет ако няма pdf_url, даврьща грешка за пхп?Lukas Kovalik 10:51 AMпо-скоро да се регенерираMessage Steliyan Georgiev+...
|
NULL
|
-7756069315450923966
|
NULL
|
click
|
ocr
|
NULL
|
=+SlackFileEditViewGoHistoryWindowHelp→ws.planhat. =+SlackFileEditViewGoHistoryWindowHelp→ws.planhat.com/jiminny/home/data-explorer/usageJiminnySearch JiminnyContent Explorer7 Metric |Datasetautomated-reports-traEnd UserData ExplorerQ autactivities.automated-reports-CalendarNotificationsNameOverviewRaw DataTral*• Morev EndUser 1Metricsautomated-reports-track-Sections +CS Day-to-day2 Getting started GuideJust CS Data* Daily Operations05 May06 May07• Weekly prep© Renewals and Upsell:= € Risk and Churn An...Implementation -Impl ProjectsTrial Opps (Under Rev...Stoyan's clientsCommentsAdd a commentHomeDMsActivityFilesLater..•More(aolSupport Daily • in 3 h 36 m100% C73• Tue 12 May 11:24:29→Describe what you are looking forJiminny ...eam+ More unreadsChannels# ai-chapter# alerts# backend# bugs# confusion-clinic# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi..0 Direct messagesPetko KashinskiR. Steliyan Georgiev%. Galya Dimitrovae. Aneliya Angelova&. Stefka Stoyanova€. Vasil Vasilev. Nikolay IvanovSteliyan Georgiev6 0• Messagest Add canvasO Files+AutomaTodayPreview in wawnStatusBacklogPriority= MediumAssigneeUnassignedAs of today at 10:46 AM RefreshOpen in JiraSummariseпроблем беше че няма pdf_url сега ще серазровя за конкретен репорти идеята е на РНР да не го пробваме през час ноГаля попита за регенериранепредполагам че е нещо случайно най-вероятносамо един репортза бъдеще може да в самия пропхет има липроверка дали има всичко преди да върнеresponse, или пак от РНР да се провери предипращане и да се пусне отновоSteliyan Georgiev 10:51 AMможе да направя профет ако няма pdf_url, даврьща грешка за пхп?Lukas Kovalik 10:51 AMпо-скоро да се регенерираMessage Steliyan Georgiev+...
|
23734
|
NULL
|
NULL
|
NULL
|
|
24934
|
1046
|
0
|
2026-05-12T10:18:06.330181+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778581086330_m1.jpg...
|
Firefox
|
Pipelines - jiminny/app — Work
|
True
|
app.circleci.com/pipelines/github/jiminny/app
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Unnamed Group
TypeError: League\Flysystem\Filesyst Unnamed Group
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
CloudWatch | us-east-2
CloudWatch | us-east-2
Unnamed Group
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
Data Explorer
Data Explorer
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
Jiminny
Jiminny
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
Platform Team - Backlog - Jira
Platform Team - Backlog - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Go to home page
Auto theme
Open notifications
Open support menu
Open user menu
org avatar Current organization: jiminny
Home
Home
Pipelines
Pipelines
Projects
Projects
Deploys
Deploys
Insights
Insights
Runners
Runners
Org
Org
Plan
Plan
Chunk sidecars
Chunk sidecars
PREVIEW
Chunk
Chunk
Smarter Testing is now in beta
Smarter Testing is now in beta
Get faster feedback on your tests while maintaining full confidence
Dismiss
Get Started
Get Started
Dashboard All Pipelines
All Pipelines
Project Outline app
app
app
app
Overview
Overview
Settings
Settings
Deploys
Deploys
Lightning Manage triggers
Manage triggers
Trigger Pipeline
Pipelines All pipelines my-pipelines-filter
All pipelines
app Project Filter. Selected "app"
app
All branches Branch Filter. Selected "All branches"
All branches
Start Time Cutoff date Arrow Drop Down
Cutoff date
All statuses Arrow Drop Down
All
statuses
Filter Display options
Display options
Pipeline
Status
Workflow
Checkout source
Trigger event
Start
Duration
Actions
app
58246
58246
RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.
Status Running Running
Running
14m 35s
remain
Info Outline
build_accept_deploy
build_accept_deploy
JY-20606-desktop-app-recall
JY-20606-desktop-app-recall
Open commit on version control site
08ff215
JY-20606: desktop app ui
Push
Commit pushed
Copy timestamp to clipboard
10m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
885153
1m 40s
1m 40s
SUCCESS job build-frontend
build-frontend
885156
1m 58s
1m 58s
SUCCESS job test-frontend
test-frontend
885158
2m 18s
2m 18s
SUCCESS job build-backend
build-backend
885154
1m 10s
1m 10s
SUCCESS job phpstan
phpstan
885163
1m 9s
1m 9s
SUCCESS job prepare_deploy_revision_subenv
prepare_deploy_revision_subenv
885159
53s
53s
SUCCESS job build_docker_backend_code_subenv
build_docker_backend_code_subenv
885160
1m 54s
1m 54s
SUCCESS job build_docker_worker_code_subenv
build_docker_worker_code_subenv
885165
1m 53s
1m 53s
SUCCESS job build_docker_worker_video_code_subenv
build_docker_worker_video_code_subenv
885161
1m 50s
1m 50s
SUCCESS job db_migrations_subenv
db_migrations_subenv
885167...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Unnamed Group","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | us-east-2","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | us-east-2","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Unnamed Group","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pull requests · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20773] User Pilot not receiving events on report generated - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20773] User Pilot not receiving events on report generated - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20776] Automated report - sentry - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20776] Automated report - sentry - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Data Explorer","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Data Explorer","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20776] Automated report - sentry - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20776] Automated report - sentry - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6793] Les Mills activity types not pulling in - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6793] Les Mills activity types not pulling in - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Team - Backlog - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Team - Backlog - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20773] User Pilot not receiving events on report generated - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20773] User Pilot not receiving events on report generated - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Go to home page","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Auto theme","depth":9,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open notifications","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Open support menu","depth":9,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Open user menu","depth":9,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"org avatar Current organization: jiminny","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Home","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Home","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pipelines","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Projects","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Projects","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Deploys","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Deploys","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Runners","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Runners","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Org","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Org","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Plan","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Plan","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chunk sidecars","depth":11,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Chunk sidecars","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PREVIEW","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chunk","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Chunk","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Smarter Testing is now in beta","depth":9,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Smarter Testing is now in beta","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Get faster feedback on your tests while maintaining full confidence","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Get Started","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Get Started","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Dashboard All Pipelines","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All Pipelines","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Project Outline app","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"app","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Overview","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Overview","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Deploys","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Deploys","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Lightning Manage triggers","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Manage triggers","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Trigger Pipeline","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Pipelines All pipelines my-pipelines-filter","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"All pipelines","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"app Project Filter. Selected \"app\"","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"All branches Branch Filter. Selected \"All branches\"","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"All branches","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Start Time Cutoff date Arrow Drop Down","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Cutoff date","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"All statuses Arrow Drop Down","depth":13,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"All","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"statuses","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Filter Display options","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Display options","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pipeline","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Status","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Workflow","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Checkout source","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Trigger event","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Start","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Duration","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Actions","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"58246","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"58246","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Status Running Running","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Running","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14m 35s","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"remain","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Info Outline","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"build_accept_deploy","depth":12,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_accept_deploy","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20606-desktop-app-recall","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20606-desktop-app-recall","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Open commit on version control site","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"08ff215","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20606: desktop app ui","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Push","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Commit pushed","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp to clipboard","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10m ago","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy timestamp duration to clipboard","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from start","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Rerun workflow from failed","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Cancel workflow","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Fix workflow","depth":12,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"More Actions","depth":12,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Jobs","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job checkout-code","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"checkout-code","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885153","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 40s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 40s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-frontend","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-frontend","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885156","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 58s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 58s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job test-frontend","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test-frontend","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885158","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2m 18s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2m 18s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build-backend","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build-backend","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885154","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 10s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 10s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job phpstan","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"phpstan","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885163","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 9s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 9s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job prepare_deploy_revision_subenv","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"prepare_deploy_revision_subenv","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885159","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"53s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"53s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_backend_code_subenv","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_docker_backend_code_subenv","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885160","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 54s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 54s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_worker_code_subenv","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_docker_worker_code_subenv","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885165","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 53s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 53s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job build_docker_worker_video_code_subenv","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"build_docker_worker_video_code_subenv","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885161","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1m 50s","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1m 50s","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SUCCESS job db_migrations_subenv","depth":14,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"db_migrations_subenv","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"885167","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-7754587464185606220
|
-3024369305522311008
|
idle
|
accessibility
|
NULL
|
Unnamed Group
TypeError: League\Flysystem\Filesyst Unnamed Group
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
CloudWatch | us-east-2
CloudWatch | us-east-2
Unnamed Group
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
Data Explorer
Data Explorer
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
Jiminny
Jiminny
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
Platform Team - Backlog - Jira
Platform Team - Backlog - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Go to home page
Auto theme
Open notifications
Open support menu
Open user menu
org avatar Current organization: jiminny
Home
Home
Pipelines
Pipelines
Projects
Projects
Deploys
Deploys
Insights
Insights
Runners
Runners
Org
Org
Plan
Plan
Chunk sidecars
Chunk sidecars
PREVIEW
Chunk
Chunk
Smarter Testing is now in beta
Smarter Testing is now in beta
Get faster feedback on your tests while maintaining full confidence
Dismiss
Get Started
Get Started
Dashboard All Pipelines
All Pipelines
Project Outline app
app
app
app
Overview
Overview
Settings
Settings
Deploys
Deploys
Lightning Manage triggers
Manage triggers
Trigger Pipeline
Pipelines All pipelines my-pipelines-filter
All pipelines
app Project Filter. Selected "app"
app
All branches Branch Filter. Selected "All branches"
All branches
Start Time Cutoff date Arrow Drop Down
Cutoff date
All statuses Arrow Drop Down
All
statuses
Filter Display options
Display options
Pipeline
Status
Workflow
Checkout source
Trigger event
Start
Duration
Actions
app
58246
58246
RUNNING workflow build_accept_deploy. Collapse the workflow jobs list.
Status Running Running
Running
14m 35s
remain
Info Outline
build_accept_deploy
build_accept_deploy
JY-20606-desktop-app-recall
JY-20606-desktop-app-recall
Open commit on version control site
08ff215
JY-20606: desktop app ui
Push
Commit pushed
Copy timestamp to clipboard
10m ago
Copy timestamp duration to clipboard
Rerun workflow from start
Rerun workflow from failed
Cancel workflow
Fix workflow
More Actions
Jobs
SUCCESS job checkout-code
checkout-code
885153
1m 40s
1m 40s
SUCCESS job build-frontend
build-frontend
885156
1m 58s
1m 58s
SUCCESS job test-frontend
test-frontend
885158
2m 18s
2m 18s
SUCCESS job build-backend
build-backend
885154
1m 10s
1m 10s
SUCCESS job phpstan
phpstan
885163
1m 9s
1m 9s
SUCCESS job prepare_deploy_revision_subenv
prepare_deploy_revision_subenv
885159
53s
53s
SUCCESS job build_docker_backend_code_subenv
build_docker_backend_code_subenv
885160
1m 54s
1m 54s
SUCCESS job build_docker_worker_code_subenv
build_docker_worker_code_subenv
885165
1m 53s
1m 53s
SUCCESS job build_docker_worker_video_code_subenv
build_docker_worker_video_code_subenv
885161
1m 50s
1m 50s
SUCCESS job db_migrations_subenv
db_migrations_subenv
885167...
|
24932
|
NULL
|
NULL
|
NULL
|
|
21606
|
944
|
8
|
2026-05-11T18:08:04.052272+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778522884052_m1.jpg...
|
Firefox
|
SQLite Web: db.sqlite — Personal
|
True
|
sqlite.screenpipe.lakylak.xyz/audio_chunks/content sqlite.screenpipe.lakylak.xyz/audio_chunks/content/...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
New Tab
New Tab
Screenpipe — Archive
Screenpipe — New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
All docs · AFFiNE
All docs · AFFiNE
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
sqlite-web 0.7.2
sqlite-web 0.7.2
db.sqlite
db.sqlite
audio_chunks
2575 rows, showing page 1
Query
Query
table name...
_sqlx_migrations
_sqlx_migrations
audio_chunks
audio_chunks
audio_tags
audio_tags
audio_transcriptions
audio_transcriptions
audio_transcriptions_fts (v)
audio_transcriptions_fts
(v)
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
elements
elements
elements_fts (v)
elements_fts
(v)
elements_fts_config
elements_fts_config
elements_fts_data
elements_fts_data
elements_fts_idx
elements_fts_idx
frames
frames
frames_fts (v)
frames_fts
(v)
frames_fts_config
frames_fts_config
frames_fts_data
frames_fts_data
frames_fts_idx
frames_fts_idx
meetings
meetings
memories
memories
memories_fts (v)
memories_fts
(v)
memories_fts_config
memories_fts_config
memories_fts_data
memories_fts_data
memories_fts_idx
memories_fts_idx
ocr_text
ocr_text
pipe_executions
pipe_executions
pipe_scheduler_state
pipe_scheduler_state
secrets
secrets
speaker_embeddings
speaker_embeddings
speakers
speakers
sqlite_sequence
sqlite_sequence
sqlite_stat1
sqlite_stat1
sqlite_stat4
sqlite_stat4
tags
tags
ui_events
ui_events
ui_events_fts (v)
ui_events_fts
(v)
ui_events_fts_config
ui_events_fts_config
ui_events_fts_data
ui_events_fts_data
ui_events_fts_idx
ui_events_fts_idx
video_chunks
video_chunks
vision_tags
vision_tags
Toggle helper tables
Toggle helper tables
Structure
Structure
Content
Content
Query
Query
Export
Export
id
id
file_path
file_path
timestamp
timestamp
sync_id
sync_id
machine_id
machine_id
synced_at
synced_at
evicted_at
evicted_at
1
/Users/lukas/.screenpipe/data/MacBook Pro Micropho
...
...
2026-05-06T17:27:47+00:00
NULL
NULL
NULL
NULL
2
/Users/lukas/.screenpipe/data/System Audio (output
...
...
2026-05-06T17:27:47+00:00
NULL
NULL
NULL
NULL
3
/Users/lukas/.screenpipe/data/MacBook Pro Micropho
...
...
2026-05-06T17:28:19+00:00
NULL
NULL
NULL
NULL
4
/Users/lukas/.screenpipe/data/System Audio (output
...
...
2026-05-06T17:28:20+00:00
NULL
NULL
NULL
NULL
5
/Users/lukas/.screenpipe/data/MacBook Pro Micropho
...
...
2026-05-06T17:28:49+00:00
NULL
NULL
NULL
NULL
6
/Users/lukas/.screenpipe/data/System Audio (output
...
...
2026-05-06T17:28:50+00:00
NULL
NULL
NULL
NULL
7
/Users/lukas/.screenpipe/data/MacBook Pro Micropho
...
...
2026-05-06T17:29:19+00:00
NULL
NULL
NULL
NULL
8
/Users/lukas/.screenpipe/data/System Audio (output
...
...
2026-05-06T17:29:20+00:00
NULL
NULL
NULL
NULL
9
/Users/lukas/.screenpipe/data/MacBook Pro Micropho
...
...
2026-05-06T17:29:49+00:00
NULL
NULL
NULL
NULL
10
/Users/lukas/.screenpipe/data/System Audio (output
...
...
2026-05-06T17:29:49+00:00
NULL
NULL
NULL
NULL
11...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All docs · AFFiNE","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.48576388,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.5086806,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.53194445,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.5552083,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.5784722,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"sqlite-web 0.7.2","depth":7,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sqlite-web 0.7.2","depth":8,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"db.sqlite","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"db.sqlite","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"audio_chunks","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2575 rows, showing page 1","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Query","depth":8,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Query","depth":9,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"table name...","depth":7,"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"_sqlx_migrations","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"_sqlx_migrations","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_chunks","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_chunks","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_tags","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_tags","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_transcriptions","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_transcriptions","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_transcriptions_fts (v)","depth":9,"on_screen":true,"help_text":"audio_transcriptions_fts","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_transcriptions_fts","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(v)","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_transcriptions_...","depth":9,"on_screen":true,"help_text":"audio_transcriptions_fts_config","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_transcriptions_...","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_transcriptions_...","depth":9,"on_screen":true,"help_text":"audio_transcriptions_fts_data","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_transcriptions_...","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"audio_transcriptions_...","depth":9,"on_screen":true,"help_text":"audio_transcriptions_fts_idx","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"audio_transcriptions_...","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"elements","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"elements","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"elements_fts (v)","depth":9,"on_screen":true,"help_text":"elements_fts","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"elements_fts","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(v)","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"elements_fts_config","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"elements_fts_config","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"elements_fts_data","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"elements_fts_data","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"elements_fts_idx","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"elements_fts_idx","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"frames","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"frames","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"frames_fts (v)","depth":9,"on_screen":true,"help_text":"frames_fts","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"frames_fts","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(v)","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"frames_fts_config","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"frames_fts_config","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"frames_fts_data","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"frames_fts_data","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"frames_fts_idx","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"frames_fts_idx","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"meetings","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"meetings","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"memories","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"memories","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"memories_fts (v)","depth":9,"on_screen":true,"help_text":"memories_fts","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"memories_fts","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(v)","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"memories_fts_config","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"memories_fts_config","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"memories_fts_data","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"memories_fts_data","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"memories_fts_idx","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"memories_fts_idx","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ocr_text","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ocr_text","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"pipe_executions","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"pipe_executions","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"pipe_scheduler_state","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"pipe_scheduler_state","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"secrets","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"secrets","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"speaker_embeddings","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"speaker_embeddings","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"speakers","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"speakers","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"sqlite_sequence","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sqlite_sequence","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"sqlite_stat1","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sqlite_stat1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"sqlite_stat4","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sqlite_stat4","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"tags","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"tags","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ui_events","depth":9,"bounds":{"left":0.6340278,"top":0.0,"width":0.12951389,"height":0.031666666},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ui_events","depth":10,"bounds":{"left":0.6409722,"top":0.0,"width":0.04548611,"height":0.020555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ui_events_fts (v)","depth":9,"bounds":{"left":0.6340278,"top":0.0,"width":0.12951389,"height":0.031666666},"on_screen":true,"help_text":"ui_events_fts","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ui_events_fts","depth":10,"bounds":{"left":0.6409722,"top":0.0,"width":0.06666667,"height":0.020555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(v)","depth":11,"bounds":{"left":0.70763886,"top":0.0,"width":0.010069445,"height":0.015},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ui_events_fts_config","depth":9,"bounds":{"left":0.6340278,"top":0.0,"width":0.12951389,"height":0.031666666},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ui_events_fts_config","depth":10,"bounds":{"left":0.6409722,"top":0.0,"width":0.098958336,"height":0.020555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ui_events_fts_data","depth":9,"bounds":{"left":0.6340278,"top":0.0,"width":0.12951389,"height":0.031666666},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ui_events_fts_data","depth":10,"bounds":{"left":0.6409722,"top":0.00055555557,"width":0.090277776,"height":0.020555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ui_events_fts_idx","depth":9,"bounds":{"left":0.6340278,"top":0.026666667,"width":0.12951389,"height":0.031666666},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ui_events_fts_idx","depth":10,"bounds":{"left":0.6409722,"top":0.032222223,"width":0.083333336,"height":0.020555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"video_chunks","depth":9,"bounds":{"left":0.6340278,"top":0.058333334,"width":0.12951389,"height":0.031666666},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"video_chunks","depth":10,"bounds":{"left":0.6409722,"top":0.06388889,"width":0.06527778,"height":0.020555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"vision_tags","depth":9,"bounds":{"left":0.6340278,"top":0.09,"width":0.12951389,"height":0.031666666},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"vision_tags","depth":10,"bounds":{"left":0.6409722,"top":0.09555556,"width":0.054166667,"height":0.020555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Toggle helper tables","depth":8,"bounds":{"left":0.6340278,"top":0.16055556,"width":0.096875,"height":0.020555556},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Toggle helper tables","depth":9,"bounds":{"left":0.6340278,"top":0.16055556,"width":0.096875,"height":0.020555556},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Structure","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Structure","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Content","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Content","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Query","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Query","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Export","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Export","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"id","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"id","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"file_path","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"file_path","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"timestamp","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"timestamp","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"sync_id","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sync_id","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"machine_id","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"machine_id","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"synced_at","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"synced_at","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"evicted_at","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"evicted_at","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/Users/lukas/.screenpipe/data/MacBook Pro Micropho","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-06T17:27:47+00:00","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/Users/lukas/.screenpipe/data/System Audio (output","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-06T17:27:47+00:00","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/Users/lukas/.screenpipe/data/MacBook Pro Micropho","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-06T17:28:19+00:00","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/Users/lukas/.screenpipe/data/System Audio (output","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-06T17:28:20+00:00","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/Users/lukas/.screenpipe/data/MacBook Pro Micropho","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-06T17:28:49+00:00","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"6","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/Users/lukas/.screenpipe/data/System Audio (output","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-06T17:28:50+00:00","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/Users/lukas/.screenpipe/data/MacBook Pro Micropho","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-06T17:29:19+00:00","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/Users/lukas/.screenpipe/data/System Audio (output","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-06T17:29:20+00:00","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"9","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/Users/lukas/.screenpipe/data/MacBook Pro Micropho","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-06T17:29:49+00:00","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/Users/lukas/.screenpipe/data/System Audio (output","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"...","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026-05-06T17:29:49+00:00","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NULL","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-7754097440284473427
|
2865820480048303816
|
idle
|
accessibility
|
NULL
|
New Tab
New Tab
Screenpipe — Archive
Screenpipe — New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
All docs · AFFiNE
All docs · AFFiNE
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
sqlite-web 0.7.2
sqlite-web 0.7.2
db.sqlite
db.sqlite
audio_chunks
2575 rows, showing page 1
Query
Query
table name...
_sqlx_migrations
_sqlx_migrations
audio_chunks
audio_chunks
audio_tags
audio_tags
audio_transcriptions
audio_transcriptions
audio_transcriptions_fts (v)
audio_transcriptions_fts
(v)
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
audio_transcriptions_...
elements
elements
elements_fts (v)
elements_fts
(v)
elements_fts_config
elements_fts_config
elements_fts_data
elements_fts_data
elements_fts_idx
elements_fts_idx
frames
frames
frames_fts (v)
frames_fts
(v)
frames_fts_config
frames_fts_config
frames_fts_data
frames_fts_data
frames_fts_idx
frames_fts_idx
meetings
meetings
memories
memories
memories_fts (v)
memories_fts
(v)
memories_fts_config
memories_fts_config
memories_fts_data
memories_fts_data
memories_fts_idx
memories_fts_idx
ocr_text
ocr_text
pipe_executions
pipe_executions
pipe_scheduler_state
pipe_scheduler_state
secrets
secrets
speaker_embeddings
speaker_embeddings
speakers
speakers
sqlite_sequence
sqlite_sequence
sqlite_stat1
sqlite_stat1
sqlite_stat4
sqlite_stat4
tags
tags
ui_events
ui_events
ui_events_fts (v)
ui_events_fts
(v)
ui_events_fts_config
ui_events_fts_config
ui_events_fts_data
ui_events_fts_data
ui_events_fts_idx
ui_events_fts_idx
video_chunks
video_chunks
vision_tags
vision_tags
Toggle helper tables
Toggle helper tables
Structure
Structure
Content
Content
Query
Query
Export
Export
id
id
file_path
file_path
timestamp
timestamp
sync_id
sync_id
machine_id
machine_id
synced_at
synced_at
evicted_at
evicted_at
1
/Users/lukas/.screenpipe/data/MacBook Pro Micropho
...
...
2026-05-06T17:27:47+00:00
NULL
NULL
NULL
NULL
2
/Users/lukas/.screenpipe/data/System Audio (output
...
...
2026-05-06T17:27:47+00:00
NULL
NULL
NULL
NULL
3
/Users/lukas/.screenpipe/data/MacBook Pro Micropho
...
...
2026-05-06T17:28:19+00:00
NULL
NULL
NULL
NULL
4
/Users/lukas/.screenpipe/data/System Audio (output
...
...
2026-05-06T17:28:20+00:00
NULL
NULL
NULL
NULL
5
/Users/lukas/.screenpipe/data/MacBook Pro Micropho
...
...
2026-05-06T17:28:49+00:00
NULL
NULL
NULL
NULL
6
/Users/lukas/.screenpipe/data/System Audio (output
...
...
2026-05-06T17:28:50+00:00
NULL
NULL
NULL
NULL
7
/Users/lukas/.screenpipe/data/MacBook Pro Micropho
...
...
2026-05-06T17:29:19+00:00
NULL
NULL
NULL
NULL
8
/Users/lukas/.screenpipe/data/System Audio (output
...
...
2026-05-06T17:29:20+00:00
NULL
NULL
NULL
NULL
9
/Users/lukas/.screenpipe/data/MacBook Pro Micropho
...
...
2026-05-06T17:29:49+00:00
NULL
NULL
NULL
NULL
10
/Users/lukas/.screenpipe/data/System Audio (output
...
...
2026-05-06T17:29:49+00:00
NULL
NULL
NULL
NULL
11...
|
21603
|
NULL
|
NULL
|
NULL
|
|
14919
|
NULL
|
0
|
2026-05-11T04:54:54.016064+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778475294016_m1.jpg...
|
iTerm2
|
screenpipe"
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
whisper_backend_init_gpu: found GPU device 0: Meta whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
2026-05-10T23:27:31.985285Z INFO screenpipe_audio::audio_manager::manager: reconciliation: transcribed 50 orphaned chunks
2026-05-10T23:27:41.489329Z ERROR screenpipe_audio::core::stream: an error occurred on the audio stream: device disconnected
2026-05-10T23:27:42.161846Z INFO screenpipe_audio::audio_manager::device_monitor: system default input changed to: MacBook Pro Microphone (input)
2026-05-10T23:27:42.163527Z INFO screenpipe_audio::device::device_manager: starting recording for device: MacBook Pro Microphone (input)
2026-05-10T23:27:42.164408Z INFO screenpipe_audio::audio_manager::device_monitor: switched to new system default input: MacBook Pro Microphone (input)
2026-05-10T23:27:42.164471Z INFO screenpipe_audio::core::run_record_and_transcribe: starting continuous recording for MacBook Pro Microphone (input) (wired / 30s segments)
2026-05-10T23:27:42.164492Z INFO screenpipe_audio::core::run_record_and_transcribe: screen locked, pausing audio recording for MacBook Pro Microphone (input)
2026-05-10T23:27:42.881174Z INFO screenpipe_audio::core::run_record_and_transcribe: stopped recording for soundcore AeroClip (input)
2026-05-10T23:27:43.285854Z INFO screenpipe_audio::transcription::handle_new_transcript: device soundcore AeroClip (input) skipping duplicate transcript (entire content overlaps with previous)
2026-05-10T23:27:58.189174Z INFO screenpipe_audio::audio_manager::device_monitor: system default input changed to: soundcore AeroClip (input)
2026-05-10T23:27:58.190264Z INFO screenpipe_audio::device::device_manager: starting recording for device: soundcore AeroClip (input)
2026-05-10T23:27:58.190299Z INFO screenpipe_audio::audio_manager::device_monitor: switched to new system default input: soundcore AeroClip (input)
2026-05-10T23:27:58.190324Z INFO screenpipe_audio::core::run_record_and_transcribe: starting continuous recording for soundcore AeroClip (input) (bluetooth / 30s segments)
2026-05-10T23:27:58.190332Z INFO screenpipe_audio::core::run_record_and_transcribe: screen locked, pausing audio recording for soundcore AeroClip (input)
2026-05-10T23:27:58.203316Z INFO screenpipe_audio::core::run_record_and_transcribe: stopped recording for MacBook Pro Microphone (input)
2026-05-10T23:28:32.063312Z ERROR screenpipe_audio::core::stream: an error occurred on the audio stream: device disconnected
2026-05-10T23:28:32.531328Z INFO screenpipe_audio::audio_manager::device_monitor: system default input changed to: MacBook Pro Microphone (input)
2026-05-10T23:28:32.531913Z INFO screenpipe_audio::device::device_manager: starting recording for device: MacBook Pro Microphone (input)
2026-05-10T23:28:32.531933Z INFO screenpipe_audio::audio_manager::device_monitor: switched to new system default input: MacBook Pro Microphone (input)
2026-05-10T23:28:32.532003Z INFO screenpipe_audio::core::run_record_and_transcribe: stopped recording for soundcore AeroClip (input)
2026-05-10T23:28:32.708770Z INFO screenpipe_audio::core::run_record_and_transcribe: starting continuous recording for MacBook Pro Microphone (input) (wired / 30s segments)
2026-05-10T23:28:32.708807Z INFO screenpipe_audio::core::run_record_and_transcribe: screen locked, pausing audio recording for MacBook Pro Microphone (input)
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
2026-05-10T23:51:42.401532Z INFO screenpipe_audio::audio_manager::manager: reconciliation: transcribed 50 orphaned chunks
tip: sign in for higher AI quotas + cloud sync:
screenpipe login
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
2026-05-11T02:54:23.501609Z INFO screenpipe_audio::audio_manager::manager: reconciliation: transcribed 50 orphaned chunks
tip: get the screenpipe desktop app for the full experience
https://screenpi.pe
2026-05-11T07:21:22.702849Z INFO screenpipe_audio::audio_manager::device_monitor: system default input changed to: soundcore AeroClip (input)
2026-05-11T07:21:22.703351Z ERROR screenpipe_audio::audio_manager::device_monitor: failed to start new default input soundcore AeroClip (input): device soundcore AeroClip (input) not found (will back off)
2026-05-11T07:21:22.704671Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] no input device running (attempt 1), starting default: soundcore AeroClip (input)
2026-05-11T07:21:22.704693Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] failed to start input device soundcore AeroClip (input) (attempt 1): device soundcore AeroClip (input) not found
2026-05-11T07:21:23.587900Z INFO screenpipe_audio::core::run_record_and_transcribe: stopped recording for MacBook Pro Microphone (input)
2026-05-11T07:21:24.708381Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] no input device running (attempt 2), starting default: soundcore AeroClip (input)
2026-05-11T07:21:24.708451Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] failed to start input device soundcore AeroClip (input) (attempt 2): device soundcore AeroClip (input) not found
2026-05-11T07:21:26.711922Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] no input device running (attempt 3), starting default: soundcore AeroClip (input)
2026-05-11T07:21:26.712001Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] failed to start input device soundcore AeroClip (input) (attempt 3): device soundcore AeroClip (input) not found
2026-05-11T07:21:28.723900Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] no input device running (attempt 4), starting default: soundcore AeroClip (input)
2026-05-11T07:21:28.726974Z INFO screenpipe_audio::device::device_manager: starting recording for device: soundcore AeroClip (input)
2026-05-11T07:21:28.727134Z INFO screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] input device restored, device=soundcore AeroClip (input)
2026-05-11T07:21:28.972503Z INFO screenpipe_audio::core::run_record_and_transcribe: starting continuous recording for soundcore AeroClip (input) (bluetooth / 30s segments)
2026-05-11T07:21:28.972538Z INFO screenpipe_audio::core::run_record_and_transcribe: screen locked, pausing audio recording for soundcore AeroClip (input)
tip: wire screenpipe into claude with one command:
claude mcp add screenpipe -- npx -y screenpipe-mcp
then ask claude to build a pipe that tracks who you are, your todos, and how you spend your time from your screen activity
2026-05-11T07:54:37.325769Z INFO screenpipe_en...
|
[{"role":"AXTextArea","text [{"role":"AXTextArea","text":"whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\n2026-05-10T23:27:31.985285Z INFO screenpipe_audio::audio_manager::manager: reconciliation: transcribed 50 orphaned chunks\n2026-05-10T23:27:41.489329Z ERROR screenpipe_audio::core::stream: an error occurred on the audio stream: device disconnected\n2026-05-10T23:27:42.161846Z INFO screenpipe_audio::audio_manager::device_monitor: system default input changed to: MacBook Pro Microphone (input)\n2026-05-10T23:27:42.163527Z INFO screenpipe_audio::device::device_manager: starting recording for device: MacBook Pro Microphone (input)\n2026-05-10T23:27:42.164408Z INFO screenpipe_audio::audio_manager::device_monitor: switched to new system default input: MacBook Pro Microphone (input)\n2026-05-10T23:27:42.164471Z INFO screenpipe_audio::core::run_record_and_transcribe: starting continuous recording for MacBook Pro Microphone (input) (wired / 30s segments)\n2026-05-10T23:27:42.164492Z INFO screenpipe_audio::core::run_record_and_transcribe: screen locked, pausing audio recording for MacBook Pro Microphone (input)\n2026-05-10T23:27:42.881174Z INFO screenpipe_audio::core::run_record_and_transcribe: stopped recording for soundcore AeroClip (input)\n2026-05-10T23:27:43.285854Z INFO screenpipe_audio::transcription::handle_new_transcript: device soundcore AeroClip (input) skipping duplicate transcript (entire content overlaps with previous)\n2026-05-10T23:27:58.189174Z INFO screenpipe_audio::audio_manager::device_monitor: system default input changed to: soundcore AeroClip (input)\n2026-05-10T23:27:58.190264Z INFO screenpipe_audio::device::device_manager: starting recording for device: soundcore AeroClip (input)\n2026-05-10T23:27:58.190299Z INFO screenpipe_audio::audio_manager::device_monitor: switched to new system default input: soundcore AeroClip (input)\n2026-05-10T23:27:58.190324Z INFO screenpipe_audio::core::run_record_and_transcribe: starting continuous recording for soundcore AeroClip (input) (bluetooth / 30s segments)\n2026-05-10T23:27:58.190332Z INFO screenpipe_audio::core::run_record_and_transcribe: screen locked, pausing audio recording for soundcore AeroClip (input)\n2026-05-10T23:27:58.203316Z INFO screenpipe_audio::core::run_record_and_transcribe: stopped recording for MacBook Pro Microphone (input)\n2026-05-10T23:28:32.063312Z ERROR screenpipe_audio::core::stream: an error occurred on the audio stream: device disconnected\n2026-05-10T23:28:32.531328Z INFO screenpipe_audio::audio_manager::device_monitor: system default input changed to: MacBook Pro Microphone (input)\n2026-05-10T23:28:32.531913Z INFO screenpipe_audio::device::device_manager: starting recording for device: MacBook Pro Microphone (input)\n2026-05-10T23:28:32.531933Z INFO screenpipe_audio::audio_manager::device_monitor: switched to new system default input: MacBook Pro Microphone (input)\n2026-05-10T23:28:32.532003Z INFO screenpipe_audio::core::run_record_and_transcribe: stopped recording for soundcore AeroClip (input)\n2026-05-10T23:28:32.708770Z INFO screenpipe_audio::core::run_record_and_transcribe: starting continuous recording for MacBook Pro Microphone (input) (wired / 30s segments)\n2026-05-10T23:28:32.708807Z INFO screenpipe_audio::core::run_record_and_transcribe: screen locked, pausing audio recording for MacBook Pro Microphone (input)\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\n2026-05-10T23:51:42.401532Z INFO screenpipe_audio::audio_manager::manager: reconciliation: transcribed 50 orphaned chunks\n\n tip: sign in for higher AI quotas + cloud sync:\n screenpipe login\n\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\n2026-05-11T02:54:23.501609Z INFO screenpipe_audio::audio_manager::manager: reconciliation: transcribed 50 orphaned chunks\n\n tip: get the screenpipe desktop app for the full experience\n https://screenpi.pe\n\n2026-05-11T07:21:22.702849Z INFO screenpipe_audio::audio_manager::device_monitor: system default input changed to: soundcore AeroClip (input)\n2026-05-11T07:21:22.703351Z ERROR screenpipe_audio::audio_manager::device_monitor: failed to start new default input soundcore AeroClip (input): device soundcore AeroClip (input) not found (will back off)\n2026-05-11T07:21:22.704671Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] no input device running (attempt 1), starting default: soundcore AeroClip (input)\n2026-05-11T07:21:22.704693Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] failed to start input device soundcore AeroClip (input) (attempt 1): device soundcore AeroClip (input) not found\n2026-05-11T07:21:23.587900Z INFO screenpipe_audio::core::run_record_and_transcribe: stopped recording for MacBook Pro Microphone (input)\n2026-05-11T07:21:24.708381Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] no input device running (attempt 2), starting default: soundcore AeroClip (input)\n2026-05-11T07:21:24.708451Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] failed to start input device soundcore AeroClip (input) (attempt 2): device soundcore AeroClip (input) not found\n2026-05-11T07:21:26.711922Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] no input device running (attempt 3), starting default: soundcore AeroClip (input)\n2026-05-11T07:21:26.712001Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] failed to start input device soundcore AeroClip (input) (attempt 3): device soundcore AeroClip (input) not found\n2026-05-11T07:21:28.723900Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] no input device running (attempt 4), starting default: soundcore AeroClip (input)\n2026-05-11T07:21:28.726974Z INFO screenpipe_audio::device::device_manager: starting recording for device: soundcore AeroClip (input)\n2026-05-11T07:21:28.727134Z INFO screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] input device restored, device=soundcore AeroClip (input)\n2026-05-11T07:21:28.972503Z INFO screenpipe_audio::core::run_record_and_transcribe: starting continuous recording for soundcore AeroClip (input) (bluetooth / 30s segments)\n2026-05-11T07:21:28.972538Z INFO screenpipe_audio::core::run_record_and_transcribe: screen locked, pausing audio recording for soundcore AeroClip (input)\n\n tip: wire screenpipe into claude with one command:\n claude mcp add screenpipe -- npx -y screenpipe-mcp\n then ask claude to build a pipe that tracks who you are, your todos, and how you spend your time from your screen activity\n\n2026-05-11T07:54:37.325769Z INFO screenpipe_engine::sleep_monitor: Screen unlocked (CGSession safety-net poll)\n2026-05-11T07:54:37.395897Z INFO screenpipe_engine::event_driven_capture: invalidating persistent streams after unlock/wake for monitor 1\n2026-05-11T07:54:37.716552Z INFO screenpipe_audio::core::run_record_and_transcribe: screen unlocked — rebuilding stream for soundcore AeroClip (input) (avoids zombie-callback state observed after sleep/wake on macOS, Windows, and Linux)\n2026-05-11T07:54:37.848027Z WARN screenpipe_audio::audio_manager::manager: recording for device soundcore AeroClip (input) exited with error: stream rebuild required after screen unlock for soundcore AeroClip (input) (recovery is automatic via device_monitor)\n2026-05-11T07:54:38.122040Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] detected stale recording handle for soundcore AeroClip (input), cleaning up for restart\n2026-05-11T07:54:38.122133Z INFO screenpipe_audio::device::device_manager: Stopping device: soundcore AeroClip (input)\n2026-05-11T07:54:38.359253Z INFO screenpipe_audio::device::device_manager: starting recording for device: soundcore AeroClip (input)\n2026-05-11T07:54:38.359387Z INFO screenpipe_audio::audio_manager::device_monitor: restarted with system default device: soundcore AeroClip (input)\n2026-05-11T07:54:38.359454Z INFO screenpipe_audio::core::run_record_and_transcribe: starting continuous recording for soundcore AeroClip (input) (bluetooth / 30s segments)\n\n tip: install a starter bundle of pipes:\n screenpipe install https://screenpi.pe/start.json\n\n2026-05-11T07:54:38.859645Z INFO screenpipe_engine::vision_manager::monitor_watcher: Monitor 2 disconnected, stopping recording\n2026-05-11T07:54:38.859753Z INFO screenpipe_engine::vision_manager::manager: Stopping vision recording for monitor 2\n2026-05-11T07:54:39.562590Z INFO sck_rs::stream_manager: stopped 2 persistent stream(s)\n2026-05-11T07:54:43.369378Z INFO sck_rs::stream_manager: persistent SCK stream started for display 2 (3008x1253, 2fps, 0 excluded)\n2026-05-11T07:54:44.338317Z INFO sck_rs::stream_manager: persistent SCK stream started for display 1 (1440x900, 2fps, 0 excluded)\n2026-05-11T07:54:44.740316Z INFO screenpipe_engine::hot_frame_cache: hot_frame_cache: day rollover (130 -> 131), clearing cache","depth":4,"on_screen":true,"value":"whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\n2026-05-10T23:27:31.985285Z INFO screenpipe_audio::audio_manager::manager: reconciliation: transcribed 50 orphaned chunks\n2026-05-10T23:27:41.489329Z ERROR screenpipe_audio::core::stream: an error occurred on the audio stream: device disconnected\n2026-05-10T23:27:42.161846Z INFO screenpipe_audio::audio_manager::device_monitor: system default input changed to: MacBook Pro Microphone (input)\n2026-05-10T23:27:42.163527Z INFO screenpipe_audio::device::device_manager: starting recording for device: MacBook Pro Microphone (input)\n2026-05-10T23:27:42.164408Z INFO screenpipe_audio::audio_manager::device_monitor: switched to new system default input: MacBook Pro Microphone (input)\n2026-05-10T23:27:42.164471Z INFO screenpipe_audio::core::run_record_and_transcribe: starting continuous recording for MacBook Pro Microphone (input) (wired / 30s segments)\n2026-05-10T23:27:42.164492Z INFO screenpipe_audio::core::run_record_and_transcribe: screen locked, pausing audio recording for MacBook Pro Microphone (input)\n2026-05-10T23:27:42.881174Z INFO screenpipe_audio::core::run_record_and_transcribe: stopped recording for soundcore AeroClip (input)\n2026-05-10T23:27:43.285854Z INFO screenpipe_audio::transcription::handle_new_transcript: device soundcore AeroClip (input) skipping duplicate transcript (entire content overlaps with previous)\n2026-05-10T23:27:58.189174Z INFO screenpipe_audio::audio_manager::device_monitor: system default input changed to: soundcore AeroClip (input)\n2026-05-10T23:27:58.190264Z INFO screenpipe_audio::device::device_manager: starting recording for device: soundcore AeroClip (input)\n2026-05-10T23:27:58.190299Z INFO screenpipe_audio::audio_manager::device_monitor: switched to new system default input: soundcore AeroClip (input)\n2026-05-10T23:27:58.190324Z INFO screenpipe_audio::core::run_record_and_transcribe: starting continuous recording for soundcore AeroClip (input) (bluetooth / 30s segments)\n2026-05-10T23:27:58.190332Z INFO screenpipe_audio::core::run_record_and_transcribe: screen locked, pausing audio recording for soundcore AeroClip (input)\n2026-05-10T23:27:58.203316Z INFO screenpipe_audio::core::run_record_and_transcribe: stopped recording for MacBook Pro Microphone (input)\n2026-05-10T23:28:32.063312Z ERROR screenpipe_audio::core::stream: an error occurred on the audio stream: device disconnected\n2026-05-10T23:28:32.531328Z INFO screenpipe_audio::audio_manager::device_monitor: system default input changed to: MacBook Pro Microphone (input)\n2026-05-10T23:28:32.531913Z INFO screenpipe_audio::device::device_manager: starting recording for device: MacBook Pro Microphone (input)\n2026-05-10T23:28:32.531933Z INFO screenpipe_audio::audio_manager::device_monitor: switched to new system default input: MacBook Pro Microphone (input)\n2026-05-10T23:28:32.532003Z INFO screenpipe_audio::core::run_record_and_transcribe: stopped recording for soundcore AeroClip (input)\n2026-05-10T23:28:32.708770Z INFO screenpipe_audio::core::run_record_and_transcribe: starting continuous recording for MacBook Pro Microphone (input) (wired / 30s segments)\n2026-05-10T23:28:32.708807Z INFO screenpipe_audio::core::run_record_and_transcribe: screen locked, pausing audio recording for MacBook Pro Microphone (input)\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\n2026-05-10T23:51:42.401532Z INFO screenpipe_audio::audio_manager::manager: reconciliation: transcribed 50 orphaned chunks\n\n tip: sign in for higher AI quotas + cloud sync:\n screenpipe login\n\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\nwhisper_backend_init_gpu: device 0: Metal (type: 1)\nwhisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)\nwhisper_backend_init_gpu: using Metal backend\nggml_metal_init: allocating\nggml_metal_init: found device: Apple M1\nggml_metal_init: picking default device: Apple M1\nggml_metal_init: use fusion = true\nggml_metal_init: use concurrency = true\nggml_metal_init: use graph optimize = true\nwhisper_backend_init: using BLAS backend\nwhisper_init_state: kv self size = 3.15 MB\nwhisper_init_state: kv cross size = 9.44 MB\nwhisper_init_state: kv pad size = 2.36 MB\nwhisper_init_state: compute buffer (conv) = 14.17 MB\nwhisper_init_state: compute buffer (encode) = 65.96 MB\nwhisper_init_state: compute buffer (cross) = 8.50 MB\nwhisper_init_state: compute buffer (decode) = 96.83 MB\nggml_metal_free: deallocating\n2026-05-11T02:54:23.501609Z INFO screenpipe_audio::audio_manager::manager: reconciliation: transcribed 50 orphaned chunks\n\n tip: get the screenpipe desktop app for the full experience\n https://screenpi.pe\n\n2026-05-11T07:21:22.702849Z INFO screenpipe_audio::audio_manager::device_monitor: system default input changed to: soundcore AeroClip (input)\n2026-05-11T07:21:22.703351Z ERROR screenpipe_audio::audio_manager::device_monitor: failed to start new default input soundcore AeroClip (input): device soundcore AeroClip (input) not found (will back off)\n2026-05-11T07:21:22.704671Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] no input device running (attempt 1), starting default: soundcore AeroClip (input)\n2026-05-11T07:21:22.704693Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] failed to start input device soundcore AeroClip (input) (attempt 1): device soundcore AeroClip (input) not found\n2026-05-11T07:21:23.587900Z INFO screenpipe_audio::core::run_record_and_transcribe: stopped recording for MacBook Pro Microphone (input)\n2026-05-11T07:21:24.708381Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] no input device running (attempt 2), starting default: soundcore AeroClip (input)\n2026-05-11T07:21:24.708451Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] failed to start input device soundcore AeroClip (input) (attempt 2): device soundcore AeroClip (input) not found\n2026-05-11T07:21:26.711922Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] no input device running (attempt 3), starting default: soundcore AeroClip (input)\n2026-05-11T07:21:26.712001Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] failed to start input device soundcore AeroClip (input) (attempt 3): device soundcore AeroClip (input) not found\n2026-05-11T07:21:28.723900Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] no input device running (attempt 4), starting default: soundcore AeroClip (input)\n2026-05-11T07:21:28.726974Z INFO screenpipe_audio::device::device_manager: starting recording for device: soundcore AeroClip (input)\n2026-05-11T07:21:28.727134Z INFO screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] input device restored, device=soundcore AeroClip (input)\n2026-05-11T07:21:28.972503Z INFO screenpipe_audio::core::run_record_and_transcribe: starting continuous recording for soundcore AeroClip (input) (bluetooth / 30s segments)\n2026-05-11T07:21:28.972538Z INFO screenpipe_audio::core::run_record_and_transcribe: screen locked, pausing audio recording for soundcore AeroClip (input)\n\n tip: wire screenpipe into claude with one command:\n claude mcp add screenpipe -- npx -y screenpipe-mcp\n then ask claude to build a pipe that tracks who you are, your todos, and how you spend your time from your screen activity\n\n2026-05-11T07:54:37.325769Z INFO screenpipe_engine::sleep_monitor: Screen unlocked (CGSession safety-net poll)\n2026-05-11T07:54:37.395897Z INFO screenpipe_engine::event_driven_capture: invalidating persistent streams after unlock/wake for monitor 1\n2026-05-11T07:54:37.716552Z INFO screenpipe_audio::core::run_record_and_transcribe: screen unlocked — rebuilding stream for soundcore AeroClip (input) (avoids zombie-callback state observed after sleep/wake on macOS, Windows, and Linux)\n2026-05-11T07:54:37.848027Z WARN screenpipe_audio::audio_manager::manager: recording for device soundcore AeroClip (input) exited with error: stream rebuild required after screen unlock for soundcore AeroClip (input) (recovery is automatic via device_monitor)\n2026-05-11T07:54:38.122040Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] detected stale recording handle for soundcore AeroClip (input), cleaning up for restart\n2026-05-11T07:54:38.122133Z INFO screenpipe_audio::device::device_manager: Stopping device: soundcore AeroClip (input)\n2026-05-11T07:54:38.359253Z INFO screenpipe_audio::device::device_manager: starting recording for device: soundcore AeroClip (input)\n2026-05-11T07:54:38.359387Z INFO screenpipe_audio::audio_manager::device_monitor: restarted with system default device: soundcore AeroClip (input)\n2026-05-11T07:54:38.359454Z INFO screenpipe_audio::core::run_record_and_transcribe: starting continuous recording for soundcore AeroClip (input) (bluetooth / 30s segments)\n\n tip: install a starter bundle of pipes:\n screenpipe install https://screenpi.pe/start.json\n\n2026-05-11T07:54:38.859645Z INFO screenpipe_engine::vision_manager::monitor_watcher: Monitor 2 disconnected, stopping recording\n2026-05-11T07:54:38.859753Z INFO screenpipe_engine::vision_manager::manager: Stopping vision recording for monitor 2\n2026-05-11T07:54:39.562590Z INFO sck_rs::stream_manager: stopped 2 persistent stream(s)\n2026-05-11T07:54:43.369378Z INFO sck_rs::stream_manager: persistent SCK stream started for display 2 (3008x1253, 2fps, 0 excluded)\n2026-05-11T07:54:44.338317Z INFO sck_rs::stream_manager: persistent SCK stream started for display 1 (1440x900, 2fps, 0 excluded)\n2026-05-11T07:54:44.740316Z INFO screenpipe_engine::hot_frame_cache: hot_frame_cache: day rollover (130 -> 131), clearing cache","is_focused":true},{"role":"AXRadioButton","text":"DOCKER","depth":2,"bounds":{"left":0.0,"top":0.05888889,"width":0.12291667,"height":0.026666667},"on_screen":true,"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.004166667,"top":0.06333333,"width":0.011111111,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"DEV (-zsh)","depth":2,"bounds":{"left":0.12291667,"top":0.05888889,"width":0.12291667,"height":0.026666667},"on_screen":true,"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.12708333,"top":0.06333333,"width":0.011111111,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"APP (-zsh)","depth":2,"bounds":{"left":0.24583334,"top":0.05888889,"width":0.12291667,"height":0.026666667},"on_screen":true,"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.25,"top":0.06333333,"width":0.011111111,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"-zsh","depth":2,"bounds":{"left":0.36875,"top":0.05888889,"width":0.12291667,"height":0.026666667},"on_screen":true,"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.37291667,"top":0.06333333,"width":0.011111111,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"-zsh","depth":2,"bounds":{"left":0.49166667,"top":0.05888889,"width":0.12291667,"height":0.026666667},"on_screen":true,"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.49583334,"top":0.06333333,"width":0.011111111,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"screenpipe\"","depth":2,"bounds":{"left":0.6145833,"top":0.05888889,"width":0.12291667,"height":0.026666667},"on_screen":true,"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.61875,"top":0.06333333,"width":0.011111111,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"-zsh","depth":2,"bounds":{"left":0.7375,"top":0.05888889,"width":0.12291667,"height":0.026666667},"on_screen":true,"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.7416667,"top":0.06333333,"width":0.011111111,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"-zsh","depth":2,"bounds":{"left":0.86041665,"top":0.05888889,"width":0.12291667,"height":0.026666667},"on_screen":true,"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.8645833,"top":0.06333333,"width":0.011111111,"height":0.017777778},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"⌥⌘1","depth":1,"bounds":{"left":0.9548611,"top":0.032222223,"width":0.03888889,"height":0.018888889},"on_screen":true,"automation_id":"_NS:8","role_description":"text"},{"role":"AXStaticText","text":"screenpipe\"","depth":1,"bounds":{"left":0.47083333,"top":0.033333335,"width":0.058333334,"height":0.017777778},"on_screen":true,"role_description":"text"}]...
|
-7753641314521957899
|
-816202935197436448
|
visual_change
|
accessibility
|
NULL
|
whisper_backend_init_gpu: found GPU device 0: Meta whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
2026-05-10T23:27:31.985285Z INFO screenpipe_audio::audio_manager::manager: reconciliation: transcribed 50 orphaned chunks
2026-05-10T23:27:41.489329Z ERROR screenpipe_audio::core::stream: an error occurred on the audio stream: device disconnected
2026-05-10T23:27:42.161846Z INFO screenpipe_audio::audio_manager::device_monitor: system default input changed to: MacBook Pro Microphone (input)
2026-05-10T23:27:42.163527Z INFO screenpipe_audio::device::device_manager: starting recording for device: MacBook Pro Microphone (input)
2026-05-10T23:27:42.164408Z INFO screenpipe_audio::audio_manager::device_monitor: switched to new system default input: MacBook Pro Microphone (input)
2026-05-10T23:27:42.164471Z INFO screenpipe_audio::core::run_record_and_transcribe: starting continuous recording for MacBook Pro Microphone (input) (wired / 30s segments)
2026-05-10T23:27:42.164492Z INFO screenpipe_audio::core::run_record_and_transcribe: screen locked, pausing audio recording for MacBook Pro Microphone (input)
2026-05-10T23:27:42.881174Z INFO screenpipe_audio::core::run_record_and_transcribe: stopped recording for soundcore AeroClip (input)
2026-05-10T23:27:43.285854Z INFO screenpipe_audio::transcription::handle_new_transcript: device soundcore AeroClip (input) skipping duplicate transcript (entire content overlaps with previous)
2026-05-10T23:27:58.189174Z INFO screenpipe_audio::audio_manager::device_monitor: system default input changed to: soundcore AeroClip (input)
2026-05-10T23:27:58.190264Z INFO screenpipe_audio::device::device_manager: starting recording for device: soundcore AeroClip (input)
2026-05-10T23:27:58.190299Z INFO screenpipe_audio::audio_manager::device_monitor: switched to new system default input: soundcore AeroClip (input)
2026-05-10T23:27:58.190324Z INFO screenpipe_audio::core::run_record_and_transcribe: starting continuous recording for soundcore AeroClip (input) (bluetooth / 30s segments)
2026-05-10T23:27:58.190332Z INFO screenpipe_audio::core::run_record_and_transcribe: screen locked, pausing audio recording for soundcore AeroClip (input)
2026-05-10T23:27:58.203316Z INFO screenpipe_audio::core::run_record_and_transcribe: stopped recording for MacBook Pro Microphone (input)
2026-05-10T23:28:32.063312Z ERROR screenpipe_audio::core::stream: an error occurred on the audio stream: device disconnected
2026-05-10T23:28:32.531328Z INFO screenpipe_audio::audio_manager::device_monitor: system default input changed to: MacBook Pro Microphone (input)
2026-05-10T23:28:32.531913Z INFO screenpipe_audio::device::device_manager: starting recording for device: MacBook Pro Microphone (input)
2026-05-10T23:28:32.531933Z INFO screenpipe_audio::audio_manager::device_monitor: switched to new system default input: MacBook Pro Microphone (input)
2026-05-10T23:28:32.532003Z INFO screenpipe_audio::core::run_record_and_transcribe: stopped recording for soundcore AeroClip (input)
2026-05-10T23:28:32.708770Z INFO screenpipe_audio::core::run_record_and_transcribe: starting continuous recording for MacBook Pro Microphone (input) (wired / 30s segments)
2026-05-10T23:28:32.708807Z INFO screenpipe_audio::core::run_record_and_transcribe: screen locked, pausing audio recording for MacBook Pro Microphone (input)
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
2026-05-10T23:51:42.401532Z INFO screenpipe_audio::audio_manager::manager: reconciliation: transcribed 50 orphaned chunks
tip: sign in for higher AI quotas + cloud sync:
screenpipe login
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
whisper_backend_init_gpu: device 0: Metal (type: 1)
whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)
whisper_backend_init_gpu: using Metal backend
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1
ggml_metal_init: picking default device: Apple M1
ggml_metal_init: use fusion = true
ggml_metal_init: use concurrency = true
ggml_metal_init: use graph optimize = true
whisper_backend_init: using BLAS backend
whisper_init_state: kv self size = 3.15 MB
whisper_init_state: kv cross size = 9.44 MB
whisper_init_state: kv pad size = 2.36 MB
whisper_init_state: compute buffer (conv) = 14.17 MB
whisper_init_state: compute buffer (encode) = 65.96 MB
whisper_init_state: compute buffer (cross) = 8.50 MB
whisper_init_state: compute buffer (decode) = 96.83 MB
ggml_metal_free: deallocating
2026-05-11T02:54:23.501609Z INFO screenpipe_audio::audio_manager::manager: reconciliation: transcribed 50 orphaned chunks
tip: get the screenpipe desktop app for the full experience
https://screenpi.pe
2026-05-11T07:21:22.702849Z INFO screenpipe_audio::audio_manager::device_monitor: system default input changed to: soundcore AeroClip (input)
2026-05-11T07:21:22.703351Z ERROR screenpipe_audio::audio_manager::device_monitor: failed to start new default input soundcore AeroClip (input): device soundcore AeroClip (input) not found (will back off)
2026-05-11T07:21:22.704671Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] no input device running (attempt 1), starting default: soundcore AeroClip (input)
2026-05-11T07:21:22.704693Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] failed to start input device soundcore AeroClip (input) (attempt 1): device soundcore AeroClip (input) not found
2026-05-11T07:21:23.587900Z INFO screenpipe_audio::core::run_record_and_transcribe: stopped recording for MacBook Pro Microphone (input)
2026-05-11T07:21:24.708381Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] no input device running (attempt 2), starting default: soundcore AeroClip (input)
2026-05-11T07:21:24.708451Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] failed to start input device soundcore AeroClip (input) (attempt 2): device soundcore AeroClip (input) not found
2026-05-11T07:21:26.711922Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] no input device running (attempt 3), starting default: soundcore AeroClip (input)
2026-05-11T07:21:26.712001Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] failed to start input device soundcore AeroClip (input) (attempt 3): device soundcore AeroClip (input) not found
2026-05-11T07:21:28.723900Z WARN screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] no input device running (attempt 4), starting default: soundcore AeroClip (input)
2026-05-11T07:21:28.726974Z INFO screenpipe_audio::device::device_manager: starting recording for device: soundcore AeroClip (input)
2026-05-11T07:21:28.727134Z INFO screenpipe_audio::audio_manager::device_monitor: [DEVICE_RECOVERY] input device restored, device=soundcore AeroClip (input)
2026-05-11T07:21:28.972503Z INFO screenpipe_audio::core::run_record_and_transcribe: starting continuous recording for soundcore AeroClip (input) (bluetooth / 30s segments)
2026-05-11T07:21:28.972538Z INFO screenpipe_audio::core::run_record_and_transcribe: screen locked, pausing audio recording for soundcore AeroClip (input)
tip: wire screenpipe into claude with one command:
claude mcp add screenpipe -- npx -y screenpipe-mcp
then ask claude to build a pipe that tracks who you are, your todos, and how you spend your time from your screen activity
2026-05-11T07:54:37.325769Z INFO screenpipe_en...
|
14918
|
NULL
|
NULL
|
NULL
|
|
4289
|
154
|
17
|
2026-05-07T13:23:50.328964+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778160230328_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_2
|
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
195
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1499,"provider":"hubspot","refreshToken":"96f94c623a404e02ebdbf07f1b75707bb6cdbf848cbf45d418baf608c41a8d86","state":"connected"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [SocialAccountObserver] Access token was modified, encrypting {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:13] local.INFO: [SocialAccountService] Token refreshed {"socialAccountId":1499,"provider":"hubspot","state":"connected"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:13] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:13] local.INFO: [Hubspot] Received 429 from API {"team_id":2,"config_id":2,"retry_after":10,"reason":"Client error: `POST [URL_WITH_CREDENTIALS] CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
if (! $this->rateLimiter->canMakeRequest($this->config)) {
$retryAfter = $this->rateLimiter->requestAvailableIn($this->config);
$this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
]);
throw new RateLimitException(
'Hubspot rate limit reached for configuration ' . $this->config->getId(),
$retryAfter,
);
}
$this->rateLimiter->incrementRequestCount($this->config);
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
public function isHubspotRateLimit(Throwable $e): bool
{
return method_exists($e, 'getCode') && (int) $e->getCode() === 429;
}
public function parseRetryAfter(Throwable $e): int
{
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$this->log->info('[Hubspot] DEBUG Getting headers', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$headers ' . PHP_EOL . print_r($headers, true));
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch ...
|
[{"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":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"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,"bounds":{"left":0.8081782,"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":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"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 'AskJiminnyReportActivityServiceTest'","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 'AskJiminnyReportActivityServiceTest'","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":"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":"195","depth":4,"bounds":{"left":0.6838431,"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.6974734,"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.70478725,"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-07 13:22:12] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1499,\"provider\":\"hubspot\",\"refreshToken\":\"96f94c623a404e02ebdbf07f1b75707bb6cdbf848cbf45d418baf608c41a8d86\",\"state\":\"connected\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [SocialAccountObserver] Access token was modified, encrypting {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.INFO: [SocialAccountService] Token refreshed {\"socialAccountId\":1499,\"provider\":\"hubspot\",\"state\":\"connected\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.INFO: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e029a-6 (truncated...)\n\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.ERROR: Hubspot returned 429 {\"exception\":\"[object] (Jiminny\\\\Exceptions\\\\RateLimitException(code: 0): Hubspot returned 429 at /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php:206)\n[stacktrace]\n#0 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(52): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->executeSearchRequest(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), 'https://api.hub...', Array, Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\PaginationState))\n#1 /home/jiminny/app/Services/Crm/Hubspot/Client.php(176): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->getPaginatedDataGenerator(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), Array, 'contact', 0, 0, NULL)\n#2 /home/jiminny/app/Services/Crm/Hubspot/Service.php(1203): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client->getPaginatedData(Array, 'contact')\n#3 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(353): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Service->matchByName('Robot')\n#4 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(44): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->rateLimit()\n#5 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->handle(Object(Jiminny\\\\Jobs\\\\JobDispatcher), Object(Jiminny\\\\Services\\\\Kiosk\\\\AutomatedReports\\\\AutomatedReportsService), Object(Jiminny\\\\Repositories\\\\AutomatedReportsRepository), Object(Jiminny\\\\Services\\\\UserPilot\\\\UserPilotClient))\n#6 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Util.php(43): Illuminate\\\\Container\\\\BoundMethod::Illuminate\\\\Container\\\\{closure}()\n#7 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(96): Illuminate\\\\Container\\\\Util::unwrapIfClosure(Object(Closure))\n#8 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(35): Illuminate\\\\Container\\\\BoundMethod::callBoundMethod(Object(Illuminate\\\\Foundation\\\\Application), Array, Object(Closure))\n#9 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Container.php(799): Illuminate\\\\Container\\\\BoundMethod::call(Object(Illuminate\\\\Foundation\\\\Application), Array, Array, NULL)\n#10 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(211): Illuminate\\\\Container\\\\Container->call(Array)\n#11 /home/jiminny/vendor/symfony/console/Command/Command.php(341): Illuminate\\\\Console\\\\Command->execute(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#12 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(180): Symfony\\\\Component\\\\Console\\\\Command\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#13 /home/jiminny/vendor/symfony/console/Application.php(1117): Illuminate\\\\Console\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#14 /home/jiminny/vendor/symfony/console/Application.php(356): Symfony\\\\Component\\\\Console\\\\Application->doRunCommand(Object(Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand), Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#15 /home/jiminny/vendor/symfony/console/Application.php(195): Symfony\\\\Component\\\\Console\\\\Application->doRun(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#16 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(198): Symfony\\\\Component\\\\Console\\\\Application->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#17 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(1235): Illuminate\\\\Foundation\\\\Console\\\\Kernel->handle(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#18 /home/jiminny/artisan(13): Illuminate\\\\Foundation\\\\Application->handleCommand(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput))\n#19 {main}\n\n[previous exception] [object] (SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest(code: 429): Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e029a-6 (truncated...)\n at /home/jiminny/vendor/hubspot/hubspot-php/src/Exceptions/HubspotException.php:24)\n[stacktrace]\n#0 /home/jiminny/vendor/hubspot/hubspot-php/src/Http/Client.php(125): SevenShores\\\\Hubspot\\\\Exceptions\\\\HubspotException::create(Object(GuzzleHttp\\\\Exception\\\\ClientException))\n#1 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(166): SevenShores\\\\Hubspot\\\\Http\\\\Client->request('POST', 'https://api.hub...', Array)\n#2 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(52): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->executeSearchRequest(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), 'https://api.hub...', Array, Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\PaginationState))\n#3 /home/jiminny/app/Services/Crm/Hubspot/Client.php(176): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->getPaginatedDataGenerator(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), Array, 'contact', 0, 0, NULL)\n#4 /home/jiminny/app/Services/Crm/Hubspot/Service.php(1203): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client->getPaginatedData(Array, 'contact')\n#5 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(353): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Service->matchByName('Robot')\n#6 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(44): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->rateLimit()\n#7 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->handle(Object(Jiminny\\\\Jobs\\\\JobDispatcher), Object(Jiminny\\\\Services\\\\Kiosk\\\\AutomatedReports\\\\AutomatedReportsService), Object(Jiminny\\\\Repositories\\\\AutomatedReportsRepository), Object(Jiminny\\\\Services\\\\UserPilot\\\\UserPilotClient))\n#8 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Util.php(43): Illuminate\\\\Container\\\\BoundMethod::Illuminate\\\\Container\\\\{closure}()\n#9 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(96): Illuminate\\\\Container\\\\Util::unwrapIfClosure(Object(Closure))\n#10 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(35): Illuminate\\\\Container\\\\BoundMethod::callBoundMethod(Object(Illuminate\\\\Foundation\\\\Application), Array, Object(Closure))\n#11 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Container.php(799): Illuminate\\\\Container\\\\BoundMethod::call(Object(Illuminate\\\\Foundation\\\\Application), Array, Array, NULL)\n#12 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(211): Illuminate\\\\Container\\\\Container->call(Array)\n#13 /home/jiminny/vendor/symfony/console/Command/Command.php(341): Illuminate\\\\Console\\\\Command->execute(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#14 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(180): Symfony\\\\Component\\\\Console\\\\Command\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#15 /home/jiminny/vendor/symfony/console/Application.php(1117): Illuminate\\\\Console\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#16 /home/jiminny/vendor/symfony/console/Application.php(356): Symfony\\\\Component\\\\Console\\\\Application->doRunCommand(Object(Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand), Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#17 /home/jiminny/vendor/symfony/console/Application.php(195): Symfony\\\\Component\\\\Console\\\\Application->doRun(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#18 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(198): Symfony\\\\Component\\\\Console\\\\Application->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#19 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(1235): Illuminate\\\\Foundation\\\\Console\\\\Kernel->handle(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#20 /home/jiminny/artisan(13): Illuminate\\\\Foundation\\\\Application->handleCommand(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput))\n#21 {main}\n\n[previous exception] [object] (GuzzleHttp\\\\Exception\\\\ClientException(code: 429): Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e029a-6 (truncated...)\n at /home/jiminny/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php:111)\n[stacktrace]\n#0 /home/jiminny/vendor/guzzlehttp/guzzle/src/Middleware.php(72): GuzzleHttp\\\\Exception\\\\RequestException::create(Object(GuzzleHttp\\\\Psr7\\\\Request), Object(GuzzleHttp\\\\Psr7\\\\Response), NULL, Array, NULL)\n#1 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(209): GuzzleHttp\\\\Middleware::GuzzleHttp\\\\{closure}(Object(GuzzleHttp\\\\Psr7\\\\Response))\n#2 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(158): GuzzleHttp\\\\Promise\\\\Promise::callHandler(1, Object(GuzzleHttp\\\\Psr7\\\\Response), NULL)\n#3 /home/jiminny/vendor/guzzlehttp/promises/src/TaskQueue.php(52): GuzzleHttp\\\\Promise\\\\Promise::GuzzleHttp\\\\Promise\\\\{closure}()\n#4 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(251): GuzzleHttp\\\\Promise\\\\TaskQueue->run(true)\n#5 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(227): GuzzleHttp\\\\Promise\\\\Promise->invokeWaitFn()\n#6 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(272): GuzzleHttp\\\\Promise\\\\Promise->waitIfPending()\n#7 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(229): GuzzleHttp\\\\Promise\\\\Promise->invokeWaitList()\n#8 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(69): GuzzleHttp\\\\Promise\\\\Promise->waitIfPending()\n#9 /home/jiminny/vendor/guzzlehttp/guzzle/src/Client.php(189): GuzzleHttp\\\\Promise\\\\Promise->wait()\n#10 /home/jiminny/vendor/hubspot/hubspot-php/src/Http/Client.php(113): GuzzleHttp\\\\Client->request('POST', 'https://api.hub...', Array)\n#11 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(166): SevenShores\\\\Hubspot\\\\Http\\\\Client->request('POST', 'https://api.hub...', Array)\n#12 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(52): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->executeSearchRequest(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), 'https://api.hub...', Array, Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\PaginationState))\n#13 /home/jiminny/app/Services/Crm/Hubspot/Client.php(176): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->getPaginatedDataGenerator(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), Array, 'contact', 0, 0, NULL)\n#14 /home/jiminny/app/Services/Crm/Hubspot/Service.php(1203): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client->getPaginatedData(Array, 'contact')\n#15 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(353): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Service->matchByName('Robot')\n#16 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(44): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->rateLimit()\n#17 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->handle(Object(Jiminny\\\\Jobs\\\\JobDispatcher), Object(Jiminny\\\\Services\\\\Kiosk\\\\AutomatedReports\\\\AutomatedReportsService), Object(Jiminny\\\\Repositories\\\\AutomatedReportsRepository), Object(Jiminny\\\\Services\\\\UserPilot\\\\UserPilotClient))\n#18 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Util.php(43): Illuminate\\\\Container\\\\BoundMethod::Illuminate\\\\Container\\\\{closure}()\n#19 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(96): Illuminate\\\\Container\\\\Util::unwrapIfClosure(Object(Closure))\n#20 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(35): Illuminate\\\\Container\\\\BoundMethod::callBoundMethod(Object(Illuminate\\\\Foundation\\\\Application), Array, Object(Closure))\n#21 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Container.php(799): Illuminate\\\\Container\\\\BoundMethod::call(Object(Illuminate\\\\Foundation\\\\Application), Array, Array, NULL)\n#22 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(211): Illuminate\\\\Container\\\\Container->call(Array)\n#23 /home/jiminny/vendor/symfony/console/Command/Command.php(341): Illuminate\\\\Console\\\\Command->execute(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#24 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(180): Symfony\\\\Component\\\\Console\\\\Command\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#25 /home/jiminny/vendor/symfony/console/Application.php(1117): Illuminate\\\\Console\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#26 /home/jiminny/vendor/symfony/console/Application.php(356): Symfony\\\\Component\\\\Console\\\\Application->doRunCommand(Object(Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand), Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#27 /home/jiminny/vendor/symfony/console/Application.php(195): Symfony\\\\Component\\\\Console\\\\Application->doRun(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#28 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(198): Symfony\\\\Component\\\\Console\\\\Application->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#29 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(1235): Illuminate\\\\Foundation\\\\Console\\\\Kernel->handle(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#30 /home/jiminny/artisan(13): Illuminate\\\\Foundation\\\\Application->handleCommand(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput))\n#31 {main}\n\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"42c3d939-2b42-4fa8-9f57-cbdc5bb1457c\",\"trace_id\":\"b9aec736-45fd-47fc-9482-fd558ed6227a\"}\n[2026-05-07 13:22:13] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"42c3d939-2b42-4fa8-9f57-cbdc5bb1457c\",\"trace_id\":\"b9aec736-45fd-47fc-9482-fd558ed6227a\"}\n[2026-05-07 13:22:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"42c3d939-2b42-4fa8-9f57-cbdc5bb1457c\",\"trace_id\":\"b9aec736-45fd-47fc-9482-fd558ed6227a\"}\n[2026-05-07 13:22:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"076c3e6b-6a67-4774-8aa0-2a84fcf5e03c\",\"trace_id\":\"284e571d-ab92-4e22-b09b-c151c2871cb4\"}\n[2026-05-07 13:22:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"076c3e6b-6a67-4774-8aa0-2a84fcf5e03c\",\"trace_id\":\"284e571d-ab92-4e22-b09b-c151c2871cb4\"}\n[2026-05-07 13:22:19] local.NOTICE: Monitoring start {\"correlation_id\":\"c41d4048-0465-4dcf-bb53-176287732e3e\",\"trace_id\":\"9ce4a71c-a1a0-456e-843d-38fd15e5c798\"}\n[2026-05-07 13:22:19] local.NOTICE: Monitoring end {\"correlation_id\":\"c41d4048-0465-4dcf-bb53-176287732e3e\",\"trace_id\":\"9ce4a71c-a1a0-456e-843d-38fd15e5c798\"}\n[2026-05-07 13:22:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"934766d6-40c0-415c-bd51-d0b67a799c7c\",\"trace_id\":\"d6c773e8-adf4-453b-8a17-077bf7bdf698\"}\n[2026-05-07 13:22:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"934766d6-40c0-415c-bd51-d0b67a799c7c\",\"trace_id\":\"d6c773e8-adf4-453b-8a17-077bf7bdf698\"}\n[2026-05-07 13:22:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b99dafc3-0e7f-4cb3-9469-9a18bd4d8a72\",\"trace_id\":\"3ca2e911-32f2-4c22-89ba-aae5e8342c8d\"}\n[2026-05-07 13:22:35] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b99dafc3-0e7f-4cb3-9469-9a18bd4d8a72\",\"trace_id\":\"3ca2e911-32f2-4c22-89ba-aae5e8342c8d\"}\n[2026-05-07 13:22:35] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"b99dafc3-0e7f-4cb3-9469-9a18bd4d8a72\",\"trace_id\":\"3ca2e911-32f2-4c22-89ba-aae5e8342c8d\"}\n[2026-05-07 13:22:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b99dafc3-0e7f-4cb3-9469-9a18bd4d8a72\",\"trace_id\":\"3ca2e911-32f2-4c22-89ba-aae5e8342c8d\"}\n[2026-05-07 13:22:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b8b1efaa-e359-4aa1-942d-2dc8ca6c048b\",\"trace_id\":\"897fc576-4657-4534-ac78-73f6c44cbeef\"}\n[2026-05-07 13:22:41] local.INFO: Running conference:monitor:count command for activities in (2026-05-07 13:20:00, 2026-05-07 13:22:00] {\"correlation_id\":\"b8b1efaa-e359-4aa1-942d-2dc8ca6c048b\",\"trace_id\":\"897fc576-4657-4534-ac78-73f6c44cbeef\"}\n[2026-05-07 13:22:41] local.INFO: [conference:monitor:count] No activities found in (2026-05-07 13:20:00, 2026-05-07 13:22:00] {\"correlation_id\":\"b8b1efaa-e359-4aa1-942d-2dc8ca6c048b\",\"trace_id\":\"897fc576-4657-4534-ac78-73f6c44cbeef\"}\n[2026-05-07 13:22:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b8b1efaa-e359-4aa1-942d-2dc8ca6c048b\",\"trace_id\":\"897fc576-4657-4534-ac78-73f6c44cbeef\"}\n[2026-05-07 13:22:49] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"08dc0025-4642-4d21-a351-c0dee099d6fc\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:49] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"08dc0025-4642-4d21-a351-c0dee099d6fc\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:49] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"08dc0025-4642-4d21-a351-c0dee099d6fc\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:49] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"08dc0025-4642-4d21-a351-c0dee099d6fc\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:52] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 2 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"13eed139-b218-43c9-b147-38ae92c45977\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:53] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"cf9df816-4614-4a06-b853-4d6815fb85e1\",\"trace_id\":\"ca6ed313-c21f-4683-8b5b-013a3ecd4081\"}\n[2026-05-07 13:22:53] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"cf9df816-4614-4a06-b853-4d6815fb85e1\",\"trace_id\":\"ca6ed313-c21f-4683-8b5b-013a3ecd4081\"}\n[2026-05-07 13:22:57] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"twilio:recover-tracks\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"93d3bd4f-fe02-4d22-aab9-00c74309e94c\",\"trace_id\":\"356db0f7-0c25-4739-8c8b-a55ba28e1df0\"}\n[2026-05-07 13:22:57] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"twilio:recover-tracks\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"93d3bd4f-fe02-4d22-aab9-00c74309e94c\",\"trace_id\":\"356db0f7-0c25-4739-8c8b-a55ba28e1df0\"}\n[2026-05-07 13:23:00] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:sync-users\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"connect-and-sell\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Start user synchronisation {\"provider\":\"justcall\",\"teams_count\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Synchronising team {\"provider\":\"justcall\",\"team_id\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.WARNING: [Salesforce] Account not connected for user {\"userId\":\"cdf9285a-8ded-4a8b-bd7d-ec68c398f2f9\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":1367,\"sociable_id\":1071,\"provider_user_id\":\"005O4000003s5c7IAA\",\"expires\":null,\"refresh_token_expires\":null,\"provider\":\"salesforce\",\"state\":\"full-refresh\",\"auth_scope\":\"refresh_token web api\",\"retry_after\":null,\"created_at\":\"2024-09-10 07:05:21\",\"updated_at\":\"2026-01-14 07:00:58\"}}} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"salesforce\",\"crm_owner\":1071,\"team_id\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"salesforce\",\"team_id\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"salesforce\",\"team_id\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.WARNING: Failed to sync external users {\"message\":\"Your Salesforce account has become disconnected. Please login to Jiminny to reconnect.\",\"provider\":\"justcall\",\"team_id\":1,\"team\":\"jiminny\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"ringcentral\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"avaya\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"telus\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"salesloft\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"talkdesk\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"vonage\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Done {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:sync-users\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}","depth":4,"bounds":{"left":0.33976063,"top":0.09736632,"width":0.66023934,"height":0.90263367},"on_screen":true,"value":"[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1499,\"provider\":\"hubspot\",\"refreshToken\":\"96f94c623a404e02ebdbf07f1b75707bb6cdbf848cbf45d418baf608c41a8d86\",\"state\":\"connected\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [SocialAccountObserver] Access token was modified, encrypting {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.INFO: [SocialAccountService] Token refreshed {\"socialAccountId\":1499,\"provider\":\"hubspot\",\"state\":\"connected\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.INFO: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e029a-6 (truncated...)\n\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.ERROR: Hubspot returned 429 {\"exception\":\"[object] (Jiminny\\\\Exceptions\\\\RateLimitException(code: 0): Hubspot returned 429 at /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php:206)\n[stacktrace]\n#0 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(52): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->executeSearchRequest(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), 'https://api.hub...', Array, Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\PaginationState))\n#1 /home/jiminny/app/Services/Crm/Hubspot/Client.php(176): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->getPaginatedDataGenerator(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), Array, 'contact', 0, 0, NULL)\n#2 /home/jiminny/app/Services/Crm/Hubspot/Service.php(1203): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client->getPaginatedData(Array, 'contact')\n#3 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(353): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Service->matchByName('Robot')\n#4 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(44): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->rateLimit()\n#5 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->handle(Object(Jiminny\\\\Jobs\\\\JobDispatcher), Object(Jiminny\\\\Services\\\\Kiosk\\\\AutomatedReports\\\\AutomatedReportsService), Object(Jiminny\\\\Repositories\\\\AutomatedReportsRepository), Object(Jiminny\\\\Services\\\\UserPilot\\\\UserPilotClient))\n#6 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Util.php(43): Illuminate\\\\Container\\\\BoundMethod::Illuminate\\\\Container\\\\{closure}()\n#7 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(96): Illuminate\\\\Container\\\\Util::unwrapIfClosure(Object(Closure))\n#8 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(35): Illuminate\\\\Container\\\\BoundMethod::callBoundMethod(Object(Illuminate\\\\Foundation\\\\Application), Array, Object(Closure))\n#9 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Container.php(799): Illuminate\\\\Container\\\\BoundMethod::call(Object(Illuminate\\\\Foundation\\\\Application), Array, Array, NULL)\n#10 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(211): Illuminate\\\\Container\\\\Container->call(Array)\n#11 /home/jiminny/vendor/symfony/console/Command/Command.php(341): Illuminate\\\\Console\\\\Command->execute(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#12 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(180): Symfony\\\\Component\\\\Console\\\\Command\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#13 /home/jiminny/vendor/symfony/console/Application.php(1117): Illuminate\\\\Console\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#14 /home/jiminny/vendor/symfony/console/Application.php(356): Symfony\\\\Component\\\\Console\\\\Application->doRunCommand(Object(Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand), Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#15 /home/jiminny/vendor/symfony/console/Application.php(195): Symfony\\\\Component\\\\Console\\\\Application->doRun(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#16 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(198): Symfony\\\\Component\\\\Console\\\\Application->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#17 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(1235): Illuminate\\\\Foundation\\\\Console\\\\Kernel->handle(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#18 /home/jiminny/artisan(13): Illuminate\\\\Foundation\\\\Application->handleCommand(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput))\n#19 {main}\n\n[previous exception] [object] (SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest(code: 429): Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e029a-6 (truncated...)\n at /home/jiminny/vendor/hubspot/hubspot-php/src/Exceptions/HubspotException.php:24)\n[stacktrace]\n#0 /home/jiminny/vendor/hubspot/hubspot-php/src/Http/Client.php(125): SevenShores\\\\Hubspot\\\\Exceptions\\\\HubspotException::create(Object(GuzzleHttp\\\\Exception\\\\ClientException))\n#1 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(166): SevenShores\\\\Hubspot\\\\Http\\\\Client->request('POST', 'https://api.hub...', Array)\n#2 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(52): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->executeSearchRequest(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), 'https://api.hub...', Array, Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\PaginationState))\n#3 /home/jiminny/app/Services/Crm/Hubspot/Client.php(176): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->getPaginatedDataGenerator(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), Array, 'contact', 0, 0, NULL)\n#4 /home/jiminny/app/Services/Crm/Hubspot/Service.php(1203): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client->getPaginatedData(Array, 'contact')\n#5 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(353): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Service->matchByName('Robot')\n#6 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(44): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->rateLimit()\n#7 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->handle(Object(Jiminny\\\\Jobs\\\\JobDispatcher), Object(Jiminny\\\\Services\\\\Kiosk\\\\AutomatedReports\\\\AutomatedReportsService), Object(Jiminny\\\\Repositories\\\\AutomatedReportsRepository), Object(Jiminny\\\\Services\\\\UserPilot\\\\UserPilotClient))\n#8 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Util.php(43): Illuminate\\\\Container\\\\BoundMethod::Illuminate\\\\Container\\\\{closure}()\n#9 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(96): Illuminate\\\\Container\\\\Util::unwrapIfClosure(Object(Closure))\n#10 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(35): Illuminate\\\\Container\\\\BoundMethod::callBoundMethod(Object(Illuminate\\\\Foundation\\\\Application), Array, Object(Closure))\n#11 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Container.php(799): Illuminate\\\\Container\\\\BoundMethod::call(Object(Illuminate\\\\Foundation\\\\Application), Array, Array, NULL)\n#12 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(211): Illuminate\\\\Container\\\\Container->call(Array)\n#13 /home/jiminny/vendor/symfony/console/Command/Command.php(341): Illuminate\\\\Console\\\\Command->execute(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#14 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(180): Symfony\\\\Component\\\\Console\\\\Command\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#15 /home/jiminny/vendor/symfony/console/Application.php(1117): Illuminate\\\\Console\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#16 /home/jiminny/vendor/symfony/console/Application.php(356): Symfony\\\\Component\\\\Console\\\\Application->doRunCommand(Object(Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand), Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#17 /home/jiminny/vendor/symfony/console/Application.php(195): Symfony\\\\Component\\\\Console\\\\Application->doRun(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#18 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(198): Symfony\\\\Component\\\\Console\\\\Application->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#19 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(1235): Illuminate\\\\Foundation\\\\Console\\\\Kernel->handle(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#20 /home/jiminny/artisan(13): Illuminate\\\\Foundation\\\\Application->handleCommand(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput))\n#21 {main}\n\n[previous exception] [object] (GuzzleHttp\\\\Exception\\\\ClientException(code: 429): Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e029a-6 (truncated...)\n at /home/jiminny/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php:111)\n[stacktrace]\n#0 /home/jiminny/vendor/guzzlehttp/guzzle/src/Middleware.php(72): GuzzleHttp\\\\Exception\\\\RequestException::create(Object(GuzzleHttp\\\\Psr7\\\\Request), Object(GuzzleHttp\\\\Psr7\\\\Response), NULL, Array, NULL)\n#1 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(209): GuzzleHttp\\\\Middleware::GuzzleHttp\\\\{closure}(Object(GuzzleHttp\\\\Psr7\\\\Response))\n#2 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(158): GuzzleHttp\\\\Promise\\\\Promise::callHandler(1, Object(GuzzleHttp\\\\Psr7\\\\Response), NULL)\n#3 /home/jiminny/vendor/guzzlehttp/promises/src/TaskQueue.php(52): GuzzleHttp\\\\Promise\\\\Promise::GuzzleHttp\\\\Promise\\\\{closure}()\n#4 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(251): GuzzleHttp\\\\Promise\\\\TaskQueue->run(true)\n#5 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(227): GuzzleHttp\\\\Promise\\\\Promise->invokeWaitFn()\n#6 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(272): GuzzleHttp\\\\Promise\\\\Promise->waitIfPending()\n#7 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(229): GuzzleHttp\\\\Promise\\\\Promise->invokeWaitList()\n#8 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(69): GuzzleHttp\\\\Promise\\\\Promise->waitIfPending()\n#9 /home/jiminny/vendor/guzzlehttp/guzzle/src/Client.php(189): GuzzleHttp\\\\Promise\\\\Promise->wait()\n#10 /home/jiminny/vendor/hubspot/hubspot-php/src/Http/Client.php(113): GuzzleHttp\\\\Client->request('POST', 'https://api.hub...', Array)\n#11 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(166): SevenShores\\\\Hubspot\\\\Http\\\\Client->request('POST', 'https://api.hub...', Array)\n#12 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(52): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->executeSearchRequest(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), 'https://api.hub...', Array, Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\PaginationState))\n#13 /home/jiminny/app/Services/Crm/Hubspot/Client.php(176): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->getPaginatedDataGenerator(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), Array, 'contact', 0, 0, NULL)\n#14 /home/jiminny/app/Services/Crm/Hubspot/Service.php(1203): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client->getPaginatedData(Array, 'contact')\n#15 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(353): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Service->matchByName('Robot')\n#16 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(44): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->rateLimit()\n#17 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->handle(Object(Jiminny\\\\Jobs\\\\JobDispatcher), Object(Jiminny\\\\Services\\\\Kiosk\\\\AutomatedReports\\\\AutomatedReportsService), Object(Jiminny\\\\Repositories\\\\AutomatedReportsRepository), Object(Jiminny\\\\Services\\\\UserPilot\\\\UserPilotClient))\n#18 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Util.php(43): Illuminate\\\\Container\\\\BoundMethod::Illuminate\\\\Container\\\\{closure}()\n#19 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(96): Illuminate\\\\Container\\\\Util::unwrapIfClosure(Object(Closure))\n#20 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(35): Illuminate\\\\Container\\\\BoundMethod::callBoundMethod(Object(Illuminate\\\\Foundation\\\\Application), Array, Object(Closure))\n#21 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Container.php(799): Illuminate\\\\Container\\\\BoundMethod::call(Object(Illuminate\\\\Foundation\\\\Application), Array, Array, NULL)\n#22 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(211): Illuminate\\\\Container\\\\Container->call(Array)\n#23 /home/jiminny/vendor/symfony/console/Command/Command.php(341): Illuminate\\\\Console\\\\Command->execute(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#24 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(180): Symfony\\\\Component\\\\Console\\\\Command\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#25 /home/jiminny/vendor/symfony/console/Application.php(1117): Illuminate\\\\Console\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#26 /home/jiminny/vendor/symfony/console/Application.php(356): Symfony\\\\Component\\\\Console\\\\Application->doRunCommand(Object(Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand), Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#27 /home/jiminny/vendor/symfony/console/Application.php(195): Symfony\\\\Component\\\\Console\\\\Application->doRun(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#28 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(198): Symfony\\\\Component\\\\Console\\\\Application->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#29 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(1235): Illuminate\\\\Foundation\\\\Console\\\\Kernel->handle(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#30 /home/jiminny/artisan(13): Illuminate\\\\Foundation\\\\Application->handleCommand(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput))\n#31 {main}\n\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"42c3d939-2b42-4fa8-9f57-cbdc5bb1457c\",\"trace_id\":\"b9aec736-45fd-47fc-9482-fd558ed6227a\"}\n[2026-05-07 13:22:13] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"42c3d939-2b42-4fa8-9f57-cbdc5bb1457c\",\"trace_id\":\"b9aec736-45fd-47fc-9482-fd558ed6227a\"}\n[2026-05-07 13:22:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"42c3d939-2b42-4fa8-9f57-cbdc5bb1457c\",\"trace_id\":\"b9aec736-45fd-47fc-9482-fd558ed6227a\"}\n[2026-05-07 13:22:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"076c3e6b-6a67-4774-8aa0-2a84fcf5e03c\",\"trace_id\":\"284e571d-ab92-4e22-b09b-c151c2871cb4\"}\n[2026-05-07 13:22:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"076c3e6b-6a67-4774-8aa0-2a84fcf5e03c\",\"trace_id\":\"284e571d-ab92-4e22-b09b-c151c2871cb4\"}\n[2026-05-07 13:22:19] local.NOTICE: Monitoring start {\"correlation_id\":\"c41d4048-0465-4dcf-bb53-176287732e3e\",\"trace_id\":\"9ce4a71c-a1a0-456e-843d-38fd15e5c798\"}\n[2026-05-07 13:22:19] local.NOTICE: Monitoring end {\"correlation_id\":\"c41d4048-0465-4dcf-bb53-176287732e3e\",\"trace_id\":\"9ce4a71c-a1a0-456e-843d-38fd15e5c798\"}\n[2026-05-07 13:22:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"934766d6-40c0-415c-bd51-d0b67a799c7c\",\"trace_id\":\"d6c773e8-adf4-453b-8a17-077bf7bdf698\"}\n[2026-05-07 13:22:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"934766d6-40c0-415c-bd51-d0b67a799c7c\",\"trace_id\":\"d6c773e8-adf4-453b-8a17-077bf7bdf698\"}\n[2026-05-07 13:22:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b99dafc3-0e7f-4cb3-9469-9a18bd4d8a72\",\"trace_id\":\"3ca2e911-32f2-4c22-89ba-aae5e8342c8d\"}\n[2026-05-07 13:22:35] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b99dafc3-0e7f-4cb3-9469-9a18bd4d8a72\",\"trace_id\":\"3ca2e911-32f2-4c22-89ba-aae5e8342c8d\"}\n[2026-05-07 13:22:35] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"b99dafc3-0e7f-4cb3-9469-9a18bd4d8a72\",\"trace_id\":\"3ca2e911-32f2-4c22-89ba-aae5e8342c8d\"}\n[2026-05-07 13:22:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b99dafc3-0e7f-4cb3-9469-9a18bd4d8a72\",\"trace_id\":\"3ca2e911-32f2-4c22-89ba-aae5e8342c8d\"}\n[2026-05-07 13:22:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b8b1efaa-e359-4aa1-942d-2dc8ca6c048b\",\"trace_id\":\"897fc576-4657-4534-ac78-73f6c44cbeef\"}\n[2026-05-07 13:22:41] local.INFO: Running conference:monitor:count command for activities in (2026-05-07 13:20:00, 2026-05-07 13:22:00] {\"correlation_id\":\"b8b1efaa-e359-4aa1-942d-2dc8ca6c048b\",\"trace_id\":\"897fc576-4657-4534-ac78-73f6c44cbeef\"}\n[2026-05-07 13:22:41] local.INFO: [conference:monitor:count] No activities found in (2026-05-07 13:20:00, 2026-05-07 13:22:00] {\"correlation_id\":\"b8b1efaa-e359-4aa1-942d-2dc8ca6c048b\",\"trace_id\":\"897fc576-4657-4534-ac78-73f6c44cbeef\"}\n[2026-05-07 13:22:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b8b1efaa-e359-4aa1-942d-2dc8ca6c048b\",\"trace_id\":\"897fc576-4657-4534-ac78-73f6c44cbeef\"}\n[2026-05-07 13:22:49] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"08dc0025-4642-4d21-a351-c0dee099d6fc\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:49] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"08dc0025-4642-4d21-a351-c0dee099d6fc\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:49] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"08dc0025-4642-4d21-a351-c0dee099d6fc\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:49] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"08dc0025-4642-4d21-a351-c0dee099d6fc\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:52] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 2 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"13eed139-b218-43c9-b147-38ae92c45977\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:53] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"cf9df816-4614-4a06-b853-4d6815fb85e1\",\"trace_id\":\"ca6ed313-c21f-4683-8b5b-013a3ecd4081\"}\n[2026-05-07 13:22:53] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"cf9df816-4614-4a06-b853-4d6815fb85e1\",\"trace_id\":\"ca6ed313-c21f-4683-8b5b-013a3ecd4081\"}\n[2026-05-07 13:22:57] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"twilio:recover-tracks\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"93d3bd4f-fe02-4d22-aab9-00c74309e94c\",\"trace_id\":\"356db0f7-0c25-4739-8c8b-a55ba28e1df0\"}\n[2026-05-07 13:22:57] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"twilio:recover-tracks\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"93d3bd4f-fe02-4d22-aab9-00c74309e94c\",\"trace_id\":\"356db0f7-0c25-4739-8c8b-a55ba28e1df0\"}\n[2026-05-07 13:23:00] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:sync-users\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"connect-and-sell\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Start user synchronisation {\"provider\":\"justcall\",\"teams_count\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Synchronising team {\"provider\":\"justcall\",\"team_id\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.WARNING: [Salesforce] Account not connected for user {\"userId\":\"cdf9285a-8ded-4a8b-bd7d-ec68c398f2f9\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":1367,\"sociable_id\":1071,\"provider_user_id\":\"005O4000003s5c7IAA\",\"expires\":null,\"refresh_token_expires\":null,\"provider\":\"salesforce\",\"state\":\"full-refresh\",\"auth_scope\":\"refresh_token web api\",\"retry_after\":null,\"created_at\":\"2024-09-10 07:05:21\",\"updated_at\":\"2026-01-14 07:00:58\"}}} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"salesforce\",\"crm_owner\":1071,\"team_id\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"salesforce\",\"team_id\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"salesforce\",\"team_id\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.WARNING: Failed to sync external users {\"message\":\"Your Salesforce account has become disconnected. Please login to Jiminny to reconnect.\",\"provider\":\"justcall\",\"team_id\":1,\"team\":\"jiminny\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"ringcentral\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"avaya\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"telus\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"salesloft\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"talkdesk\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"vonage\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Done {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:sync-users\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}","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":"1","depth":4,"bounds":{"left":0.3394282,"top":0.2490024,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.3487367,"top":0.2490024,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"69","depth":4,"bounds":{"left":0.3587101,"top":0.2490024,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.37101063,"top":0.2490024,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.3806516,"top":0.24740623,"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.3879654,"top":0.24740623,"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\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Component\\Utility\\Service\\ProviderRateLimiter;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n private ProviderRateLimiter $rateLimiter;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n ProviderRateLimiter $rateLimiter,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n $this->rateLimiter = $rateLimiter;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Single entry point for every HubSpot API call. Enforces the per-portal\n * rate limit configured in the rate_limits table (morphed to the current\n * Configuration) and reacts to a real 429 from HubSpot by translating it\n * into a RateLimitException carrying Retry-After.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n if (! $this->rateLimiter->canMakeRequest($this->config)) {\n $retryAfter = $this->rateLimiter->requestAvailableIn($this->config);\n\n $this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n ]);\n\n throw new RateLimitException(\n 'Hubspot rate limit reached for configuration ' . $this->config->getId(),\n $retryAfter,\n );\n }\n\n $this->rateLimiter->incrementRequestCount($this->config);\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n return method_exists($e, 'getCode') && (int) $e->getCode() === 429;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $this->log->info('[Hubspot] DEBUG Getting headers', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$headers ' . PHP_EOL . print_r($headers, true));\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n\n $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n $body = json_decode((string) $response->getBody(), true);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Component\\Utility\\Service\\ProviderRateLimiter;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n private ProviderRateLimiter $rateLimiter;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n ProviderRateLimiter $rateLimiter,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n $this->rateLimiter = $rateLimiter;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Single entry point for every HubSpot API call. Enforces the per-portal\n * rate limit configured in the rate_limits table (morphed to the current\n * Configuration) and reacts to a real 429 from HubSpot by translating it\n * into a RateLimitException carrying Retry-After.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n if (! $this->rateLimiter->canMakeRequest($this->config)) {\n $retryAfter = $this->rateLimiter->requestAvailableIn($this->config);\n\n $this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n ]);\n\n throw new RateLimitException(\n 'Hubspot rate limit reached for configuration ' . $this->config->getId(),\n $retryAfter,\n );\n }\n\n $this->rateLimiter->incrementRequestCount($this->config);\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n return method_exists($e, 'getCode') && (int) $e->getCode() === 429;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $this->log->info('[Hubspot] DEBUG Getting headers', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$headers ' . PHP_EOL . print_r($headers, true));\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n\n $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n $body = json_decode((string) $response->getBody(), true);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"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}]...
|
-7753210734642263226
|
6593672105841920124
|
click
|
accessibility
|
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
195
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1499,"provider":"hubspot","refreshToken":"96f94c623a404e02ebdbf07f1b75707bb6cdbf848cbf45d418baf608c41a8d86","state":"connected"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [SocialAccountObserver] Access token was modified, encrypting {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:13] local.INFO: [SocialAccountService] Token refreshed {"socialAccountId":1499,"provider":"hubspot","state":"connected"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:13] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:13] local.INFO: [Hubspot] Received 429 from API {"team_id":2,"config_id":2,"retry_after":10,"reason":"Client error: `POST [URL_WITH_CREDENTIALS] CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
if (! $this->rateLimiter->canMakeRequest($this->config)) {
$retryAfter = $this->rateLimiter->requestAvailableIn($this->config);
$this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
]);
throw new RateLimitException(
'Hubspot rate limit reached for configuration ' . $this->config->getId(),
$retryAfter,
);
}
$this->rateLimiter->incrementRequestCount($this->config);
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
public function isHubspotRateLimit(Throwable $e): bool
{
return method_exists($e, 'getCode') && (int) $e->getCode() === 429;
}
public function parseRetryAfter(Throwable $e): int
{
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$this->log->info('[Hubspot] DEBUG Getting headers', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$headers ' . PHP_EOL . print_r($headers, true));
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch ...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
4290
|
153
|
15
|
2026-05-07T13:23:50.384100+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778160230384_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
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
195
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1499,"provider":"hubspot","refreshToken":"96f94c623a404e02ebdbf07f1b75707bb6cdbf848cbf45d418baf608c41a8d86","state":"connected"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [SocialAccountObserver] Access token was modified, encrypting {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:13] local.INFO: [SocialAccountService] Token refreshed {"socialAccountId":1499,"provider":"hubspot","state":"connected"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:13] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:13] local.INFO: [Hubspot] Received 429 from API {"team_id":2,"config_id":2,"retry_after":10,"reason":"Client error: `POST [URL_WITH_CREDENTIALS] CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
if (! $this->rateLimiter->canMakeRequest($this->config)) {
$retryAfter = $this->rateLimiter->requestAvailableIn($this->config);
$this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
]);
throw new RateLimitException(
'Hubspot rate limit reached for configuration ' . $this->config->getId(),
$retryAfter,
);
}
$this->rateLimiter->incrementRequestCount($this->config);
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
public function isHubspotRateLimit(Throwable $e): bool
{
return method_exists($e, 'getCode') && (int) $e->getCode() === 429;
}
public function parseRetryAfter(Throwable $e): int
{
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$this->log->info('[Hubspot] DEBUG Getting headers', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$headers ' . PHP_EOL . print_r($headers, true));
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch ...
|
[{"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},{"role":"AXStaticText","text":"195","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-07 13:22:12] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1499,\"provider\":\"hubspot\",\"refreshToken\":\"96f94c623a404e02ebdbf07f1b75707bb6cdbf848cbf45d418baf608c41a8d86\",\"state\":\"connected\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [SocialAccountObserver] Access token was modified, encrypting {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.INFO: [SocialAccountService] Token refreshed {\"socialAccountId\":1499,\"provider\":\"hubspot\",\"state\":\"connected\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.INFO: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e029a-6 (truncated...)\n\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.ERROR: Hubspot returned 429 {\"exception\":\"[object] (Jiminny\\\\Exceptions\\\\RateLimitException(code: 0): Hubspot returned 429 at /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php:206)\n[stacktrace]\n#0 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(52): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->executeSearchRequest(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), 'https://api.hub...', Array, Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\PaginationState))\n#1 /home/jiminny/app/Services/Crm/Hubspot/Client.php(176): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->getPaginatedDataGenerator(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), Array, 'contact', 0, 0, NULL)\n#2 /home/jiminny/app/Services/Crm/Hubspot/Service.php(1203): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client->getPaginatedData(Array, 'contact')\n#3 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(353): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Service->matchByName('Robot')\n#4 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(44): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->rateLimit()\n#5 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->handle(Object(Jiminny\\\\Jobs\\\\JobDispatcher), Object(Jiminny\\\\Services\\\\Kiosk\\\\AutomatedReports\\\\AutomatedReportsService), Object(Jiminny\\\\Repositories\\\\AutomatedReportsRepository), Object(Jiminny\\\\Services\\\\UserPilot\\\\UserPilotClient))\n#6 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Util.php(43): Illuminate\\\\Container\\\\BoundMethod::Illuminate\\\\Container\\\\{closure}()\n#7 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(96): Illuminate\\\\Container\\\\Util::unwrapIfClosure(Object(Closure))\n#8 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(35): Illuminate\\\\Container\\\\BoundMethod::callBoundMethod(Object(Illuminate\\\\Foundation\\\\Application), Array, Object(Closure))\n#9 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Container.php(799): Illuminate\\\\Container\\\\BoundMethod::call(Object(Illuminate\\\\Foundation\\\\Application), Array, Array, NULL)\n#10 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(211): Illuminate\\\\Container\\\\Container->call(Array)\n#11 /home/jiminny/vendor/symfony/console/Command/Command.php(341): Illuminate\\\\Console\\\\Command->execute(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#12 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(180): Symfony\\\\Component\\\\Console\\\\Command\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#13 /home/jiminny/vendor/symfony/console/Application.php(1117): Illuminate\\\\Console\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#14 /home/jiminny/vendor/symfony/console/Application.php(356): Symfony\\\\Component\\\\Console\\\\Application->doRunCommand(Object(Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand), Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#15 /home/jiminny/vendor/symfony/console/Application.php(195): Symfony\\\\Component\\\\Console\\\\Application->doRun(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#16 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(198): Symfony\\\\Component\\\\Console\\\\Application->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#17 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(1235): Illuminate\\\\Foundation\\\\Console\\\\Kernel->handle(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#18 /home/jiminny/artisan(13): Illuminate\\\\Foundation\\\\Application->handleCommand(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput))\n#19 {main}\n\n[previous exception] [object] (SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest(code: 429): Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e029a-6 (truncated...)\n at /home/jiminny/vendor/hubspot/hubspot-php/src/Exceptions/HubspotException.php:24)\n[stacktrace]\n#0 /home/jiminny/vendor/hubspot/hubspot-php/src/Http/Client.php(125): SevenShores\\\\Hubspot\\\\Exceptions\\\\HubspotException::create(Object(GuzzleHttp\\\\Exception\\\\ClientException))\n#1 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(166): SevenShores\\\\Hubspot\\\\Http\\\\Client->request('POST', 'https://api.hub...', Array)\n#2 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(52): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->executeSearchRequest(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), 'https://api.hub...', Array, Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\PaginationState))\n#3 /home/jiminny/app/Services/Crm/Hubspot/Client.php(176): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->getPaginatedDataGenerator(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), Array, 'contact', 0, 0, NULL)\n#4 /home/jiminny/app/Services/Crm/Hubspot/Service.php(1203): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client->getPaginatedData(Array, 'contact')\n#5 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(353): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Service->matchByName('Robot')\n#6 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(44): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->rateLimit()\n#7 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->handle(Object(Jiminny\\\\Jobs\\\\JobDispatcher), Object(Jiminny\\\\Services\\\\Kiosk\\\\AutomatedReports\\\\AutomatedReportsService), Object(Jiminny\\\\Repositories\\\\AutomatedReportsRepository), Object(Jiminny\\\\Services\\\\UserPilot\\\\UserPilotClient))\n#8 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Util.php(43): Illuminate\\\\Container\\\\BoundMethod::Illuminate\\\\Container\\\\{closure}()\n#9 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(96): Illuminate\\\\Container\\\\Util::unwrapIfClosure(Object(Closure))\n#10 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(35): Illuminate\\\\Container\\\\BoundMethod::callBoundMethod(Object(Illuminate\\\\Foundation\\\\Application), Array, Object(Closure))\n#11 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Container.php(799): Illuminate\\\\Container\\\\BoundMethod::call(Object(Illuminate\\\\Foundation\\\\Application), Array, Array, NULL)\n#12 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(211): Illuminate\\\\Container\\\\Container->call(Array)\n#13 /home/jiminny/vendor/symfony/console/Command/Command.php(341): Illuminate\\\\Console\\\\Command->execute(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#14 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(180): Symfony\\\\Component\\\\Console\\\\Command\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#15 /home/jiminny/vendor/symfony/console/Application.php(1117): Illuminate\\\\Console\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#16 /home/jiminny/vendor/symfony/console/Application.php(356): Symfony\\\\Component\\\\Console\\\\Application->doRunCommand(Object(Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand), Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#17 /home/jiminny/vendor/symfony/console/Application.php(195): Symfony\\\\Component\\\\Console\\\\Application->doRun(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#18 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(198): Symfony\\\\Component\\\\Console\\\\Application->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#19 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(1235): Illuminate\\\\Foundation\\\\Console\\\\Kernel->handle(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#20 /home/jiminny/artisan(13): Illuminate\\\\Foundation\\\\Application->handleCommand(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput))\n#21 {main}\n\n[previous exception] [object] (GuzzleHttp\\\\Exception\\\\ClientException(code: 429): Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e029a-6 (truncated...)\n at /home/jiminny/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php:111)\n[stacktrace]\n#0 /home/jiminny/vendor/guzzlehttp/guzzle/src/Middleware.php(72): GuzzleHttp\\\\Exception\\\\RequestException::create(Object(GuzzleHttp\\\\Psr7\\\\Request), Object(GuzzleHttp\\\\Psr7\\\\Response), NULL, Array, NULL)\n#1 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(209): GuzzleHttp\\\\Middleware::GuzzleHttp\\\\{closure}(Object(GuzzleHttp\\\\Psr7\\\\Response))\n#2 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(158): GuzzleHttp\\\\Promise\\\\Promise::callHandler(1, Object(GuzzleHttp\\\\Psr7\\\\Response), NULL)\n#3 /home/jiminny/vendor/guzzlehttp/promises/src/TaskQueue.php(52): GuzzleHttp\\\\Promise\\\\Promise::GuzzleHttp\\\\Promise\\\\{closure}()\n#4 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(251): GuzzleHttp\\\\Promise\\\\TaskQueue->run(true)\n#5 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(227): GuzzleHttp\\\\Promise\\\\Promise->invokeWaitFn()\n#6 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(272): GuzzleHttp\\\\Promise\\\\Promise->waitIfPending()\n#7 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(229): GuzzleHttp\\\\Promise\\\\Promise->invokeWaitList()\n#8 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(69): GuzzleHttp\\\\Promise\\\\Promise->waitIfPending()\n#9 /home/jiminny/vendor/guzzlehttp/guzzle/src/Client.php(189): GuzzleHttp\\\\Promise\\\\Promise->wait()\n#10 /home/jiminny/vendor/hubspot/hubspot-php/src/Http/Client.php(113): GuzzleHttp\\\\Client->request('POST', 'https://api.hub...', Array)\n#11 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(166): SevenShores\\\\Hubspot\\\\Http\\\\Client->request('POST', 'https://api.hub...', Array)\n#12 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(52): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->executeSearchRequest(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), 'https://api.hub...', Array, Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\PaginationState))\n#13 /home/jiminny/app/Services/Crm/Hubspot/Client.php(176): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->getPaginatedDataGenerator(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), Array, 'contact', 0, 0, NULL)\n#14 /home/jiminny/app/Services/Crm/Hubspot/Service.php(1203): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client->getPaginatedData(Array, 'contact')\n#15 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(353): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Service->matchByName('Robot')\n#16 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(44): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->rateLimit()\n#17 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->handle(Object(Jiminny\\\\Jobs\\\\JobDispatcher), Object(Jiminny\\\\Services\\\\Kiosk\\\\AutomatedReports\\\\AutomatedReportsService), Object(Jiminny\\\\Repositories\\\\AutomatedReportsRepository), Object(Jiminny\\\\Services\\\\UserPilot\\\\UserPilotClient))\n#18 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Util.php(43): Illuminate\\\\Container\\\\BoundMethod::Illuminate\\\\Container\\\\{closure}()\n#19 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(96): Illuminate\\\\Container\\\\Util::unwrapIfClosure(Object(Closure))\n#20 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(35): Illuminate\\\\Container\\\\BoundMethod::callBoundMethod(Object(Illuminate\\\\Foundation\\\\Application), Array, Object(Closure))\n#21 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Container.php(799): Illuminate\\\\Container\\\\BoundMethod::call(Object(Illuminate\\\\Foundation\\\\Application), Array, Array, NULL)\n#22 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(211): Illuminate\\\\Container\\\\Container->call(Array)\n#23 /home/jiminny/vendor/symfony/console/Command/Command.php(341): Illuminate\\\\Console\\\\Command->execute(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#24 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(180): Symfony\\\\Component\\\\Console\\\\Command\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#25 /home/jiminny/vendor/symfony/console/Application.php(1117): Illuminate\\\\Console\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#26 /home/jiminny/vendor/symfony/console/Application.php(356): Symfony\\\\Component\\\\Console\\\\Application->doRunCommand(Object(Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand), Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#27 /home/jiminny/vendor/symfony/console/Application.php(195): Symfony\\\\Component\\\\Console\\\\Application->doRun(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#28 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(198): Symfony\\\\Component\\\\Console\\\\Application->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#29 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(1235): Illuminate\\\\Foundation\\\\Console\\\\Kernel->handle(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#30 /home/jiminny/artisan(13): Illuminate\\\\Foundation\\\\Application->handleCommand(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput))\n#31 {main}\n\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"42c3d939-2b42-4fa8-9f57-cbdc5bb1457c\",\"trace_id\":\"b9aec736-45fd-47fc-9482-fd558ed6227a\"}\n[2026-05-07 13:22:13] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"42c3d939-2b42-4fa8-9f57-cbdc5bb1457c\",\"trace_id\":\"b9aec736-45fd-47fc-9482-fd558ed6227a\"}\n[2026-05-07 13:22:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"42c3d939-2b42-4fa8-9f57-cbdc5bb1457c\",\"trace_id\":\"b9aec736-45fd-47fc-9482-fd558ed6227a\"}\n[2026-05-07 13:22:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"076c3e6b-6a67-4774-8aa0-2a84fcf5e03c\",\"trace_id\":\"284e571d-ab92-4e22-b09b-c151c2871cb4\"}\n[2026-05-07 13:22:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"076c3e6b-6a67-4774-8aa0-2a84fcf5e03c\",\"trace_id\":\"284e571d-ab92-4e22-b09b-c151c2871cb4\"}\n[2026-05-07 13:22:19] local.NOTICE: Monitoring start {\"correlation_id\":\"c41d4048-0465-4dcf-bb53-176287732e3e\",\"trace_id\":\"9ce4a71c-a1a0-456e-843d-38fd15e5c798\"}\n[2026-05-07 13:22:19] local.NOTICE: Monitoring end {\"correlation_id\":\"c41d4048-0465-4dcf-bb53-176287732e3e\",\"trace_id\":\"9ce4a71c-a1a0-456e-843d-38fd15e5c798\"}\n[2026-05-07 13:22:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"934766d6-40c0-415c-bd51-d0b67a799c7c\",\"trace_id\":\"d6c773e8-adf4-453b-8a17-077bf7bdf698\"}\n[2026-05-07 13:22:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"934766d6-40c0-415c-bd51-d0b67a799c7c\",\"trace_id\":\"d6c773e8-adf4-453b-8a17-077bf7bdf698\"}\n[2026-05-07 13:22:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b99dafc3-0e7f-4cb3-9469-9a18bd4d8a72\",\"trace_id\":\"3ca2e911-32f2-4c22-89ba-aae5e8342c8d\"}\n[2026-05-07 13:22:35] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b99dafc3-0e7f-4cb3-9469-9a18bd4d8a72\",\"trace_id\":\"3ca2e911-32f2-4c22-89ba-aae5e8342c8d\"}\n[2026-05-07 13:22:35] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"b99dafc3-0e7f-4cb3-9469-9a18bd4d8a72\",\"trace_id\":\"3ca2e911-32f2-4c22-89ba-aae5e8342c8d\"}\n[2026-05-07 13:22:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b99dafc3-0e7f-4cb3-9469-9a18bd4d8a72\",\"trace_id\":\"3ca2e911-32f2-4c22-89ba-aae5e8342c8d\"}\n[2026-05-07 13:22:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b8b1efaa-e359-4aa1-942d-2dc8ca6c048b\",\"trace_id\":\"897fc576-4657-4534-ac78-73f6c44cbeef\"}\n[2026-05-07 13:22:41] local.INFO: Running conference:monitor:count command for activities in (2026-05-07 13:20:00, 2026-05-07 13:22:00] {\"correlation_id\":\"b8b1efaa-e359-4aa1-942d-2dc8ca6c048b\",\"trace_id\":\"897fc576-4657-4534-ac78-73f6c44cbeef\"}\n[2026-05-07 13:22:41] local.INFO: [conference:monitor:count] No activities found in (2026-05-07 13:20:00, 2026-05-07 13:22:00] {\"correlation_id\":\"b8b1efaa-e359-4aa1-942d-2dc8ca6c048b\",\"trace_id\":\"897fc576-4657-4534-ac78-73f6c44cbeef\"}\n[2026-05-07 13:22:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b8b1efaa-e359-4aa1-942d-2dc8ca6c048b\",\"trace_id\":\"897fc576-4657-4534-ac78-73f6c44cbeef\"}\n[2026-05-07 13:22:49] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"08dc0025-4642-4d21-a351-c0dee099d6fc\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:49] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"08dc0025-4642-4d21-a351-c0dee099d6fc\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:49] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"08dc0025-4642-4d21-a351-c0dee099d6fc\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:49] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"08dc0025-4642-4d21-a351-c0dee099d6fc\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:52] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 2 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"13eed139-b218-43c9-b147-38ae92c45977\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:53] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"cf9df816-4614-4a06-b853-4d6815fb85e1\",\"trace_id\":\"ca6ed313-c21f-4683-8b5b-013a3ecd4081\"}\n[2026-05-07 13:22:53] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"cf9df816-4614-4a06-b853-4d6815fb85e1\",\"trace_id\":\"ca6ed313-c21f-4683-8b5b-013a3ecd4081\"}\n[2026-05-07 13:22:57] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"twilio:recover-tracks\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"93d3bd4f-fe02-4d22-aab9-00c74309e94c\",\"trace_id\":\"356db0f7-0c25-4739-8c8b-a55ba28e1df0\"}\n[2026-05-07 13:22:57] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"twilio:recover-tracks\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"93d3bd4f-fe02-4d22-aab9-00c74309e94c\",\"trace_id\":\"356db0f7-0c25-4739-8c8b-a55ba28e1df0\"}\n[2026-05-07 13:23:00] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:sync-users\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"connect-and-sell\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Start user synchronisation {\"provider\":\"justcall\",\"teams_count\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Synchronising team {\"provider\":\"justcall\",\"team_id\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.WARNING: [Salesforce] Account not connected for user {\"userId\":\"cdf9285a-8ded-4a8b-bd7d-ec68c398f2f9\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":1367,\"sociable_id\":1071,\"provider_user_id\":\"005O4000003s5c7IAA\",\"expires\":null,\"refresh_token_expires\":null,\"provider\":\"salesforce\",\"state\":\"full-refresh\",\"auth_scope\":\"refresh_token web api\",\"retry_after\":null,\"created_at\":\"2024-09-10 07:05:21\",\"updated_at\":\"2026-01-14 07:00:58\"}}} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"salesforce\",\"crm_owner\":1071,\"team_id\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"salesforce\",\"team_id\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"salesforce\",\"team_id\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.WARNING: Failed to sync external users {\"message\":\"Your Salesforce account has become disconnected. Please login to Jiminny to reconnect.\",\"provider\":\"justcall\",\"team_id\":1,\"team\":\"jiminny\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"ringcentral\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"avaya\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"telus\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"salesloft\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"talkdesk\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"vonage\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Done {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:sync-users\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}","depth":4,"on_screen":true,"value":"[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Fetching token {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Token needs refreshing {\"socialAccountId\":1499,\"provider\":\"hubspot\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [EncryptedTokenManager] Generating access token. {\"mode\":\"legacy\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Refreshing token from provider {\"socialAccountId\":1499,\"provider\":\"hubspot\",\"refreshToken\":\"96f94c623a404e02ebdbf07f1b75707bb6cdbf848cbf45d418baf608c41a8d86\",\"state\":\"connected\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [SocialAccountObserver] Saving model {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:12] local.INFO: [SocialAccountObserver] Access token was modified, encrypting {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.INFO: [SocialAccountService] Token refreshed {\"socialAccountId\":1499,\"provider\":\"hubspot\",\"state\":\"connected\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {\"crm_provider\":\"hubspot\",\"crm_owner\":148,\"team_id\":2} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.INFO: [Hubspot] Received 429 from API {\"team_id\":2,\"config_id\":2,\"retry_after\":10,\"reason\":\"Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e029a-6 (truncated...)\n\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.ERROR: Hubspot returned 429 {\"exception\":\"[object] (Jiminny\\\\Exceptions\\\\RateLimitException(code: 0): Hubspot returned 429 at /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php:206)\n[stacktrace]\n#0 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(52): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->executeSearchRequest(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), 'https://api.hub...', Array, Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\PaginationState))\n#1 /home/jiminny/app/Services/Crm/Hubspot/Client.php(176): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->getPaginatedDataGenerator(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), Array, 'contact', 0, 0, NULL)\n#2 /home/jiminny/app/Services/Crm/Hubspot/Service.php(1203): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client->getPaginatedData(Array, 'contact')\n#3 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(353): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Service->matchByName('Robot')\n#4 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(44): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->rateLimit()\n#5 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->handle(Object(Jiminny\\\\Jobs\\\\JobDispatcher), Object(Jiminny\\\\Services\\\\Kiosk\\\\AutomatedReports\\\\AutomatedReportsService), Object(Jiminny\\\\Repositories\\\\AutomatedReportsRepository), Object(Jiminny\\\\Services\\\\UserPilot\\\\UserPilotClient))\n#6 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Util.php(43): Illuminate\\\\Container\\\\BoundMethod::Illuminate\\\\Container\\\\{closure}()\n#7 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(96): Illuminate\\\\Container\\\\Util::unwrapIfClosure(Object(Closure))\n#8 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(35): Illuminate\\\\Container\\\\BoundMethod::callBoundMethod(Object(Illuminate\\\\Foundation\\\\Application), Array, Object(Closure))\n#9 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Container.php(799): Illuminate\\\\Container\\\\BoundMethod::call(Object(Illuminate\\\\Foundation\\\\Application), Array, Array, NULL)\n#10 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(211): Illuminate\\\\Container\\\\Container->call(Array)\n#11 /home/jiminny/vendor/symfony/console/Command/Command.php(341): Illuminate\\\\Console\\\\Command->execute(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#12 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(180): Symfony\\\\Component\\\\Console\\\\Command\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#13 /home/jiminny/vendor/symfony/console/Application.php(1117): Illuminate\\\\Console\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#14 /home/jiminny/vendor/symfony/console/Application.php(356): Symfony\\\\Component\\\\Console\\\\Application->doRunCommand(Object(Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand), Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#15 /home/jiminny/vendor/symfony/console/Application.php(195): Symfony\\\\Component\\\\Console\\\\Application->doRun(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#16 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(198): Symfony\\\\Component\\\\Console\\\\Application->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#17 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(1235): Illuminate\\\\Foundation\\\\Console\\\\Kernel->handle(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#18 /home/jiminny/artisan(13): Illuminate\\\\Foundation\\\\Application->handleCommand(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput))\n#19 {main}\n\n[previous exception] [object] (SevenShores\\\\Hubspot\\\\Exceptions\\\\BadRequest(code: 429): Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e029a-6 (truncated...)\n at /home/jiminny/vendor/hubspot/hubspot-php/src/Exceptions/HubspotException.php:24)\n[stacktrace]\n#0 /home/jiminny/vendor/hubspot/hubspot-php/src/Http/Client.php(125): SevenShores\\\\Hubspot\\\\Exceptions\\\\HubspotException::create(Object(GuzzleHttp\\\\Exception\\\\ClientException))\n#1 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(166): SevenShores\\\\Hubspot\\\\Http\\\\Client->request('POST', 'https://api.hub...', Array)\n#2 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(52): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->executeSearchRequest(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), 'https://api.hub...', Array, Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\PaginationState))\n#3 /home/jiminny/app/Services/Crm/Hubspot/Client.php(176): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->getPaginatedDataGenerator(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), Array, 'contact', 0, 0, NULL)\n#4 /home/jiminny/app/Services/Crm/Hubspot/Service.php(1203): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client->getPaginatedData(Array, 'contact')\n#5 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(353): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Service->matchByName('Robot')\n#6 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(44): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->rateLimit()\n#7 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->handle(Object(Jiminny\\\\Jobs\\\\JobDispatcher), Object(Jiminny\\\\Services\\\\Kiosk\\\\AutomatedReports\\\\AutomatedReportsService), Object(Jiminny\\\\Repositories\\\\AutomatedReportsRepository), Object(Jiminny\\\\Services\\\\UserPilot\\\\UserPilotClient))\n#8 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Util.php(43): Illuminate\\\\Container\\\\BoundMethod::Illuminate\\\\Container\\\\{closure}()\n#9 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(96): Illuminate\\\\Container\\\\Util::unwrapIfClosure(Object(Closure))\n#10 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(35): Illuminate\\\\Container\\\\BoundMethod::callBoundMethod(Object(Illuminate\\\\Foundation\\\\Application), Array, Object(Closure))\n#11 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Container.php(799): Illuminate\\\\Container\\\\BoundMethod::call(Object(Illuminate\\\\Foundation\\\\Application), Array, Array, NULL)\n#12 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(211): Illuminate\\\\Container\\\\Container->call(Array)\n#13 /home/jiminny/vendor/symfony/console/Command/Command.php(341): Illuminate\\\\Console\\\\Command->execute(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#14 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(180): Symfony\\\\Component\\\\Console\\\\Command\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#15 /home/jiminny/vendor/symfony/console/Application.php(1117): Illuminate\\\\Console\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#16 /home/jiminny/vendor/symfony/console/Application.php(356): Symfony\\\\Component\\\\Console\\\\Application->doRunCommand(Object(Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand), Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#17 /home/jiminny/vendor/symfony/console/Application.php(195): Symfony\\\\Component\\\\Console\\\\Application->doRun(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#18 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(198): Symfony\\\\Component\\\\Console\\\\Application->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#19 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(1235): Illuminate\\\\Foundation\\\\Console\\\\Kernel->handle(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#20 /home/jiminny/artisan(13): Illuminate\\\\Foundation\\\\Application->handleCommand(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput))\n#21 {main}\n\n[previous exception] [object] (GuzzleHttp\\\\Exception\\\\ClientException(code: 429): Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response:\n{\\\"status\\\":\\\"error\\\",\\\"message\\\":\\\"You have reached your secondly limit.\\\",\\\"errorType\\\":\\\"RATE_LIMIT\\\",\\\"correlationId\\\":\\\"019e029a-6 (truncated...)\n at /home/jiminny/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php:111)\n[stacktrace]\n#0 /home/jiminny/vendor/guzzlehttp/guzzle/src/Middleware.php(72): GuzzleHttp\\\\Exception\\\\RequestException::create(Object(GuzzleHttp\\\\Psr7\\\\Request), Object(GuzzleHttp\\\\Psr7\\\\Response), NULL, Array, NULL)\n#1 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(209): GuzzleHttp\\\\Middleware::GuzzleHttp\\\\{closure}(Object(GuzzleHttp\\\\Psr7\\\\Response))\n#2 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(158): GuzzleHttp\\\\Promise\\\\Promise::callHandler(1, Object(GuzzleHttp\\\\Psr7\\\\Response), NULL)\n#3 /home/jiminny/vendor/guzzlehttp/promises/src/TaskQueue.php(52): GuzzleHttp\\\\Promise\\\\Promise::GuzzleHttp\\\\Promise\\\\{closure}()\n#4 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(251): GuzzleHttp\\\\Promise\\\\TaskQueue->run(true)\n#5 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(227): GuzzleHttp\\\\Promise\\\\Promise->invokeWaitFn()\n#6 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(272): GuzzleHttp\\\\Promise\\\\Promise->waitIfPending()\n#7 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(229): GuzzleHttp\\\\Promise\\\\Promise->invokeWaitList()\n#8 /home/jiminny/vendor/guzzlehttp/promises/src/Promise.php(69): GuzzleHttp\\\\Promise\\\\Promise->waitIfPending()\n#9 /home/jiminny/vendor/guzzlehttp/guzzle/src/Client.php(189): GuzzleHttp\\\\Promise\\\\Promise->wait()\n#10 /home/jiminny/vendor/hubspot/hubspot-php/src/Http/Client.php(113): GuzzleHttp\\\\Client->request('POST', 'https://api.hub...', Array)\n#11 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(166): SevenShores\\\\Hubspot\\\\Http\\\\Client->request('POST', 'https://api.hub...', Array)\n#12 /home/jiminny/app/Services/Crm/Hubspot/Pagination/HubspotPaginationService.php(52): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->executeSearchRequest(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), 'https://api.hub...', Array, Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\PaginationState))\n#13 /home/jiminny/app/Services/Crm/Hubspot/Client.php(176): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Pagination\\\\HubspotPaginationService->getPaginatedDataGenerator(Object(Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client), Array, 'contact', 0, 0, NULL)\n#14 /home/jiminny/app/Services/Crm/Hubspot/Service.php(1203): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Client->getPaginatedData(Array, 'contact')\n#15 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(353): Jiminny\\\\Services\\\\Crm\\\\Hubspot\\\\Service->matchByName('Robot')\n#16 /home/jiminny/app/Console/Commands/JiminnyDebugCommand.php(44): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->rateLimit()\n#17 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(36): Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand->handle(Object(Jiminny\\\\Jobs\\\\JobDispatcher), Object(Jiminny\\\\Services\\\\Kiosk\\\\AutomatedReports\\\\AutomatedReportsService), Object(Jiminny\\\\Repositories\\\\AutomatedReportsRepository), Object(Jiminny\\\\Services\\\\UserPilot\\\\UserPilotClient))\n#18 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Util.php(43): Illuminate\\\\Container\\\\BoundMethod::Illuminate\\\\Container\\\\{closure}()\n#19 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(96): Illuminate\\\\Container\\\\Util::unwrapIfClosure(Object(Closure))\n#20 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/BoundMethod.php(35): Illuminate\\\\Container\\\\BoundMethod::callBoundMethod(Object(Illuminate\\\\Foundation\\\\Application), Array, Object(Closure))\n#21 /home/jiminny/vendor/laravel/framework/src/Illuminate/Container/Container.php(799): Illuminate\\\\Container\\\\BoundMethod::call(Object(Illuminate\\\\Foundation\\\\Application), Array, Array, NULL)\n#22 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(211): Illuminate\\\\Container\\\\Container->call(Array)\n#23 /home/jiminny/vendor/symfony/console/Command/Command.php(341): Illuminate\\\\Console\\\\Command->execute(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#24 /home/jiminny/vendor/laravel/framework/src/Illuminate/Console/Command.php(180): Symfony\\\\Component\\\\Console\\\\Command\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Illuminate\\\\Console\\\\OutputStyle))\n#25 /home/jiminny/vendor/symfony/console/Application.php(1117): Illuminate\\\\Console\\\\Command->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#26 /home/jiminny/vendor/symfony/console/Application.php(356): Symfony\\\\Component\\\\Console\\\\Application->doRunCommand(Object(Jiminny\\\\Console\\\\Commands\\\\JiminnyDebugCommand), Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#27 /home/jiminny/vendor/symfony/console/Application.php(195): Symfony\\\\Component\\\\Console\\\\Application->doRun(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#28 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Console/Kernel.php(198): Symfony\\\\Component\\\\Console\\\\Application->run(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#29 /home/jiminny/vendor/laravel/framework/src/Illuminate/Foundation/Application.php(1235): Illuminate\\\\Foundation\\\\Console\\\\Kernel->handle(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput), Object(Symfony\\\\Component\\\\Console\\\\Output\\\\ConsoleOutput))\n#30 /home/jiminny/artisan(13): Illuminate\\\\Foundation\\\\Application->handleCommand(Object(Symfony\\\\Component\\\\Console\\\\Input\\\\ArgvInput))\n#31 {main}\n\"} {\"correlation_id\":\"343f341d-028f-4c8c-9578-252fcde6e04c\",\"trace_id\":\"41071c00-9712-46eb-8acf-d5c4298fea69\"}\n[2026-05-07 13:22:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"42c3d939-2b42-4fa8-9f57-cbdc5bb1457c\",\"trace_id\":\"b9aec736-45fd-47fc-9482-fd558ed6227a\"}\n[2026-05-07 13:22:13] local.INFO: [ScheduleBotCommand] Number of activities to be captured: 0 {\"correlation_id\":\"42c3d939-2b42-4fa8-9f57-cbdc5bb1457c\",\"trace_id\":\"b9aec736-45fd-47fc-9482-fd558ed6227a\"}\n[2026-05-07 13:22:13] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"meeting-bot:schedule-bot\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"42c3d939-2b42-4fa8-9f57-cbdc5bb1457c\",\"trace_id\":\"b9aec736-45fd-47fc-9482-fd558ed6227a\"}\n[2026-05-07 13:22:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"076c3e6b-6a67-4774-8aa0-2a84fcf5e03c\",\"trace_id\":\"284e571d-ab92-4e22-b09b-c151c2871cb4\"}\n[2026-05-07 13:22:17] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:monitor-activities\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"076c3e6b-6a67-4774-8aa0-2a84fcf5e03c\",\"trace_id\":\"284e571d-ab92-4e22-b09b-c151c2871cb4\"}\n[2026-05-07 13:22:19] local.NOTICE: Monitoring start {\"correlation_id\":\"c41d4048-0465-4dcf-bb53-176287732e3e\",\"trace_id\":\"9ce4a71c-a1a0-456e-843d-38fd15e5c798\"}\n[2026-05-07 13:22:19] local.NOTICE: Monitoring end {\"correlation_id\":\"c41d4048-0465-4dcf-bb53-176287732e3e\",\"trace_id\":\"9ce4a71c-a1a0-456e-843d-38fd15e5c798\"}\n[2026-05-07 13:22:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"934766d6-40c0-415c-bd51-d0b67a799c7c\",\"trace_id\":\"d6c773e8-adf4-453b-8a17-077bf7bdf698\"}\n[2026-05-07 13:22:30] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:skip-lists:refresh\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"934766d6-40c0-415c-bd51-d0b67a799c7c\",\"trace_id\":\"d6c773e8-adf4-453b-8a17-077bf7bdf698\"}\n[2026-05-07 13:22:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b99dafc3-0e7f-4cb3-9469-9a18bd4d8a72\",\"trace_id\":\"3ca2e911-32f2-4c22-89ba-aae5e8342c8d\"}\n[2026-05-07 13:22:35] local.INFO: [EmailSchedule] STARTING batch process {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"b99dafc3-0e7f-4cb3-9469-9a18bd4d8a72\",\"trace_id\":\"3ca2e911-32f2-4c22-89ba-aae5e8342c8d\"}\n[2026-05-07 13:22:35] local.INFO: [EmailSchedule] FINISHED batch process {\"host\":\"docker_lamp_1\",\"processed\":0} {\"correlation_id\":\"b99dafc3-0e7f-4cb3-9469-9a18bd4d8a72\",\"trace_id\":\"3ca2e911-32f2-4c22-89ba-aae5e8342c8d\"}\n[2026-05-07 13:22:35] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:process\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b99dafc3-0e7f-4cb3-9469-9a18bd4d8a72\",\"trace_id\":\"3ca2e911-32f2-4c22-89ba-aae5e8342c8d\"}\n[2026-05-07 13:22:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"b8b1efaa-e359-4aa1-942d-2dc8ca6c048b\",\"trace_id\":\"897fc576-4657-4534-ac78-73f6c44cbeef\"}\n[2026-05-07 13:22:41] local.INFO: Running conference:monitor:count command for activities in (2026-05-07 13:20:00, 2026-05-07 13:22:00] {\"correlation_id\":\"b8b1efaa-e359-4aa1-942d-2dc8ca6c048b\",\"trace_id\":\"897fc576-4657-4534-ac78-73f6c44cbeef\"}\n[2026-05-07 13:22:41] local.INFO: [conference:monitor:count] No activities found in (2026-05-07 13:20:00, 2026-05-07 13:22:00] {\"correlation_id\":\"b8b1efaa-e359-4aa1-942d-2dc8ca6c048b\",\"trace_id\":\"897fc576-4657-4534-ac78-73f6c44cbeef\"}\n[2026-05-07 13:22:41] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"conference:monitor:count\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"b8b1efaa-e359-4aa1-942d-2dc8ca6c048b\",\"trace_id\":\"897fc576-4657-4534-ac78-73f6c44cbeef\"}\n[2026-05-07 13:22:49] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"08dc0025-4642-4d21-a351-c0dee099d6fc\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:49] local.INFO: [EmailSchedule] STARTING batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"08dc0025-4642-4d21-a351-c0dee099d6fc\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:49] local.INFO: [EmailSchedule] FINISHED batch create {\"host\":\"docker_lamp_1\"} {\"correlation_id\":\"08dc0025-4642-4d21-a351-c0dee099d6fc\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:49] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"mailbox:batch:create\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"08dc0025-4642-4d21-a351-c0dee099d6fc\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:52] local.INFO: [Jiminny\\Jobs\\Mailbox\\CreateBatches] processed 2 inboxes and created 0 batches {\"userId\":null,\"batchSize\":30,\"maxBatches\":1000} {\"correlation_id\":\"13eed139-b218-43c9-b147-38ae92c45977\",\"trace_id\":\"b0e009f0-3c67-4281-87ce-4ccdc1ab3055\"}\n[2026-05-07 13:22:53] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"cf9df816-4614-4a06-b853-4d6815fb85e1\",\"trace_id\":\"ca6ed313-c21f-4683-8b5b-013a3ecd4081\"}\n[2026-05-07 13:22:53] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"activity:sync\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"cf9df816-4614-4a06-b853-4d6815fb85e1\",\"trace_id\":\"ca6ed313-c21f-4683-8b5b-013a3ecd4081\"}\n[2026-05-07 13:22:57] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"twilio:recover-tracks\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"93d3bd4f-fe02-4d22-aab9-00c74309e94c\",\"trace_id\":\"356db0f7-0c25-4739-8c8b-a55ba28e1df0\"}\n[2026-05-07 13:22:57] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"twilio:recover-tracks\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"93d3bd4f-fe02-4d22-aab9-00c74309e94c\",\"trace_id\":\"356db0f7-0c25-4739-8c8b-a55ba28e1df0\"}\n[2026-05-07 13:23:00] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage before starting command {\"command\":\"dialers:sync-users\",\"memoryBeforeCommandInMb\":62.0,\"memoryPeakBeforeCommandInMb\":99.727} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"connect-and-sell\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Start user synchronisation {\"provider\":\"justcall\",\"teams_count\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Synchronising team {\"provider\":\"justcall\",\"team_id\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.WARNING: [Salesforce] Account not connected for user {\"userId\":\"cdf9285a-8ded-4a8b-bd7d-ec68c398f2f9\",\"account\":{\"Jiminny\\\\Models\\\\SocialAccount\":{\"id\":1367,\"sociable_id\":1071,\"provider_user_id\":\"005O4000003s5c7IAA\",\"expires\":null,\"refresh_token_expires\":null,\"provider\":\"salesforce\",\"state\":\"full-refresh\",\"auth_scope\":\"refresh_token web api\",\"retry_after\":null,\"created_at\":\"2024-09-10 07:05:21\",\"updated_at\":\"2026-01-14 07:00:58\"}}} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: [CrmOwnerResolver] Integration owner is not connected, attempting team members {\"crm_provider\":\"salesforce\",\"crm_owner\":1071,\"team_id\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: [CrmOwnerResolver] No team members found with active crm connection {\"crm_provider\":\"salesforce\",\"team_id\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: [CrmOwnerResolver] No team member found with active crm connection {\"crm_provider\":\"salesforce\",\"team_id\":1} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.WARNING: Failed to sync external users {\"message\":\"Your Salesforce account has become disconnected. Please login to Jiminny to reconnect.\",\"provider\":\"justcall\",\"team_id\":1,\"team\":\"jiminny\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"ringcentral\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"avaya\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"telus\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"salesloft\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"talkdesk\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Skip provider synchronisation, no teams found {\"provider\":\"vonage\"} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Done {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}\n[2026-05-07 13:23:00] local.INFO: Jiminny\\Console\\Commands\\Command::run Memory usage for command {\"command\":\"dialers:sync-users\",\"memoryBeforeCommandInMb\":62.0,\"memoryAfterCommandInMB\":62.0,\"memoryPeakBeforeCommandInMb\":99.727,\"memoryPeakAfterCommandInMB\":99.727} {\"correlation_id\":\"fb2297ef-3768-4c39-a39d-8d56cc5f19fd\",\"trace_id\":\"f5f44e82-383e-4e36-b898-5e6a6bb73621\"}","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":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"69","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","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\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Component\\Utility\\Service\\ProviderRateLimiter;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n private ProviderRateLimiter $rateLimiter;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n ProviderRateLimiter $rateLimiter,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n $this->rateLimiter = $rateLimiter;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Single entry point for every HubSpot API call. Enforces the per-portal\n * rate limit configured in the rate_limits table (morphed to the current\n * Configuration) and reacts to a real 429 from HubSpot by translating it\n * into a RateLimitException carrying Retry-After.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n if (! $this->rateLimiter->canMakeRequest($this->config)) {\n $retryAfter = $this->rateLimiter->requestAvailableIn($this->config);\n\n $this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n ]);\n\n throw new RateLimitException(\n 'Hubspot rate limit reached for configuration ' . $this->config->getId(),\n $retryAfter,\n );\n }\n\n $this->rateLimiter->incrementRequestCount($this->config);\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n return method_exists($e, 'getCode') && (int) $e->getCode() === 429;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $this->log->info('[Hubspot] DEBUG Getting headers', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$headers ' . PHP_EOL . print_r($headers, true));\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n\n $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n $body = json_decode((string) $response->getBody(), true);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Component\\Utility\\Service\\ProviderRateLimiter;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n private ProviderRateLimiter $rateLimiter;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n ProviderRateLimiter $rateLimiter,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n $this->rateLimiter = $rateLimiter;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Single entry point for every HubSpot API call. Enforces the per-portal\n * rate limit configured in the rate_limits table (morphed to the current\n * Configuration) and reacts to a real 429 from HubSpot by translating it\n * into a RateLimitException carrying Retry-After.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n if (! $this->rateLimiter->canMakeRequest($this->config)) {\n $retryAfter = $this->rateLimiter->requestAvailableIn($this->config);\n\n $this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n ]);\n\n throw new RateLimitException(\n 'Hubspot rate limit reached for configuration ' . $this->config->getId(),\n $retryAfter,\n );\n }\n\n $this->rateLimiter->incrementRequestCount($this->config);\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n return method_exists($e, 'getCode') && (int) $e->getCode() === 429;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $this->log->info('[Hubspot] DEBUG Getting headers', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$headers ' . PHP_EOL . print_r($headers, true));\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n\n $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n $body = json_decode((string) $response->getBody(), true);\n\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"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}]...
|
-7753210734642263226
|
6593672105841920124
|
click
|
accessibility
|
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
195
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Fetching token {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Token needs refreshing {"socialAccountId":1499,"provider":"hubspot"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [EncryptedTokenManager] Generating access token. {"mode":"legacy"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [SocialAccountService] Refreshing token from provider {"socialAccountId":1499,"provider":"hubspot","refreshToken":"96f94c623a404e02ebdbf07f1b75707bb6cdbf848cbf45d418baf608c41a8d86","state":"connected"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [SocialAccountObserver] Saving model {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:12] local.INFO: [SocialAccountObserver] Access token was modified, encrypting {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:13] local.INFO: [SocialAccountService] Token refreshed {"socialAccountId":1499,"provider":"hubspot","state":"connected"} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:13] local.INFO: [CrmOwnerResolver] Integration owner matched as CRM Owner {"crm_provider":"hubspot","crm_owner":148,"team_id":2} {"correlation_id":"343f341d-028f-4c8c-9578-252fcde6e04c","trace_id":"41071c00-9712-46eb-8acf-d5c4298fea69"}
[2026-05-07 13:22:13] local.INFO: [Hubspot] Received 429 from API {"team_id":2,"config_id":2,"retry_after":10,"reason":"Client error: `POST [URL_WITH_CREDENTIALS] CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
if (! $this->rateLimiter->canMakeRequest($this->config)) {
$retryAfter = $this->rateLimiter->requestAvailableIn($this->config);
$this->log->warning('[Hubspot] Rate limit exceeded, deferring request', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
]);
throw new RateLimitException(
'Hubspot rate limit reached for configuration ' . $this->config->getId(),
$retryAfter,
);
}
$this->rateLimiter->incrementRequestCount($this->config);
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
public function isHubspotRateLimit(Throwable $e): bool
{
return method_exists($e, 'getCode') && (int) $e->getCode() === 429;
}
public function parseRetryAfter(Throwable $e): int
{
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$this->log->info('[Hubspot] DEBUG Getting headers', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
\Illuminate\Support\Facades\Log::channel('custom_channel')->info('$headers ' . PHP_EOL . print_r($headers, true));
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch ...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
10418
|
NULL
|
0
|
2026-05-08T17:23:19.148804+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778260999148_m2.jpg...
|
iTerm2
|
NULL
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
selectionView$0 N O100% 2Fri 8 May 20:23:1908 000• selectionView$0 N O100% 2Fri 8 May 20:23:1908 000•1|C* Claude Code XдeV PAYMENTS-LOGGER [SSH: NAS]>.claudev backendv prisma> migrationsA schema.prismavSro> routesJs auth.lsJs index.jsJS parser.is# Dockertilepackage.isontrontendD .envenv examole* gitignoreAPI.mdl# docker-compose.ymlG README.mdliJS index.isbackend › src › js index.js › ...const express = require('express');const cors - requtrel corsrconst morgan = requirel morgan);const rateLimit = requirel express-rate-L1mic);const paymentsRouter = require.routes/payments':const & bearerTokenMiddleware, wellKnownRouter y = require('•/auth');const ann = exnresso.const PORT = process.env.PORT || 3001;•use(express. json({ Limit: '16kb' }));Well-known OAuth discovery endpoints (always public)aoonswwennowininolunderr// - OAuth Bearer token auth (skips public paths)— Rate-umit the pubuic lngest endoointconst ingestLimiter = rateLimit‹windowMs: 60 * 1000standardHeaders: true,message: { error: "Too many requests, slow down' },*Claude CodeUse planning mode to talk through bigchanges before a commit. Press (Shift) (Tab)to cycle between modes.app.use("/api/payments', paymentsRouter);res.son status:(_rea, res) »> (ok, cimescamp: new Dace.colsuscrinqd:ann. listan(PORT. "[IP_ADDRESS]' 0) =><PROBLEMSOUTPUTPORTSAdm1nadxP4800PLUS-B5F8:/volume2/docker/oavments-loagersPrefer the Terminal experience? Switch back in Settings. Xexaplin to me how does it weok hre, Mhare are usors stored? Aro theindex.jse Edit automaticallyObash +O@|ax> OUTLINETIMELINESSH: nas @oA0 (o8 SignInA...
|
NULL
|
-7749785516000178521
|
NULL
|
idle
|
ocr
|
NULL
|
selectionView$0 N O100% 2Fri 8 May 20:23:1908 000• selectionView$0 N O100% 2Fri 8 May 20:23:1908 000•1|C* Claude Code XдeV PAYMENTS-LOGGER [SSH: NAS]>.claudev backendv prisma> migrationsA schema.prismavSro> routesJs auth.lsJs index.jsJS parser.is# Dockertilepackage.isontrontendD .envenv examole* gitignoreAPI.mdl# docker-compose.ymlG README.mdliJS index.isbackend › src › js index.js › ...const express = require('express');const cors - requtrel corsrconst morgan = requirel morgan);const rateLimit = requirel express-rate-L1mic);const paymentsRouter = require.routes/payments':const & bearerTokenMiddleware, wellKnownRouter y = require('•/auth');const ann = exnresso.const PORT = process.env.PORT || 3001;•use(express. json({ Limit: '16kb' }));Well-known OAuth discovery endpoints (always public)aoonswwennowininolunderr// - OAuth Bearer token auth (skips public paths)— Rate-umit the pubuic lngest endoointconst ingestLimiter = rateLimit‹windowMs: 60 * 1000standardHeaders: true,message: { error: "Too many requests, slow down' },*Claude CodeUse planning mode to talk through bigchanges before a commit. Press (Shift) (Tab)to cycle between modes.app.use("/api/payments', paymentsRouter);res.son status:(_rea, res) »> (ok, cimescamp: new Dace.colsuscrinqd:ann. listan(PORT. "[IP_ADDRESS]' 0) =><PROBLEMSOUTPUTPORTSAdm1nadxP4800PLUS-B5F8:/volume2/docker/oavments-loagersPrefer the Terminal experience? Switch back in Settings. Xexaplin to me how does it weok hre, Mhare are usors stored? Aro theindex.jse Edit automaticallyObash +O@|ax> OUTLINETIMELINESSH: nas @oA0 (o8 SignInA...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
23239
|
984
|
0
|
2026-05-12T07:40:21.824679+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778571621824_m1.jpg...
|
Slack
|
Steliyan Georgiev (DM) - Jiminny Inc - 4 new items Steliyan Georgiev (DM) - Jiminny Inc - 4 new items - Slack...
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Steliyan Georgiev
Petko Kashinski
Galya Dimitrova
Aneliya Angelova
Stefka Stoyanova
Vasil Vasilev
Nikolay Ivanov
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Ves
Lukas Kovalik
you
Jira Cloud
Toast
Google Calendar
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Steliyan Georgiev
Apr 9th at 10:00:27 AM
10:00 AM
прав си и за двете неща
Apr 9th at 10:00:29 AM
10:00
ще ми трябва
Apr 9th at 10:00:38 AM
10:00
ще ги видя имената да са консистентни
Lukas Kovalik
Apr 9th at 10:10:52 AM
10:10 AM
значи на снаке го направия, и добавя report_name
Steliyan Georgiev
Apr 9th at 10:11:17 AM
10:11 AM
reportName значи щом ще е снейк?
Lukas Kovalik
Apr 9th at 10:18:38 AM
10:18 AM
ами ай така
return [
'user_question' => $automatedReport->getAskAnythingPrompt()?->getContent(),
'callIds' => array_map('strval', $activityIds),
'team_id' => $automatedReport->getTeamId(),
'request_id' => $reportResultUuid,
'callback_url' => $this->getCallbackUrl(),
'report_period' => $this->getReportPeriodName($reportResult),
'report_name' => $automatedReport->getCustomName(),
];
Steliyan Georgiev
Apr 9th at 10:19:15 AM
10:19 AM
обърках се
(edited)
Apr 9th at 10:19:16 AM
10:19
кол?
Lukas Kovalik
Apr 9th at 10:19:30 AM
10:19 AM
да
A huddle happened
Apr 9th at 10:19:45 AM
10:19 AM
You and
Steliyan Georgiev
were in the huddle for
4m
.
Lukas Kovalik
Apr 9th at 10:21:16 AM
10:21 AM
return [
'user_question' => $automatedReport->getAskAnythingPrompt()?->getContent(),
'call_ids' => array_map('strval', $activityIds),
'team_id' => $automatedReport->getTeamId(),
'request_id' => $reportResultUuid,
'callback_url' => $this->getCallbackUrl(),
'report_period' => $this->getReportPeriodName($reportResult),
'report_name' => $automatedReport->getCustomName(),
];
Steliyan Georgiev
Apr 9th at 10:24:06 AM
10:24 AM
това е ПРът
https://github.com/jiminny/prophet/pull/465
https://github.com/jiminny/prophet/pull/465
Lukas Kovalik
Apr 9th at 3:19:47 PM
3:19 PM
Стели трябва ли да направя нещо на staging сега получавам [2026-04-09 11:55:47] staging.ERROR: [AskJiminnyReport:Generate] Error {“automatedReportUuid”:“fa7417aa-538e-49ab-8827-77235637a6f9",“reportUuid”:“058c1c38-4f61-4b06-8ede-5fb73f8942e7",“code”:0,“message”:“Unexpected service error.Client error: `POST
https://prophet.staging.jiminny.com/ask-anything-on-demand/request-report
https://prophet.staging.jiminny.com/ask-anything-on-demand/request-report
` resulted in a `404 Not Found` response:
Apr 9th at 3:19:59 PM...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Petko Kashinski","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ves","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Google Calendar","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Add canvas","depth":18,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Add canvas","depth":20,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Jump to date","depth":22,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Steliyan Georgiev","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 9th at 10:00:27 AM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:00 AM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"прав си и за двете неща","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 9th at 10:00:29 AM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:00","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ще ми трябва","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 9th at 10:00:38 AM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:00","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ще ги видя имената да са консистентни","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 9th at 10:10:52 AM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:10 AM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"значи на снаке го направия, и добавя report_name","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Steliyan Georgiev","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 9th at 10:11:17 AM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:11 AM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"reportName значи щом ще е снейк?","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 9th at 10:18:38 AM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:18 AM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ами ай така","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"return [\n 'user_question' => $automatedReport->getAskAnythingPrompt()?->getContent(),\n 'callIds' => array_map('strval', $activityIds),\n 'team_id' => $automatedReport->getTeamId(),\n 'request_id' => $reportResultUuid,\n 'callback_url' => $this->getCallbackUrl(),\n 'report_period' => $this->getReportPeriodName($reportResult),\n 'report_name' => $automatedReport->getCustomName(),\n ];","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Steliyan Georgiev","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 9th at 10:19:15 AM","depth":23,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:19 AM","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"обърках се","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"(edited)","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Apr 9th at 10:19:16 AM","depth":24,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:19","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"кол?","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 9th at 10:19:30 AM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:19 AM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"да","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"A huddle happened","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 9th at 10:19:45 AM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:19 AM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"You and","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"were in the huddle for","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"4m","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 9th at 10:21:16 AM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:21 AM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"return [\n 'user_question' => $automatedReport->getAskAnythingPrompt()?->getContent(),\n 'call_ids' => array_map('strval', $activityIds),\n 'team_id' => $automatedReport->getTeamId(),\n 'request_id' => $reportResultUuid,\n 'callback_url' => $this->getCallbackUrl(),\n 'report_period' => $this->getReportPeriodName($reportResult),\n 'report_name' => $automatedReport->getCustomName(),\n ];","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Steliyan Georgiev","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 9th at 10:24:06 AM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10:24 AM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"това е ПРът","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://github.com/jiminny/prophet/pull/465","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://github.com/jiminny/prophet/pull/465","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 9th at 3:19:47 PM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3:19 PM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Стели трябва ли да направя нещо на staging сега получавам [2026-04-09 11:55:47] staging.ERROR: [AskJiminnyReport:Generate] Error {“automatedReportUuid”:“fa7417aa-538e-49ab-8827-77235637a6f9\",“reportUuid”:“058c1c38-4f61-4b06-8ede-5fb73f8942e7\",“code”:0,“message”:“Unexpected service error.Client error: `POST","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://prophet.staging.jiminny.com/ask-anything-on-demand/request-report","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://prophet.staging.jiminny.com/ask-anything-on-demand/request-report","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"` resulted in a `404 Not Found` response:","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Apr 9th at 3:19:59 PM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-7749734779391925015
|
-3161544186513128402
|
idle
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Steliyan Georgiev
Petko Kashinski
Galya Dimitrova
Aneliya Angelova
Stefka Stoyanova
Vasil Vasilev
Nikolay Ivanov
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Ves
Lukas Kovalik
you
Jira Cloud
Toast
Google Calendar
Messages
Messages
Add canvas
Add canvas
Files
Files
Add and Edit Channel Tabs
Canvas
List
Folder
Jump to date
Steliyan Georgiev
Apr 9th at 10:00:27 AM
10:00 AM
прав си и за двете неща
Apr 9th at 10:00:29 AM
10:00
ще ми трябва
Apr 9th at 10:00:38 AM
10:00
ще ги видя имената да са консистентни
Lukas Kovalik
Apr 9th at 10:10:52 AM
10:10 AM
значи на снаке го направия, и добавя report_name
Steliyan Georgiev
Apr 9th at 10:11:17 AM
10:11 AM
reportName значи щом ще е снейк?
Lukas Kovalik
Apr 9th at 10:18:38 AM
10:18 AM
ами ай така
return [
'user_question' => $automatedReport->getAskAnythingPrompt()?->getContent(),
'callIds' => array_map('strval', $activityIds),
'team_id' => $automatedReport->getTeamId(),
'request_id' => $reportResultUuid,
'callback_url' => $this->getCallbackUrl(),
'report_period' => $this->getReportPeriodName($reportResult),
'report_name' => $automatedReport->getCustomName(),
];
Steliyan Georgiev
Apr 9th at 10:19:15 AM
10:19 AM
обърках се
(edited)
Apr 9th at 10:19:16 AM
10:19
кол?
Lukas Kovalik
Apr 9th at 10:19:30 AM
10:19 AM
да
A huddle happened
Apr 9th at 10:19:45 AM
10:19 AM
You and
Steliyan Georgiev
were in the huddle for
4m
.
Lukas Kovalik
Apr 9th at 10:21:16 AM
10:21 AM
return [
'user_question' => $automatedReport->getAskAnythingPrompt()?->getContent(),
'call_ids' => array_map('strval', $activityIds),
'team_id' => $automatedReport->getTeamId(),
'request_id' => $reportResultUuid,
'callback_url' => $this->getCallbackUrl(),
'report_period' => $this->getReportPeriodName($reportResult),
'report_name' => $automatedReport->getCustomName(),
];
Steliyan Georgiev
Apr 9th at 10:24:06 AM
10:24 AM
това е ПРът
https://github.com/jiminny/prophet/pull/465
https://github.com/jiminny/prophet/pull/465
Lukas Kovalik
Apr 9th at 3:19:47 PM
3:19 PM
Стели трябва ли да направя нещо на staging сега получавам [2026-04-09 11:55:47] staging.ERROR: [AskJiminnyReport:Generate] Error {“automatedReportUuid”:“fa7417aa-538e-49ab-8827-77235637a6f9",“reportUuid”:“058c1c38-4f61-4b06-8ede-5fb73f8942e7",“code”:0,“message”:“Unexpected service error.Client error: `POST
https://prophet.staging.jiminny.com/ask-anything-on-demand/request-report
https://prophet.staging.jiminny.com/ask-anything-on-demand/request-report
` resulted in a `404 Not Found` response:
Apr 9th at 3:19:59 PM
SlackFileEditViewGoHistoryWindowHelp(a6]• Support Daily • in 4 h 20 mБГDOCKERO ₴1DEV (-zsh)O $2APP (-zsh)whisper_init_state:kv selfsize3.15 MBwhisper_init_state: kv cross size =9.44 MBwhisper_init_state: kv padsize=2.36 MBwhisper_init_state:compute buffer(conv)whisper_init_state:compute buffer(encode)=whisper_init_state:computebuffer (cross)whisper_init_state: compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocatingwhisper_backend_init_gpu: device 0: Metal (type: 1)whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt:0)whisper_backend_init_gpu:using Metal backendggml_metal_init: allocatingggml_metal_init:founddevice: Apple M1ggml_metal_init:pickingdefault device: Apple M1ggml_metal_init:use fusion= trueggml_metal_init:use concurrencytrueggml_metal_init:use graph optimizetruewhisper_backend_init: using BLAS backendwhisper_init_state: kv self size=3.15 MBwhisper_init_state: kv cross size =9.44 MBwhisper_init_state: kv padsize=2.36 MBwhisper_init_state: compute buffer (conv)whi sper-_init-state: Compute buffer (encode)-whisper_init_state: compute buffer (cross)=whisper_init_state: compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocatingwhisper_backend_init_gpu: device 0: Metal (type:1)whisper_backend_init_gpu: found GPU device 0: Metal (type: 1, cnt: 0)whisper_backend_init_gpu: using Metal backendggml_metal_init: allocatingggml_metal_init: found device: Apple M1ggml_metal_init: picking default device: Apple M1ggml_metal_init:use fusion= trueggml_metal_init:use concurrency= trueggml_metal_init: use graph optimize = truewhisper_backend_init: using BLAS backendwhisper_init_state: kv self size=3.15 MBwhisper_init_state: kv cross size =9.44 MBwhisper_init_state: kv padsize2.36 MBwhisper_init_state: compute buffer (conv)whisper_init_state: compute buffer (encode) =whisper_init_state: compute buffer (cross)=whisper_init_state: compute buffer (decode) =14.17 MB65.96 MB8.50 MB96.83 MBggml_metal_free: deallocatingwhisper_backend_init_gpu: device 0: Metal (type: 1)883screenpipe"-zsh-zsh*5screenpipe"100% <78•Tue 12 May 10:40:21T81186-zsh+...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
25935
|
1083
|
7
|
2026-05-12T11:55:39.403646+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778586939403_m2.jpg...
|
Firefox
|
TypeError: League\Flysystem\Filesystem::has(): Arg TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app — Work...
|
True
|
jiminny.sentry.io/issues/6873095751/events/?enviro jiminny.sentry.io/issues/6873095751/events/?environment=production-eu&environment=production&project=82419&query=&statsPeriod=24h...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Ask Google Gemini
Unnamed Group
TypeError: League\ Ask Google Gemini
Unnamed Group
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
Close tab
CloudWatch | us-east-2
CloudWatch | us-east-2
test (885333) - jiminny/app
test (885333) - jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking for automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking for automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
Platform Team - Backlog - Jira
Platform Team - Backlog - Jira
Userpilot | Events
Userpilot | Events
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to main content
Skip to main content
Toggle organization menu
Issues
Issues
Explore
Explore
Dashboards
Dashboards
Monitors
Monitors
Settings
Settings
Try Business
What's New
Help
[EMAIL]
Issues
Expand
Feed
Feed
Errors & Outages
Errors & Outages
Breached Metrics
Breached Metrics
Warnings
Warnings
User Feedback
User Feedback
Autofix
Autofix
Recently Run
Recently Run
All Views
All Views
Configure
Alerts Moved
Alerts
Moved
Issues
Issues
View Project Details
APP-1DTF
Ask Seer
Ask Seer
/
Give Feedback
TypeError
View events
Events (total)
Users (90d)
Level: Error
League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218
2.4K
0
Ongoing
/app/Jobs/AutomatedReports/SendReportJob.php in Jiminny\Jobs\AutomatedReports\SendReportJob::handle
Quick Fix
Resolve
Resolve
More resolve options
Resolved In
Archive
Archive
Archive options
Subscribe
Share
More Actions
Priority
Modify issue priority
High
Assignee
Modify issue assignee
Nikolay Nikolov
production-eu, production
production-eu, production
24H
24H
Add a search term
Add a search term
Close sidebar
Toggle graph series - Events
Events
44
Toggle graph series - Users
Users
0
release 13% 881233
release
13%
881233
environment 100% production
environment
100%
production
os.build 63% #1 SMP Fri Mar 6 16:11:04 UTC 2026
os.build
63%
#1 SMP Fri Mar 6 16:11:04 UTC 2026
correlation_id <1% 3ff7aac9-a6ae-4a36-817c-d68edc55db66
correlation_id
<1%
3ff7aac9-a6ae-4a36-817c-d68edc55db66
View all tags
View all tags
Select issue content
Events
Open in Discover
Open in Discover
Return to event details
Close
All Events
Showing
1
-
44
of
44
matching
events
Previous Page
Next Page
Event ID
Timestamp
Timestamp
Title
Title
Transaction
Transaction
Release
Release
Environment
Environment
User
User
Device
Device
OS
OS
URL
URL
Runtime
Runtime
Replay
Trace
Actions
2dc71891
2dc71891
Actions
May 12, 2026 9:00:34 AM UTC
Actions
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218
Actions
(empty string)
Actions
884981
884981
Actions
production
Actions
(no value)
Actions
Actions
Linux 6.1.164-196.303.amzn2023.aarch64
Actions
(empty string)
Actions
php 8.3.30
Actions
Actions
6316eb00
6316eb00
Actions
452df925
452df925
Actions
May 12, 2026 9:00:33 AM UTC
Actions
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218
Actions
(empty string)
Actions
884981
884981
Actions
production
Actions
(no value)
Actions
Actions
Linux 6.1.164-196.303.amzn2023.aarch64
Actions
(empty string)
Actions
php 8.3.30
Actions
Actions
6316eb00
6316eb00...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Ask Google Gemini","depth":4,"bounds":{"left":0.14178856,"top":0.18355946,"width":0.011303191,"height":0.027134877},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Unnamed Group","depth":4,"bounds":{"left":0.0028257978,"top":0.057063047,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":4,"bounds":{"left":0.0028257978,"top":0.08060654,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":5,"bounds":{"left":0.015957447,"top":0.09217877,"width":0.40492022,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.087789305,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"CloudWatch | us-east-2","depth":4,"bounds":{"left":0.0028257978,"top":0.11332801,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | us-east-2","depth":5,"bounds":{"left":0.015957447,"top":0.12490024,"width":0.04138963,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"test (885333) - jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.14604948,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test (885333) - jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.15762171,"width":0.048038565,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira","depth":4,"bounds":{"left":0.0,"top":0.17877094,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.19034317,"width":0.16140293,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.21149242,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.22306465,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20773] User Pilot not receiving events on report generated - Jira","depth":4,"bounds":{"left":0.0,"top":0.2442139,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20773] User Pilot not receiving events on report generated - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.25578612,"width":0.1200133,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking for automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.27693537,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking for automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.28850758,"width":0.1931516,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20776] Automated report - sentry - Jira","depth":4,"bounds":{"left":0.0,"top":0.30965683,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20776] Automated report - sentry - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.32122904,"width":0.07646277,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.3423783,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.35395053,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6793] Les Mills activity types not pulling in - Jira","depth":4,"bounds":{"left":0.0,"top":0.37509975,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6793] Les Mills activity types not pulling in - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.386672,"width":0.09524601,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Team - Backlog - Jira","depth":4,"bounds":{"left":0.0,"top":0.40782124,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Team - Backlog - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.41939345,"width":0.053025264,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Events","depth":4,"bounds":{"left":0.0,"top":0.4405427,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Events","depth":5,"bounds":{"left":0.013297873,"top":0.4521149,"width":0.030418882,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.47486034,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to main content","depth":8,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to main content","depth":9,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle organization menu","depth":11,"bounds":{"left":0.08643617,"top":0.059856344,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Issues","depth":12,"bounds":{"left":0.0809508,"top":0.09736632,"width":0.021609042,"height":0.050678372},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Issues","depth":14,"bounds":{"left":0.0866024,"top":0.13048683,"width":0.010305851,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Explore","depth":12,"bounds":{"left":0.0809508,"top":0.14804469,"width":0.021609042,"height":0.050678372},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Explore","depth":14,"bounds":{"left":0.08577128,"top":0.1811652,"width":0.011968086,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Dashboards","depth":12,"bounds":{"left":0.0809508,"top":0.19872306,"width":0.021609042,"height":0.05027933},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dashboards","depth":14,"bounds":{"left":0.08211436,"top":0.23184358,"width":0.019281914,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Monitors","depth":12,"bounds":{"left":0.0809508,"top":0.2490024,"width":0.021609042,"height":0.050678372},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Monitors","depth":14,"bounds":{"left":0.084773935,"top":0.2821229,"width":0.013962766,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"bounds":{"left":0.0809508,"top":0.29968077,"width":0.021609042,"height":0.050678372},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"bounds":{"left":0.08494016,"top":0.33280128,"width":0.013630319,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Try Business","depth":10,"bounds":{"left":0.08643617,"top":0.88667196,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"What's New","depth":10,"bounds":{"left":0.08643617,"top":0.9114126,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Help","depth":10,"bounds":{"left":0.08643617,"top":0.93615323,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"lukas.kovalik@jiminny.com","depth":10,"bounds":{"left":0.08643617,"top":0.9680766,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Issues","depth":13,"bounds":{"left":0.04305186,"top":0.066640064,"width":0.014461436,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":13,"bounds":{"left":0.088597074,"top":0.061452515,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Feed","depth":15,"bounds":{"left":0.039727394,"top":0.10055866,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Feed","depth":17,"bounds":{"left":0.044049203,"top":0.10734238,"width":0.010638298,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Errors & Outages","depth":15,"bounds":{"left":0.039727394,"top":0.14046289,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Errors & Outages","depth":17,"bounds":{"left":0.044049203,"top":0.14724661,"width":0.03673537,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Breached Metrics","depth":15,"bounds":{"left":0.039727394,"top":0.16759777,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Breached Metrics","depth":17,"bounds":{"left":0.044049203,"top":0.17438148,"width":0.037898935,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Warnings","depth":15,"bounds":{"left":0.039727394,"top":0.19473264,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Warnings","depth":17,"bounds":{"left":0.044049203,"top":0.20151636,"width":0.019946808,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"User Feedback","depth":15,"bounds":{"left":0.039727394,"top":0.22186752,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"User Feedback","depth":17,"bounds":{"left":0.044049203,"top":0.22865124,"width":0.032081116,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Autofix","depth":13,"bounds":{"left":0.039727394,"top":0.26177174,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Autofix","depth":16,"bounds":{"left":0.043716755,"top":0.26855546,"width":0.016289894,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Recently Run","depth":15,"bounds":{"left":0.039727394,"top":0.28731045,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Recently Run","depth":17,"bounds":{"left":0.044049203,"top":0.29409418,"width":0.028922873,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"All Views","depth":15,"bounds":{"left":0.039727394,"top":0.3272147,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All Views","depth":17,"bounds":{"left":0.044049203,"top":0.3339984,"width":0.019281914,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Configure","depth":14,"bounds":{"left":0.043716755,"top":0.3735036,"width":0.021941489,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Alerts Moved","depth":15,"bounds":{"left":0.039727394,"top":0.39225858,"width":0.058843084,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Alerts","depth":17,"bounds":{"left":0.044049203,"top":0.3990423,"width":0.012799202,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Moved","depth":17,"bounds":{"left":0.08045213,"top":0.39984038,"width":0.012466756,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Issues","depth":12,"bounds":{"left":0.10954122,"top":0.06464485,"width":0.013796543,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Issues","depth":14,"bounds":{"left":0.10954122,"top":0.066640064,"width":0.013796543,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View Project Details","depth":13,"bounds":{"left":0.1299867,"top":0.06624102,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APP-1DTF","depth":16,"bounds":{"left":0.13796543,"top":0.066640064,"width":0.021609042,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Ask Seer","depth":10,"bounds":{"left":0.93484044,"top":0.059856344,"width":0.04720745,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Seer","depth":13,"bounds":{"left":0.9461436,"top":0.0650439,"width":0.019614361,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":14,"bounds":{"left":0.9740692,"top":0.065442935,"width":0.0021609042,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Give Feedback","depth":11,"bounds":{"left":0.9840425,"top":0.059856344,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TypeError","depth":13,"bounds":{"left":0.10954122,"top":0.10295291,"width":0.03174867,"height":0.017557861},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View events","depth":13,"bounds":{"left":0.9409907,"top":0.10654429,"width":0.026097074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Events (total)","depth":14,"bounds":{"left":0.9409907,"top":0.10654429,"width":0.026097074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Users (90d)","depth":13,"bounds":{"left":0.9724069,"top":0.10654429,"width":0.022273935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Level: Error","depth":15,"bounds":{"left":0.10920878,"top":0.12490024,"width":0.02443484,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218","depth":14,"bounds":{"left":0.11253324,"top":0.12490024,"width":0.453125,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2.4K","depth":13,"bounds":{"left":0.9534575,"top":0.12210695,"width":0.013630319,"height":0.017557861},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":13,"bounds":{"left":0.99052525,"top":0.12210695,"width":0.004155585,"height":0.017557861},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ongoing","depth":14,"bounds":{"left":0.10954122,"top":0.14046289,"width":0.018118352,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/app/Jobs/AutomatedReports/SendReportJob.php in Jiminny\\Jobs\\AutomatedReports\\SendReportJob::handle","depth":13,"bounds":{"left":0.13447474,"top":0.14046289,"width":0.24534574,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Quick Fix","depth":14,"bounds":{"left":0.3912899,"top":0.14046289,"width":0.019614361,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Resolve","depth":12,"bounds":{"left":0.10954122,"top":0.16719872,"width":0.02543218,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Resolve","depth":14,"bounds":{"left":0.11353058,"top":0.17238627,"width":0.017453458,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More resolve options","depth":12,"bounds":{"left":0.13464096,"top":0.16719872,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Resolved In","depth":15,"bounds":{"left":0.13896276,"top":0.20630486,"width":0.022107713,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Archive","depth":12,"bounds":{"left":0.14660904,"top":0.16719872,"width":0.025265958,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Archive","depth":14,"bounds":{"left":0.1505984,"top":0.17238627,"width":0.017287234,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Archive options","depth":12,"bounds":{"left":0.17154256,"top":0.16719872,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Subscribe","depth":12,"bounds":{"left":0.18351063,"top":0.16719872,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share","depth":12,"bounds":{"left":0.19547872,"top":0.16719872,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"More Actions","depth":12,"bounds":{"left":0.20744681,"top":0.16719872,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Priority","depth":12,"bounds":{"left":0.89544547,"top":0.17398244,"width":0.015791224,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue priority","depth":12,"bounds":{"left":0.9125665,"top":0.17039107,"width":0.013962766,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"High","depth":17,"bounds":{"left":0.91954786,"top":0.18076617,"width":0.008976064,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Assignee","depth":12,"bounds":{"left":0.9318484,"top":0.17398244,"width":0.019946808,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Modify issue assignee","depth":13,"bounds":{"left":0.953125,"top":0.16999201,"width":0.04155585,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Nikolay Nikolov","depth":17,"bounds":{"left":0.9616024,"top":0.17398244,"width":0.027593086,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"production-eu, production","depth":13,"bounds":{"left":0.10954122,"top":0.20949721,"width":0.07363697,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"production-eu, production","depth":17,"bounds":{"left":0.11353058,"top":0.21628092,"width":0.059674203,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"24H","depth":13,"bounds":{"left":0.18284574,"top":0.20949721,"width":0.023271276,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"24H","depth":17,"bounds":{"left":0.18683511,"top":0.21628092,"width":0.00930851,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXComboBox","text":"Add a search term","depth":16,"bounds":{"left":0.21941489,"top":0.21428572,"width":0.6549202,"height":0.01915403},"on_screen":true,"help_text":"","placeholder":"Filter events…","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXComboBox","text":"Add a search term","depth":16,"bounds":{"left":0.21941489,"top":0.21428572,"width":0.6549202,"height":0.01915403},"on_screen":true,"help_text":"","placeholder":"Filter events…","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close sidebar","depth":13,"bounds":{"left":0.88264626,"top":0.20949721,"width":0.011968086,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Toggle graph series - Events","depth":12,"bounds":{"left":0.11386303,"top":0.25818038,"width":0.021276595,"height":0.035115723},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Events","depth":15,"bounds":{"left":0.1178524,"top":0.26256984,"width":0.013297873,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"44","depth":15,"bounds":{"left":0.12101064,"top":0.27693537,"width":0.006981383,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Toggle graph series - Users","depth":12,"bounds":{"left":0.11386303,"top":0.2980846,"width":0.021276595,"height":0.035115723},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Users","depth":15,"bounds":{"left":0.119015954,"top":0.3008779,"width":0.010970744,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":15,"bounds":{"left":0.12267287,"top":0.31524342,"width":0.0034906915,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"release 13% 881233","depth":12,"bounds":{"left":0.7669548,"top":0.25818038,"width":0.11702128,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"release","depth":14,"bounds":{"left":0.76894945,"top":0.25977653,"width":0.013962766,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"13%","depth":14,"bounds":{"left":0.83627,"top":0.25977653,"width":0.007978723,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"881233","depth":14,"bounds":{"left":0.84557843,"top":0.25977653,"width":0.013962766,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"environment 100% production","depth":12,"bounds":{"left":0.7669548,"top":0.2725459,"width":0.11702128,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"environment","depth":14,"bounds":{"left":0.76894945,"top":0.273743,"width":0.024767287,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"100%","depth":14,"bounds":{"left":0.8337766,"top":0.273743,"width":0.010472074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"production","depth":14,"bounds":{"left":0.84557843,"top":0.273743,"width":0.02044548,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"os.build 63% #1 SMP Fri Mar 6 16:11:04 UTC 2026","depth":12,"bounds":{"left":0.7669548,"top":0.2869114,"width":0.11702128,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"os.build","depth":14,"bounds":{"left":0.76894945,"top":0.28810853,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"63%","depth":14,"bounds":{"left":0.83627,"top":0.28810853,"width":0.007978723,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#1 SMP Fri Mar 6 16:11:04 UTC 2026","depth":14,"bounds":{"left":0.84557843,"top":0.28810853,"width":0.06549202,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"correlation_id <1% 3ff7aac9-a6ae-4a36-817c-d68edc55db66","depth":12,"bounds":{"left":0.7669548,"top":0.3008779,"width":0.11702128,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"correlation_id","depth":14,"bounds":{"left":0.76894945,"top":0.30247405,"width":0.027593086,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"<1%","depth":14,"bounds":{"left":0.8367686,"top":0.30247405,"width":0.007480053,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3ff7aac9-a6ae-4a36-817c-d68edc55db66","depth":14,"bounds":{"left":0.84557843,"top":0.30247405,"width":0.07945479,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View all tags","depth":12,"bounds":{"left":0.76894945,"top":0.31763768,"width":0.027094414,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"View all tags","depth":13,"bounds":{"left":0.76894945,"top":0.31923383,"width":0.027094414,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Select issue content","depth":13,"bounds":{"left":0.10954122,"top":0.34836394,"width":0.028922873,"height":0.025538707},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Events","depth":15,"bounds":{"left":0.11353058,"top":0.35434955,"width":0.01761968,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open in Discover","depth":13,"bounds":{"left":0.82430184,"top":0.3499601,"width":0.04338431,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Open in Discover","depth":15,"bounds":{"left":0.83294547,"top":0.35514766,"width":0.032081116,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Return to event details","depth":13,"bounds":{"left":0.8703458,"top":0.3499601,"width":0.015957447,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Close","depth":15,"bounds":{"left":0.87300533,"top":0.35514766,"width":0.010638298,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"All Events","depth":14,"bounds":{"left":0.11386303,"top":0.38946527,"width":0.022273935,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Showing","depth":13,"bounds":{"left":0.79138964,"top":0.39026338,"width":0.017121011,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":13,"bounds":{"left":0.80851066,"top":0.39026338,"width":0.0018284575,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":13,"bounds":{"left":0.8103391,"top":0.39026338,"width":0.0018284575,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"44","depth":13,"bounds":{"left":0.8121675,"top":0.39026338,"width":0.004986702,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"of","depth":13,"bounds":{"left":0.8171542,"top":0.39026338,"width":0.005817819,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"44","depth":13,"bounds":{"left":0.82297206,"top":0.39026338,"width":0.0048204786,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"matching","depth":13,"bounds":{"left":0.8277925,"top":0.39026338,"width":0.019780586,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"events","depth":13,"bounds":{"left":0.84757316,"top":0.39026338,"width":0.012466756,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Previous Page","depth":13,"bounds":{"left":0.8640292,"top":0.38427773,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Next Page","depth":13,"bounds":{"left":0.87400264,"top":0.38427773,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Event ID","depth":16,"bounds":{"left":0.11386303,"top":0.42218676,"width":0.018783245,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Timestamp","depth":15,"bounds":{"left":0.1471077,"top":0.42218676,"width":0.06482713,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Timestamp","depth":16,"bounds":{"left":0.1471077,"top":0.42218676,"width":0.025099734,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Title","depth":15,"bounds":{"left":0.22024602,"top":0.42218676,"width":0.05817819,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Title","depth":16,"bounds":{"left":0.22024602,"top":0.42218676,"width":0.009973404,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Transaction","depth":15,"bounds":{"left":0.2867354,"top":0.42218676,"width":0.05817819,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Transaction","depth":16,"bounds":{"left":0.2867354,"top":0.42218676,"width":0.026595745,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Release","depth":15,"bounds":{"left":0.35322472,"top":0.42218676,"width":0.04155585,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Release","depth":16,"bounds":{"left":0.35322472,"top":0.42218676,"width":0.01761968,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Environment","depth":15,"bounds":{"left":0.40309176,"top":0.42218676,"width":0.029920213,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Environment","depth":16,"bounds":{"left":0.40309176,"top":0.42218676,"width":0.029089095,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"User","depth":15,"bounds":{"left":0.44132313,"top":0.42218676,"width":0.04155585,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"User","depth":16,"bounds":{"left":0.44132313,"top":0.42218676,"width":0.010472074,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Device","depth":15,"bounds":{"left":0.49119017,"top":0.42218676,"width":0.04155585,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Device","depth":16,"bounds":{"left":0.49119017,"top":0.42218676,"width":0.01512633,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"OS","depth":15,"bounds":{"left":0.54105717,"top":0.42218676,"width":0.04155585,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"OS","depth":16,"bounds":{"left":0.54105717,"top":0.42218676,"width":0.006150266,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"URL","depth":15,"bounds":{"left":0.5909242,"top":0.42218676,"width":0.09142287,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"URL","depth":16,"bounds":{"left":0.5909242,"top":0.42218676,"width":0.009142287,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Runtime","depth":15,"bounds":{"left":0.6906583,"top":0.42218676,"width":0.04155585,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Runtime","depth":16,"bounds":{"left":0.6906583,"top":0.42218676,"width":0.019115692,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replay","depth":16,"bounds":{"left":0.74052525,"top":0.42218676,"width":0.01512633,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Trace","depth":16,"bounds":{"left":0.77377,"top":0.42218676,"width":0.012466756,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.11386303,"top":0.4501197,"width":0.025265958,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"2dc71891","depth":16,"bounds":{"left":0.11386303,"top":0.4501197,"width":0.025265958,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2dc71891","depth":18,"bounds":{"left":0.11386303,"top":0.4517159,"width":0.020113032,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.1471077,"top":0.44972068,"width":0.065159574,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"May 12, 2026 9:00:34 AM UTC","depth":19,"bounds":{"left":0.1471077,"top":0.4521149,"width":0.06549202,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.22024602,"top":0.4501197,"width":0.05851064,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218","depth":18,"bounds":{"left":0.22024602,"top":0.4517159,"width":0.47639626,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.2867354,"top":0.44972068,"width":0.05851064,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"(empty string)","depth":17,"bounds":{"left":0.2867354,"top":0.4521149,"width":0.030585106,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.35322472,"top":0.4501197,"width":0.041888297,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"884981","depth":18,"bounds":{"left":0.35322472,"top":0.4501197,"width":0.017287234,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"884981","depth":20,"bounds":{"left":0.35322472,"top":0.4517159,"width":0.017287234,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.40309176,"top":0.4501197,"width":0.03025266,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"production","depth":18,"bounds":{"left":0.40309176,"top":0.4517159,"width":0.023769947,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.44132313,"top":0.44972068,"width":0.041888297,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"(no value)","depth":17,"bounds":{"left":0.44132313,"top":0.4521149,"width":0.020944148,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.54105717,"top":0.4501197,"width":0.041888297,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Linux 6.1.164-196.303.amzn2023.aarch64","depth":17,"bounds":{"left":0.5490359,"top":0.4517159,"width":0.09009308,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.5909242,"top":0.44972068,"width":0.091755316,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"(empty string)","depth":17,"bounds":{"left":0.5909242,"top":0.4521149,"width":0.030585106,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.6906583,"top":0.4501197,"width":0.041888297,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"php 8.3.30","depth":18,"bounds":{"left":0.6906583,"top":0.4517159,"width":0.023271276,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.74052525,"top":0.4501197,"width":0.025265958,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.77377,"top":0.4501197,"width":0.108211435,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"6316eb00","depth":16,"bounds":{"left":0.77377,"top":0.4501197,"width":0.108211435,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"6316eb00","depth":18,"bounds":{"left":0.77377,"top":0.4517159,"width":0.021609042,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.11386303,"top":0.47964883,"width":0.025265958,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"452df925","depth":16,"bounds":{"left":0.11386303,"top":0.47964883,"width":0.025265958,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"452df925","depth":18,"bounds":{"left":0.11386303,"top":0.481245,"width":0.021276595,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.1471077,"top":0.47964883,"width":0.065159574,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"May 12, 2026 9:00:33 AM UTC","depth":19,"bounds":{"left":0.1471077,"top":0.48164406,"width":0.06549202,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.22024602,"top":0.47964883,"width":0.05851064,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218","depth":18,"bounds":{"left":0.22024602,"top":0.481245,"width":0.47639626,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.2867354,"top":0.47964883,"width":0.05851064,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"(empty string)","depth":17,"bounds":{"left":0.2867354,"top":0.48164406,"width":0.030585106,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.35322472,"top":0.47964883,"width":0.041888297,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"884981","depth":18,"bounds":{"left":0.35322472,"top":0.47964883,"width":0.017287234,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"884981","depth":20,"bounds":{"left":0.35322472,"top":0.481245,"width":0.017287234,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.40309176,"top":0.47964883,"width":0.03025266,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"production","depth":18,"bounds":{"left":0.40309176,"top":0.481245,"width":0.023769947,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.44132313,"top":0.47964883,"width":0.041888297,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"(no value)","depth":17,"bounds":{"left":0.44132313,"top":0.48164406,"width":0.020944148,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.54105717,"top":0.47964883,"width":0.041888297,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Linux 6.1.164-196.303.amzn2023.aarch64","depth":17,"bounds":{"left":0.5490359,"top":0.481245,"width":0.09009308,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.5909242,"top":0.47964883,"width":0.091755316,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"(empty string)","depth":17,"bounds":{"left":0.5909242,"top":0.48164406,"width":0.030585106,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.6906583,"top":0.47964883,"width":0.041888297,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"php 8.3.30","depth":18,"bounds":{"left":0.6906583,"top":0.481245,"width":0.023271276,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.74052525,"top":0.47964883,"width":0.025265958,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Actions","depth":15,"bounds":{"left":0.77377,"top":0.47964883,"width":0.108211435,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"6316eb00","depth":16,"bounds":{"left":0.77377,"top":0.47964883,"width":0.108211435,"height":0.01556265},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"6316eb00","depth":18,"bounds":{"left":0.77377,"top":0.481245,"width":0.021609042,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-7749423653177018438
|
6789513862719600820
|
visual_change
|
accessibility
|
NULL
|
Ask Google Gemini
Unnamed Group
TypeError: League\ Ask Google Gemini
Unnamed Group
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
Close tab
CloudWatch | us-east-2
CloudWatch | us-east-2
test (885333) - jiminny/app
test (885333) - jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking for automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking for automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
Platform Team - Backlog - Jira
Platform Team - Backlog - Jira
Userpilot | Events
Userpilot | Events
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to main content
Skip to main content
Toggle organization menu
Issues
Issues
Explore
Explore
Dashboards
Dashboards
Monitors
Monitors
Settings
Settings
Try Business
What's New
Help
[EMAIL]
Issues
Expand
Feed
Feed
Errors & Outages
Errors & Outages
Breached Metrics
Breached Metrics
Warnings
Warnings
User Feedback
User Feedback
Autofix
Autofix
Recently Run
Recently Run
All Views
All Views
Configure
Alerts Moved
Alerts
Moved
Issues
Issues
View Project Details
APP-1DTF
Ask Seer
Ask Seer
/
Give Feedback
TypeError
View events
Events (total)
Users (90d)
Level: Error
League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218
2.4K
0
Ongoing
/app/Jobs/AutomatedReports/SendReportJob.php in Jiminny\Jobs\AutomatedReports\SendReportJob::handle
Quick Fix
Resolve
Resolve
More resolve options
Resolved In
Archive
Archive
Archive options
Subscribe
Share
More Actions
Priority
Modify issue priority
High
Assignee
Modify issue assignee
Nikolay Nikolov
production-eu, production
production-eu, production
24H
24H
Add a search term
Add a search term
Close sidebar
Toggle graph series - Events
Events
44
Toggle graph series - Users
Users
0
release 13% 881233
release
13%
881233
environment 100% production
environment
100%
production
os.build 63% #1 SMP Fri Mar 6 16:11:04 UTC 2026
os.build
63%
#1 SMP Fri Mar 6 16:11:04 UTC 2026
correlation_id <1% 3ff7aac9-a6ae-4a36-817c-d68edc55db66
correlation_id
<1%
3ff7aac9-a6ae-4a36-817c-d68edc55db66
View all tags
View all tags
Select issue content
Events
Open in Discover
Open in Discover
Return to event details
Close
All Events
Showing
1
-
44
of
44
matching
events
Previous Page
Next Page
Event ID
Timestamp
Timestamp
Title
Title
Transaction
Transaction
Release
Release
Environment
Environment
User
User
Device
Device
OS
OS
URL
URL
Runtime
Runtime
Replay
Trace
Actions
2dc71891
2dc71891
Actions
May 12, 2026 9:00:34 AM UTC
Actions
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218
Actions
(empty string)
Actions
884981
884981
Actions
production
Actions
(no value)
Actions
Actions
Linux 6.1.164-196.303.amzn2023.aarch64
Actions
(empty string)
Actions
php 8.3.30
Actions
Actions
6316eb00
6316eb00
Actions
452df925
452df925
Actions
May 12, 2026 9:00:33 AM UTC
Actions
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218
Actions
(empty string)
Actions
884981
884981
Actions
production
Actions
(no value)
Actions
Actions
Linux 6.1.164-196.303.amzn2023.aarch64
Actions
(empty string)
Actions
php 8.3.30
Actions
Actions
6316eb00
6316eb00...
|
25934
|
NULL
|
NULL
|
NULL
|
|
8316
|
368
|
5
|
2026-05-08T10:20:11.681068+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778235611681_m2.jpg...
|
Slack
|
Galya Dimitrova (DM) - Jiminny Inc - 4 new items - Galya Dimitrova (DM) - Jiminny Inc - 4 new items - Slack...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
Vasil Vasilev
James Graham
Lukas Kovalik
you
Jira Cloud
Toast
Messages
Messages
Files
Files
Untitled
Untitled
Add and Edit Channel Tabs
Canvas
List
Folder
Today at 11:02:07 AM
11:02
за AJ Reports нали в Datadog ги направихме да се логват към същия евент към който и другите и само типа да е различен
Today at 11:02:51 AM
11:02
обаче така се оказа че се включват във всичките графики където са и другите и развалят числата. Сега не мога да видя колко компании ползват едните и колко другите.
Today at 11:03:13 AM
11:03
сигурно има някаква сложна формула която да се измисли ама се чудя дали няма да е по добре да ги сложим да се тракват под друг евент
Lukas Kovalik
Today at 11:31:05 AM
11:31 AM
здрасти, погледнах го и то си пуска общ event
Today at 11:32:00 AM
11:32
ако е podcast пуска още един
Galya Dimitrova
Today at 11:32:23 AM
11:32 AM
можем ли да направим за aj reports да се пуска на отделен
Today at 11:32:40 AM
11:32
че го мъчих ама не успях да го изкарам от всичките графики
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 11:33:14 AM
11:33 AM
хм, по report_type не става ли
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Galya Dimitrova
Today at 11:35:50 AM
11:35 AM
https://app.datadoghq.com/dashboard/5id-9sv-qmg/ai-features?fromUser=false&refresh_mo[…]9773418&from_ts=1772316000000&to_ts=1777475592447&live=false
https://app.datadoghq.com/dashboard/5id-9sv-qmg/ai-features?fromUser=false&refresh_mo[…]9773418&from_ts=1772316000000&to_ts=1777475592447&live=false
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:36:02 AM
11:36
виж най горе първите 2 графики
(edited)
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:36:27 AM
11:36
те вече са разбити по друго
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:36:46 AM
11:36
ако добавя report typе ми го слага с or което не ми върши работа
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:37:09 AM
11:37
поне аз не успях да измисля как да стане
React with white_check_mark
React with eyes
React with raised_hands...
|
[{"role":"AXPopUpButton","text [{"role":"AXPopUpButton","text":"Switch workspaces… (Jiminny Inc) Has new messages","depth":14,"bounds":{"left":0.5152925,"top":1.0,"width":0.011968086,"height":-0.058260202},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Home","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Home","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"DMs","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"DMs","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Activity","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Activity","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Later","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Later","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"More…","depth":14,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"More","depth":16,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Unreads","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.018949468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Threads","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.01761968,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Huddles","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Drafts & sent","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.02925532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":21,"bounds":{"left":0.5980718,"top":1.0,"width":0.0026595744,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Directories","depth":21,"bounds":{"left":0.5465425,"top":1.0,"width":0.024268618,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-x-integration-app","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.043882977,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-inner-team","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.04454787,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ai-chapter","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.022273935,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"alerts","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.012300532,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"backend","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.018284574,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bugs","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.010638298,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"confusion-clinic","depth":23,"bounds":{"left":0.5518617,"top":1.0,"width":0.034574468,"height":-0.09177971},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"curiosity_lab","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"engineering","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"general","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"jiminny-bg","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"platform-tickets","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"product_launches","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"random","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"releases","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"sofia-office","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"support","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"thank-yous","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"the_people_of_jiminny","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Ivanov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Nikolay Yankov","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":",","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Steliyan Georgiev","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Stoyan Tanev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Stefka Stoyanova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Ves","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Aneliya Angelova","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Vasil Vasilev","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"James Graham","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"you","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Jira Cloud","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Toast","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Messages","depth":17,"bounds":{"left":0.61170214,"top":1.0,"width":0.030917553,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"Messages","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Files","depth":17,"bounds":{"left":0.64361703,"top":1.0,"width":0.020944148,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Files","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Untitled","depth":17,"bounds":{"left":0.66589093,"top":1.0,"width":0.02925532,"height":-0.09177971},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Untitled","depth":19,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"Add and Edit Channel Tabs","depth":17,"bounds":{"left":0.6961436,"top":1.0,"width":0.010970744,"height":-0.09177971},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Canvas","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":17,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Today at 11:02:07 AM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:02","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"за AJ Reports нали в Datadog ги направихме да се логват към същия евент към който и другите и само типа да е различен","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 11:02:51 AM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:02","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"обаче така се оказа че се включват във всичките графики където са и другите и развалят числата. Сега не мога да видя колко компании ползват едните и колко другите.","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 11:03:13 AM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:03","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"сигурно има някаква сложна формула която да се измисли ама се чудя дали няма да е по добре да ги сложим да се тракват под друг евент","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 11:31:05 AM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:31 AM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"здрасти, погледнах го и то си пуска общ event","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 11:32:00 AM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:32","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ако е podcast пуска още един","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 11:32:23 AM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:32 AM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"можем ли да направим за aj reports да се пуска на отделен","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 11:32:40 AM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:32","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"че го мъчих ама не успях да го изкарам от всичките графики","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Lukas Kovalik","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 11:33:14 AM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:33 AM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"хм, по report_type не става ли","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Galya Dimitrova","depth":23,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"Today at 11:35:50 AM","depth":23,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:35 AM","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXLink","text":"https://app.datadoghq.com/dashboard/5id-9sv-qmg/ai-features?fromUser=false&refresh_mo[…]9773418&from_ts=1772316000000&to_ts=1777475592447&live=false","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"https://app.datadoghq.com/dashboard/5id-9sv-qmg/ai-features?fromUser=false&refresh_mo[…]9773418&from_ts=1772316000000&to_ts=1777475592447&live=false","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:36:02 AM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:36","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"виж най горе първите 2 графики","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"(edited)","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:36:27 AM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:36","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"те вече са разбити по друго","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:36:46 AM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:36","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ако добавя report typе ми го слага с or което не ми върши работа","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add reaction…","depth":25,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reply in thread","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Forward message…","depth":25,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Save for later","depth":25,"on_screen":false,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXPopUpButton","text":"More actions","depth":25,"on_screen":false,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Today at 11:37:09 AM","depth":24,"on_screen":true,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"11:37","depth":25,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"поне аз не успях да измисля как да стане","depth":24,"on_screen":true,"role_description":"text"},{"role":"AXCheckBox","text":"React with white_check_mark","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with eyes","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"React with raised_hands","depth":25,"on_screen":true,"role_description":"toggle button","subrole":"AXToggleButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-7749045149526517182
|
-1569199003023260584
|
app_switch
|
hybrid
|
NULL
|
Switch workspaces… (Jiminny Inc) Has new messages
Switch workspaces… (Jiminny Inc) Has new messages
Home
Home
DMs
DMs
Activity
Activity
Files
Files
Later
Later
More…
More
Unreads
Threads
Huddles
Drafts & sent
1
Directories
jiminny-x-integration-app
platform-inner-team
ai-chapter
alerts
backend
bugs
confusion-clinic
curiosity_lab
engineering
general
jiminny-bg
platform-tickets
product_launches
random
releases
sofia-office
support
thank-yous
the_people_of_jiminny
Nikolay Ivanov
Galya Dimitrova
Aneliya Angelova
,
Nikolay Yankov
,
Steliyan Georgiev
Stoyan Tanev
Stefka Stoyanova
Ves
Aneliya Angelova
Vasil Vasilev
James Graham
Lukas Kovalik
you
Jira Cloud
Toast
Messages
Messages
Files
Files
Untitled
Untitled
Add and Edit Channel Tabs
Canvas
List
Folder
Today at 11:02:07 AM
11:02
за AJ Reports нали в Datadog ги направихме да се логват към същия евент към който и другите и само типа да е различен
Today at 11:02:51 AM
11:02
обаче така се оказа че се включват във всичките графики където са и другите и развалят числата. Сега не мога да видя колко компании ползват едните и колко другите.
Today at 11:03:13 AM
11:03
сигурно има някаква сложна формула която да се измисли ама се чудя дали няма да е по добре да ги сложим да се тракват под друг евент
Lukas Kovalik
Today at 11:31:05 AM
11:31 AM
здрасти, погледнах го и то си пуска общ event
Today at 11:32:00 AM
11:32
ако е podcast пуска още един
Galya Dimitrova
Today at 11:32:23 AM
11:32 AM
можем ли да направим за aj reports да се пуска на отделен
Today at 11:32:40 AM
11:32
че го мъчих ама не успях да го изкарам от всичките графики
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Lukas Kovalik
Today at 11:33:14 AM
11:33 AM
хм, по report_type не става ли
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Galya Dimitrova
Today at 11:35:50 AM
11:35 AM
https://app.datadoghq.com/dashboard/5id-9sv-qmg/ai-features?fromUser=false&refresh_mo[…]9773418&from_ts=1772316000000&to_ts=1777475592447&live=false
https://app.datadoghq.com/dashboard/5id-9sv-qmg/ai-features?fromUser=false&refresh_mo[…]9773418&from_ts=1772316000000&to_ts=1777475592447&live=false
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:36:02 AM
11:36
виж най горе първите 2 графики
(edited)
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:36:27 AM
11:36
те вече са разбити по друго
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:36:46 AM
11:36
ако добавя report typе ми го слага с or което не ми върши работа
React with white_check_mark
React with eyes
React with raised_hands
Add reaction…
Reply in thread
Forward message…
Save for later
More actions
Today at 11:37:09 AM
11:37
поне аз не успях да измисля как да стане
React with white_check_mark
React with eyes
React with raised_hands
$0 libl• supoont Dally • In 1n 40ml100% 5ril o May 13.20.12FV faVsco.js v°9 master kProledey© DeleteCrmEntityTrait.php© RematchActivityOnCrmObj|© TimezoneRepository.php© CrmActivityService.php© RateLimitException.php© TopicRepository.php© TopicTriggerRepository.p© CrmObjectsResolver.php© TrackRepository.php© TranscriptionModelLocale©TranscriptionRepository.p© TranscriptionSummaryRel©UserRepository.php© VocabularyRepository.ph|class Client extends BaseClient implem* @template T* @param callable(): T $apiCall* oreun› D Rulesv U servicesx ochrows KaceLzmrccxcepcionD ACuVILyAjReportsW Avaratprivate function executeRequest(caCalendarConterenceD Crm> BullhornO Close→ coonenreturn sapnlallon} catch (Throwable $e) {1+ Sthis->isHubspotRateL1SretrvAfter = Sthis->oCrmObjectsDecorateActivity89Dummy>• Helpersv D HubspotSthis->lo0->warnindd''team 1d'"retry aftent =>= $|AccountSyncStrate>D Actions• ContactSyncStrate!> DDTOthrow new RateLimitExo• D Fields> D Journalm Motadatalthrow $e;> D OpportunitySyncStiv D Pagination© HubspotPaginatil© PaginationConfig1 usage(C) PaqinationState.public function isHubspotRateLimit> D ProspectSearchStra|> D Redis.v D ServiceTraitspublic function parseRetryAfter(ThTOnoortunitvsvne* SyncCrmEntities163 Gt›pubuac function getMinimumApiVers1T SuncFieldstirait.T. WriteCrmTrait.ol168 Et>pubunc function getinstanceo: Fac• M UtilsM Webhook177 € >public function getNewInstance() :C) BatchSvncCollectotc) RatchSvncRedisSec) Client nho(C) ClocedDea|Stadecs@ DoalFieldsService r• 0app.calacoene.com/casnooara/lists.o=- Imoort bookmarks.• Sprint Board • SRD QueueGithub S Jiminnv DEVAsk Jiminnv Report.©circle Cl 8 PRODUS & Staging l Sentryrultrequests " junE Workers | Datadog M Jiminny Mail Dashboards | Datad...Platform Sorint 3 02 - Platform TelDashboardsListbookmarksShared DashboardsSevenShores|Hubspot|ExceptionsQ Search bookmarks• Search dashboardsService-Desk - Queues - Platfornf Jy 20807 check various issues witlC. JY-20818 move ask jiminny reportu Userpilot | Ask Jiminny Report Gen• Jy-20773 fix user pilot tracking of© Problem loading pageDo Search the CRM - HubSpot docs8 JiminnyNew TabNew TabM. Dashboards I Datadodlv * Bookmarks ToolbaSprint BoardSRD QueueGithub Jiminny DEVAsk Jiminny Reports by nikolay-yankov•..© Circle Cl8 PRODUS8 Staginga SentryPull requests - jiminny/appF Workers | DatadogwJiminny Mail# Dashboards | DatadogJ Other BookmarksDATADOGQ Go to...x + K3 Recent,* Bits AI]4 DashboardsE Monitoring§*) Incident Response4 AutomationE Hide Controls> My TeamsQ FilterPreset Lists[ All CustomE All HostsI All Integrations{ Created By YouI Frequently Viewed By YouI Recently Deleted# Security and ComplianceAll Dashboards230 totalNAMEworkersProcessinaAI FeaturesJiminny HealthCustomer APIAl Features | Datadog• Jy 20493 smart instant nudae ordDashboards | Datadog8 InfrastructureA Cloud CostE. APMi Digital ExperienceS Software Delivery# Securitya Data Observability& AI ObservabilityDialer ImoortsNotetakenProduct MetricsES updateHubspot appQueues by Oggietit ErrorsDialers All in one(4, Metrics83 RUM - Web App ErrorsFÖ Logs#. Integrationslukas.kovalik@)ji..iminny, Ine.NEWAWS ES (Elasticsearch service)AWS SQSJiminny SQS StatsDAWS ELBPusherRedis - Overviewl* Product Tier: Free & Starter100/10 secondsStovan notetaker test• SharedShared• SharedShared• Shared• Shared|SharedAUTHOR@ Veselin Kulov§ Mihail Mihaylov.F3) Galya DimitrovaP) Veselin Kulov.i) Martin Petkov# Todor StamatovAhmet KatrancilE James GrahamTEAMSVanvan Dimitrov• Nikolay NikolovOgnyan DimitrovTonislav Atanasovlames GrahamJames GrahamO Veselin KulovJames GrahamStovan TomovA vacain vntait leamsAdd toW DeleteApr 28, 10:46 amApr 20, 11:56 amMay 8, 10:59 amMar 30, 12:23 pmMay 5, 10:33 amMar 11.2:37 omlFeb 27. 10:47 amlMar 31, 1:24 pmMar 19, 4:44 pmDec 4, 2025, 9:53 pmApr 9, 5:59 pmFeb 4. 10:50 amMar 17. 10:59 pmApr 8, 2020, 3:22 pmFeb 20, 6:26 pmApr 8, 2020, 3:19 pmPOPULARITY11l1Mav 29. 2025. 11:26 am...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
22542
|
972
|
34
|
2026-05-12T07:12:54.002724+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778569974002_m1.jpg...
|
Firefox
|
planhat - Google Search — Work
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
planhat - Google Search
google.com
New Tab
New Tab planhat - Google Search
google.com
New Tab
New Tab
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
LLM pricing overview with the most actual prices - Google Search
LLM pricing overview with the most actual prices - Google Search
planhat - Google Search...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"planhat - Google Search","depth":4,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"google.com","depth":4,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pull requests · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20773] User Pilot not receiving events on report generated - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20773] User Pilot not receiving events on report generated - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20776] Automated report - sentry - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20776] Automated report - sentry - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"LLM pricing overview with the most actual prices - Google Search","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"LLM pricing overview with the most actual prices - Google Search","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"planhat - Google Search","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true}]...
|
-7748353109789222894
|
-2435019734841083253
|
visual_change
|
accessibility
|
NULL
|
planhat - Google Search
google.com
New Tab
New Tab planhat - Google Search
google.com
New Tab
New Tab
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
LLM pricing overview with the most actual prices - Google Search
LLM pricing overview with the most actual prices - Google Search
planhat - Google Search...
|
22541
|
NULL
|
NULL
|
NULL
|
|
19201
|
824
|
22
|
2026-05-11T12:35:33.088965+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778502933088_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
67
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall The API call to execute
* @return T The result of the API call
*
* @throws RateLimitException When rate limit is hit or cached rate limit is active
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedExpiresAt = Redis::get($cacheKey);
if (is_string($cachedExpiresAt) && is_numeric($cachedExpiresAt)) {
$remaining = max(1, (int) $cachedExpiresAt - time());
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
$remaining,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
// NX: only the first job to receive a 429 in this burst sets the key.
// Subsequent 429s in the same burst leave the TTL untouched so the
// window is not reset by every concurrent job hitting the limit.
Redis::set($cacheKey, (string) (time() + $retryAfter), ['nx', 'ex' => $retryAfter]);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$message = strtolower($e->getMessage());
if (str_contains($message, 'daily')) {
return 600;
}
if (str_contains($message, 'ten secondly')) {
return 10;
}
if (str_contains($message, 'secondly')) {
return 1;
}
$this->log->warning('[Hubspot] No retry-after header or known message, using default', [
'exception_class' => get_class($e),
'message' => $message,
]);
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Show Replace Field
Search History
429
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
23/223
Previous Occurrence
Next Occurrence
Filter Search Results...
|
[{"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-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","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":"HandleHubspotRateLimitTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","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},{"role":"AXStaticText","text":"2","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"67","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","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\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Execute a HubSpot API call with rate limit handling.\n *\n * On a 429, stores the absolute expiry timestamp with SET NX (first writer wins).\n * This means all subsequent jobs that also receive 429 in the same burst do not\n * reset the TTL — the window is anchored to the first 429, not the last.\n * Readers compute the remaining wait from the stored timestamp, so jobs that check\n * the cache near expiry are not delayed longer than necessary.\n *\n * @template T\n * @param callable(): T $apiCall The API call to execute\n * @return T The result of the API call\n *\n * @throws RateLimitException When rate limit is hit or cached rate limit is active\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedExpiresAt = Redis::get($cacheKey);\n if (is_string($cachedExpiresAt) && is_numeric($cachedExpiresAt)) {\n $remaining = max(1, (int) $cachedExpiresAt - time());\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n $remaining,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n // NX: only the first job to receive a 429 in this burst sets the key.\n // Subsequent 429s in the same burst leave the TTL untouched so the\n // window is not reset by every concurrent job hitting the limit.\n Redis::set($cacheKey, (string) (time() + $retryAfter), ['nx', 'ex' => $retryAfter]);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $message = strtolower($e->getMessage());\n\n if (str_contains($message, 'daily')) {\n return 600;\n }\n if (str_contains($message, 'ten secondly')) {\n return 10;\n }\n if (str_contains($message, 'secondly')) {\n return 1;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or known message, using default', [\n 'exception_class' => get_class($e),\n 'message' => $message,\n ]);\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Execute a HubSpot API call with rate limit handling.\n *\n * On a 429, stores the absolute expiry timestamp with SET NX (first writer wins).\n * This means all subsequent jobs that also receive 429 in the same burst do not\n * reset the TTL — the window is anchored to the first 429, not the last.\n * Readers compute the remaining wait from the stored timestamp, so jobs that check\n * the cache near expiry are not delayed longer than necessary.\n *\n * @template T\n * @param callable(): T $apiCall The API call to execute\n * @return T The result of the API call\n *\n * @throws RateLimitException When rate limit is hit or cached rate limit is active\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedExpiresAt = Redis::get($cacheKey);\n if (is_string($cachedExpiresAt) && is_numeric($cachedExpiresAt)) {\n $remaining = max(1, (int) $cachedExpiresAt - time());\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n $remaining,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n // NX: only the first job to receive a 429 in this burst sets the key.\n // Subsequent 429s in the same burst leave the TTL untouched so the\n // window is not reset by every concurrent job hitting the limit.\n Redis::set($cacheKey, (string) (time() + $retryAfter), ['nx', 'ex' => $retryAfter]);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $message = strtolower($e->getMessage());\n\n if (str_contains($message, 'daily')) {\n return 600;\n }\n if (str_contains($message, 'ten secondly')) {\n return 10;\n }\n if (str_contains($message, 'secondly')) {\n return 1;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or known message, using default', [\n 'exception_class' => get_class($e),\n 'message' => $message,\n ]);\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Replace Field","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Search History","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"429","depth":4,"on_screen":true,"value":"429","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Match Case","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Words","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Regex","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Replace History","depth":3,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.024444444},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Replace","depth":4,"on_screen":false,"role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":3,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.024444444},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Preserve case","depth":3,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.024444444},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"23/223","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Occurrence","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Occurrence","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Filter Search Results","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-7748219105398282943
|
5225837844320127076
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
67
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall The API call to execute
* @return T The result of the API call
*
* @throws RateLimitException When rate limit is hit or cached rate limit is active
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedExpiresAt = Redis::get($cacheKey);
if (is_string($cachedExpiresAt) && is_numeric($cachedExpiresAt)) {
$remaining = max(1, (int) $cachedExpiresAt - time());
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
$remaining,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
// NX: only the first job to receive a 429 in this burst sets the key.
// Subsequent 429s in the same burst leave the TTL untouched so the
// window is not reset by every concurrent job hitting the limit.
Redis::set($cacheKey, (string) (time() + $retryAfter), ['nx', 'ex' => $retryAfter]);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$message = strtolower($e->getMessage());
if (str_contains($message, 'daily')) {
return 600;
}
if (str_contains($message, 'ten secondly')) {
return 10;
}
if (str_contains($message, 'secondly')) {
return 1;
}
$this->log->warning('[Hubspot] No retry-after header or known message, using default', [
'exception_class' => get_class($e),
'message' => $message,
]);
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Show Replace Field
Search History
429
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
23/223
Previous Occurrence
Next Occurrence
Filter Search Results...
|
19199
|
NULL
|
NULL
|
NULL
|
|
19207
|
824
|
25
|
2026-05-11T12:35:36.795699+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778502936795_m1.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
67
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall The API call to execute
* @return T The result of the API call
*
* @throws RateLimitException When rate limit is hit or cached rate limit is active
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedExpiresAt = Redis::get($cacheKey);
if (is_string($cachedExpiresAt) && is_numeric($cachedExpiresAt)) {
$remaining = max(1, (int) $cachedExpiresAt - time());
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
$remaining,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
// NX: only the first job to receive a 429 in this burst sets the key.
// Subsequent 429s in the same burst leave the TTL untouched so the
// window is not reset by every concurrent job hitting the limit.
Redis::set($cacheKey, (string) (time() + $retryAfter), ['nx', 'ex' => $retryAfter]);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$message = strtolower($e->getMessage());
if (str_contains($message, 'daily')) {
return 600;
}
if (str_contains($message, 'ten secondly')) {
return 10;
}
if (str_contains($message, 'secondly')) {
return 1;
}
$this->log->warning('[Hubspot] No retry-after header or known message, using default', [
'exception_class' => get_class($e),
'message' => $message,
]);
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Show Replace Field
Search History
429
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
23/223
Previous Occurrence
Next Occurrence
Filter Search Results...
|
[{"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-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20725-handle-HS-search-rate-limit","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":"HandleHubspotRateLimitTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","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},{"role":"AXStaticText","text":"2","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"67","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","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\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Execute a HubSpot API call with rate limit handling.\n *\n * On a 429, stores the absolute expiry timestamp with SET NX (first writer wins).\n * This means all subsequent jobs that also receive 429 in the same burst do not\n * reset the TTL — the window is anchored to the first 429, not the last.\n * Readers compute the remaining wait from the stored timestamp, so jobs that check\n * the cache near expiry are not delayed longer than necessary.\n *\n * @template T\n * @param callable(): T $apiCall The API call to execute\n * @return T The result of the API call\n *\n * @throws RateLimitException When rate limit is hit or cached rate limit is active\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedExpiresAt = Redis::get($cacheKey);\n if (is_string($cachedExpiresAt) && is_numeric($cachedExpiresAt)) {\n $remaining = max(1, (int) $cachedExpiresAt - time());\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n $remaining,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n // NX: only the first job to receive a 429 in this burst sets the key.\n // Subsequent 429s in the same burst leave the TTL untouched so the\n // window is not reset by every concurrent job hitting the limit.\n Redis::set($cacheKey, (string) (time() + $retryAfter), ['nx', 'ex' => $retryAfter]);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $message = strtolower($e->getMessage());\n\n if (str_contains($message, 'daily')) {\n return 600;\n }\n if (str_contains($message, 'ten secondly')) {\n return 10;\n }\n if (str_contains($message, 'secondly')) {\n return 1;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or known message, using default', [\n 'exception_class' => get_class($e),\n 'message' => $message,\n ]);\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Illuminate\\Support\\Facades\\Redis;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Execute a HubSpot API call with rate limit handling.\n *\n * On a 429, stores the absolute expiry timestamp with SET NX (first writer wins).\n * This means all subsequent jobs that also receive 429 in the same burst do not\n * reset the TTL — the window is anchored to the first 429, not the last.\n * Readers compute the remaining wait from the stored timestamp, so jobs that check\n * the cache near expiry are not delayed longer than necessary.\n *\n * @template T\n * @param callable(): T $apiCall The API call to execute\n * @return T The result of the API call\n *\n * @throws RateLimitException When rate limit is hit or cached rate limit is active\n */\n private function executeRequest(callable $apiCall)\n {\n $cacheKey = $this->getRateLimitCacheKey();\n\n $cachedExpiresAt = Redis::get($cacheKey);\n if (is_string($cachedExpiresAt) && is_numeric($cachedExpiresAt)) {\n $remaining = max(1, (int) $cachedExpiresAt - time());\n throw new RateLimitException(\n 'Hubspot rate limit (cached circuit-breaker)',\n $remaining,\n );\n }\n\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n // NX: only the first job to receive a 429 in this burst sets the key.\n // Subsequent 429s in the same burst leave the TTL untouched so the\n // window is not reset by every concurrent job hitting the limit.\n Redis::set($cacheKey, (string) (time() + $retryAfter), ['nx', 'ex' => $retryAfter]);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n private function getRateLimitCacheKey(): string\n {\n return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n if ($e instanceof BadRequest\n || $e instanceof DealApiException\n || $e instanceof ContactApiException\n || $e instanceof CompanyApiException\n || $e instanceof \\GuzzleHttp\\Exception\\RequestException\n ) {\n return (int) $e->getCode() === 429;\n }\n\n return false;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n $message = strtolower($e->getMessage());\n\n if (str_contains($message, 'daily')) {\n return 600;\n }\n if (str_contains($message, 'ten secondly')) {\n return 10;\n }\n if (str_contains($message, 'secondly')) {\n return 1;\n }\n\n $this->log->warning('[Hubspot] No retry-after header or known message, using default', [\n 'exception_class' => get_class($e),\n 'message' => $message,\n ]);\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n return $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n return $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Replace Field","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Search History","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"429","depth":4,"on_screen":true,"value":"429","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Match Case","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Words","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Regex","depth":3,"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Replace History","depth":3,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.024444444},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Replace","depth":4,"on_screen":false,"role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":3,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.024444444},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Preserve case","depth":3,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.024444444},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"23/223","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Occurrence","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Occurrence","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Filter Search Results","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-7748219105398282943
|
5225837844320127076
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20725-handle-HS-search Project: faVsco.js, menu
JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
67
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Illuminate\Support\Facades\Redis;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall The API call to execute
* @return T The result of the API call
*
* @throws RateLimitException When rate limit is hit or cached rate limit is active
*/
private function executeRequest(callable $apiCall)
{
$cacheKey = $this->getRateLimitCacheKey();
$cachedExpiresAt = Redis::get($cacheKey);
if (is_string($cachedExpiresAt) && is_numeric($cachedExpiresAt)) {
$remaining = max(1, (int) $cachedExpiresAt - time());
throw new RateLimitException(
'Hubspot rate limit (cached circuit-breaker)',
$remaining,
);
}
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
// NX: only the first job to receive a 429 in this burst sets the key.
// Subsequent 429s in the same burst leave the TTL untouched so the
// window is not reset by every concurrent job hitting the limit.
Redis::set($cacheKey, (string) (time() + $retryAfter), ['nx', 'ex' => $retryAfter]);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
private function getRateLimitCacheKey(): string
{
return sprintf('hubspot:ratelimit:portal:%d', $this->config->getId());
}
public function isHubspotRateLimit(Throwable $e): bool
{
if ($e instanceof BadRequest
|| $e instanceof DealApiException
|| $e instanceof ContactApiException
|| $e instanceof CompanyApiException
|| $e instanceof \GuzzleHttp\Exception\RequestException
) {
return (int) $e->getCode() === 429;
}
return false;
}
public function parseRetryAfter(Throwable $e): int
{
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
$message = strtolower($e->getMessage());
if (str_contains($message, 'daily')) {
return 600;
}
if (str_contains($message, 'ten secondly')) {
return 10;
}
if (str_contains($message, 'secondly')) {
return 1;
}
$this->log->warning('[Hubspot] No retry-after header or known message, using default', [
'exception_class' => get_class($e),
'message' => $message,
]);
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
return $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
return $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Show Replace Field
Search History
429
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
23/223
Previous Occurrence
Next Occurrence
Filter Search Results...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
27598
|
NULL
|
0
|
2026-05-12T14:32:13.803323+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778596333803_m1.jpg...
|
Firefox
|
DXP4800PLUS-B5F8 — Personal
|
True
|
nas.lakylak.xyz/desktop/#/
|
monitor_1
|
NULL
|
NULL
|
NULL
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778596333803_m1.jpg...
|
Screenpipe — Archive
Screenpipe — Archive
All docs Screenpipe — Archive
Screenpipe — Archive
All docs · AFFiNE
All docs · AFFiNE
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Close tab
New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
Claude
Claude
Manage extra usage for paid Claude plans | Claude Help Center
Manage extra usage for paid Claude plans | Claude Help Center
New Tab
New Tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Open history (⇧⌘H)...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All docs · AFFiNE","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Claude","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Claude","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Manage extra usage for paid Claude plans | Claude Help Center","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Manage extra usage for paid Claude plans | Claude Help Center","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-7747737819540923036
|
5715520968609353667
|
click
|
accessibility
|
NULL
|
Screenpipe — Archive
Screenpipe — Archive
All docs Screenpipe — Archive
Screenpipe — Archive
All docs · AFFiNE
All docs · AFFiNE
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
Close tab
New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
Claude
Claude
Manage extra usage for paid Claude plans | Claude Help Center
Manage extra usage for paid Claude plans | Claude Help Center
New Tab
New Tab
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Open history (⇧⌘H)...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
2313
|
101
|
13
|
2026-05-07T11:10:32.653713+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778152232653_m1.jpg...
|
PhpStorm
|
faVsco.js – HS_local [jiminny@localhost]
|
True
|
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
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
6
1
6
Previous Highlighted Error
Next Highlighted Error
# [PASSWORD_DOTS] HS [PASSWORD_DOTS]
select * from teams where id = 2; # 2
select * from features; # 2
select * from team_features where team_id = 2; # 2
select * from crm_configurations where id = 2; # 2
select * from users where team_id = 2; #
select * from playbooks where team_id = 2; # event 38
select * from playbook_categories where playbook_id = 38; #
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;
https://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624
https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0
SELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;
# 609126 softphone tr. 11241
SELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;
# 608874 conference tr. 11226 crmId: 103422236596
select * from ai_prompts where transcription_id IN (11241, 11226);
select * from activity_summary_logs where activity_id = 608874;
select * from sidekick_settings;
select * from default_activity_types;
select * from crm_field_data where activity_id = 1223;
select * from crm_layouts where crm_configuration_id = 2;
SELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);
select * from crm_fields where crm_configuration_id = 11 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);
SELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;
SELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u
on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 2 and sa.provider = 'hubspot';
select * from social_accounts where id = 1499;
select * from opportunities where team_id = 2
and crm_provider_id IN ('51317301383');
select * from contacts where id = 85;
select * from opportunities where team_id = 2 order by id desc;
select * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112
select * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112
select * from opportunity_contacts where opportunity_id = 5117;
select * from crm_field_data where object_id = 1365;
SELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);
select * from features;
select * from team_features where team_id IN (1);
select * from team_features where feature_id IN (36);
SHOW CREATE TABLE opportunity_contacts;
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';
# $slug = 'HUBSPOT_WEBHOOK_SYNC';
# $team = Jiminny\Models\Team::find(2);
# $feature = Feature::query()->where('slug', $slug)->first();
# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);
# hubspot_webhook_metrics
select * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365
SELECT * FROM opportunity_contacts WHERE opportunity_id = '414';
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';
select * from contacts where id in (414, 464);
select * from activities where crm_configuration_id = 2;
select settings from crm_configurations where id = 11;
select * from teams; # 1, 2
select * from users;
select * from crm_configurations where id = 39;
select * from team_features where team_id = 2;
select * from features;
# SELECT * FROM opportunities WHERE crm_configuration_id = 2
# order by id desc;
# and crm_provider_id = '49908861993';
select * from activity_providers where id IN (443, 202, 203, 227);
select * from activity_imports where id = 795889;
select c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id
where c.provider = 'hubspot';
select * from crm_configurations crm JOIN teams t on crm.team_id = t.id
where provider = 'hubspot';
SELECT * FROM teams WHERE id = 31;
SELECT * FROM users WHERE id = 257;
SELECT * FROM opportunities WHERE team_id = 2;
select * from opportunity_contacts where opportunity_id = 5124;
select * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)
select * from activities where crm_configuration_id = 13;
SELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141
select id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;
SELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;
SELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;
SELECT * FROM contacts WHERE team_id = 2 order by id desc;
select * from opportunity_contacts where contact_id = 6223;
SELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;
select * from crm_profiles where crm_configuration_id = 2;
select * from activities where account_id = 46;
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","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":"Execute","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"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},{"role":"AXStaticText","text":"6","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"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":"# **************************** HS **************************************\n\nselect * from teams where id = 2; # 2\nselect * from features; # 2\nselect * from team_features where team_id = 2; # 2\nselect * from crm_configurations where id = 2; # 2\nselect * from users where team_id = 2; #\nselect * from playbooks where team_id = 2; # event 38\nselect * from playbook_categories where playbook_id = 38; #\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;\nhttps://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624\n https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0\n\nSELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;\n# 609126 softphone tr. 11241\n\nSELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;\n# 608874 conference tr. 11226 crmId: 103422236596\n\nselect * from ai_prompts where transcription_id IN (11241, 11226);\nselect * from activity_summary_logs where activity_id = 608874;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nselect * from crm_field_data where activity_id = 1223;\n\nselect * from crm_layouts where crm_configuration_id = 2;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);\nselect * from crm_fields where crm_configuration_id = 11 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);\n\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u\n on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 2 and sa.provider = 'hubspot';\n\nselect * from social_accounts where id = 1499;\n\nselect * from opportunities where team_id = 2\nand crm_provider_id IN ('51317301383');\n\nselect * from contacts where id = 85;\n\nselect * from opportunities where team_id = 2 order by id desc;\nselect * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112\nselect * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112\nselect * from opportunity_contacts where opportunity_id = 5117;\nselect * from crm_field_data where object_id = 1365;\nSELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);\n\nselect * from features;\nselect * from team_features where team_id IN (1);\nselect * from team_features where feature_id IN (36);\n\nSHOW CREATE TABLE opportunity_contacts;\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';\n\n# $slug = 'HUBSPOT_WEBHOOK_SYNC';\n# $team = Jiminny\\Models\\Team::find(2);\n# $feature = Feature::query()->where('slug', $slug)->first();\n# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);\n\n# hubspot_webhook_metrics\n\nselect * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365\nSELECT * FROM opportunity_contacts WHERE opportunity_id = '414';\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';\nselect * from contacts where id in (414, 464);\n\nselect * from activities where crm_configuration_id = 2;\n\nselect settings from crm_configurations where id = 11;\n\nselect * from teams; # 1, 2\nselect * from users;\nselect * from crm_configurations where id = 39;\nselect * from team_features where team_id = 2;\nselect * from features;\n# SELECT * FROM opportunities WHERE crm_configuration_id = 2\n# order by id desc;\n# and crm_provider_id = '49908861993';\n\n\nselect * from activity_providers where id IN (443, 202, 203, 227);\n\nselect * from activity_imports where id = 795889;\n\nselect c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id\nwhere c.provider = 'hubspot';\n\nselect * from crm_configurations crm JOIN teams t on crm.team_id = t.id\nwhere provider = 'hubspot';\nSELECT * FROM teams WHERE id = 31;\nSELECT * FROM users WHERE id = 257;\nSELECT * FROM opportunities WHERE team_id = 2;\n\nselect * from opportunity_contacts where opportunity_id = 5124;\nselect * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)\n\nselect * from activities where crm_configuration_id = 13;\n\nSELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141\n\n\nselect id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;\nSELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 order by id desc;\nselect * from opportunity_contacts where contact_id = 6223;\nSELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;\n\nselect * from crm_profiles where crm_configuration_id = 2;\n\nselect * from activities where account_id = 46;","depth":4,"on_screen":true,"value":"# **************************** HS **************************************\n\nselect * from teams where id = 2; # 2\nselect * from features; # 2\nselect * from team_features where team_id = 2; # 2\nselect * from crm_configurations where id = 2; # 2\nselect * from users where team_id = 2; #\nselect * from playbooks where team_id = 2; # event 38\nselect * from playbook_categories where playbook_id = 38; #\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;\nhttps://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624\n https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0\n\nSELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;\n# 609126 softphone tr. 11241\n\nSELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;\n# 608874 conference tr. 11226 crmId: 103422236596\n\nselect * from ai_prompts where transcription_id IN (11241, 11226);\nselect * from activity_summary_logs where activity_id = 608874;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nselect * from crm_field_data where activity_id = 1223;\n\nselect * from crm_layouts where crm_configuration_id = 2;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);\nselect * from crm_fields where crm_configuration_id = 11 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);\n\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u\n on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 2 and sa.provider = 'hubspot';\n\nselect * from social_accounts where id = 1499;\n\nselect * from opportunities where team_id = 2\nand crm_provider_id IN ('51317301383');\n\nselect * from contacts where id = 85;\n\nselect * from opportunities where team_id = 2 order by id desc;\nselect * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112\nselect * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112\nselect * from opportunity_contacts where opportunity_id = 5117;\nselect * from crm_field_data where object_id = 1365;\nSELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);\n\nselect * from features;\nselect * from team_features where team_id IN (1);\nselect * from team_features where feature_id IN (36);\n\nSHOW CREATE TABLE opportunity_contacts;\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';\n\n# $slug = 'HUBSPOT_WEBHOOK_SYNC';\n# $team = Jiminny\\Models\\Team::find(2);\n# $feature = Feature::query()->where('slug', $slug)->first();\n# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);\n\n# hubspot_webhook_metrics\n\nselect * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365\nSELECT * FROM opportunity_contacts WHERE opportunity_id = '414';\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';\nselect * from contacts where id in (414, 464);\n\nselect * from activities where crm_configuration_id = 2;\n\nselect settings from crm_configurations where id = 11;\n\nselect * from teams; # 1, 2\nselect * from users;\nselect * from crm_configurations where id = 39;\nselect * from team_features where team_id = 2;\nselect * from features;\n# SELECT * FROM opportunities WHERE crm_configuration_id = 2\n# order by id desc;\n# and crm_provider_id = '49908861993';\n\n\nselect * from activity_providers where id IN (443, 202, 203, 227);\n\nselect * from activity_imports where id = 795889;\n\nselect c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id\nwhere c.provider = 'hubspot';\n\nselect * from crm_configurations crm JOIN teams t on crm.team_id = t.id\nwhere provider = 'hubspot';\nSELECT * FROM teams WHERE id = 31;\nSELECT * FROM users WHERE id = 257;\nSELECT * FROM opportunities WHERE team_id = 2;\n\nselect * from opportunity_contacts where opportunity_id = 5124;\nselect * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)\n\nselect * from activities where crm_configuration_id = 13;\n\nSELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141\n\n\nselect id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;\nSELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 order by id desc;\nselect * from opportunity_contacts where contact_id = 6223;\nSELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;\n\nselect * from crm_profiles where crm_configuration_id = 2;\n\nselect * from activities where account_id = 46;","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}]...
|
-7747293802907390058
|
921758650370266701
|
click
|
accessibility
|
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
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
6
1
6
Previous Highlighted Error
Next Highlighted Error
# [PASSWORD_DOTS] HS [PASSWORD_DOTS]
select * from teams where id = 2; # 2
select * from features; # 2
select * from team_features where team_id = 2; # 2
select * from crm_configurations where id = 2; # 2
select * from users where team_id = 2; #
select * from playbooks where team_id = 2; # event 38
select * from playbook_categories where playbook_id = 38; #
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;
https://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624
https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0
SELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;
# 609126 softphone tr. 11241
SELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;
# 608874 conference tr. 11226 crmId: 103422236596
select * from ai_prompts where transcription_id IN (11241, 11226);
select * from activity_summary_logs where activity_id = 608874;
select * from sidekick_settings;
select * from default_activity_types;
select * from crm_field_data where activity_id = 1223;
select * from crm_layouts where crm_configuration_id = 2;
SELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);
select * from crm_fields where crm_configuration_id = 11 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);
SELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;
SELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u
on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 2 and sa.provider = 'hubspot';
select * from social_accounts where id = 1499;
select * from opportunities where team_id = 2
and crm_provider_id IN ('51317301383');
select * from contacts where id = 85;
select * from opportunities where team_id = 2 order by id desc;
select * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112
select * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112
select * from opportunity_contacts where opportunity_id = 5117;
select * from crm_field_data where object_id = 1365;
SELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);
select * from features;
select * from team_features where team_id IN (1);
select * from team_features where feature_id IN (36);
SHOW CREATE TABLE opportunity_contacts;
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';
# $slug = 'HUBSPOT_WEBHOOK_SYNC';
# $team = Jiminny\Models\Team::find(2);
# $feature = Feature::query()->where('slug', $slug)->first();
# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);
# hubspot_webhook_metrics
select * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365
SELECT * FROM opportunity_contacts WHERE opportunity_id = '414';
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';
select * from contacts where id in (414, 464);
select * from activities where crm_configuration_id = 2;
select settings from crm_configurations where id = 11;
select * from teams; # 1, 2
select * from users;
select * from crm_configurations where id = 39;
select * from team_features where team_id = 2;
select * from features;
# SELECT * FROM opportunities WHERE crm_configuration_id = 2
# order by id desc;
# and crm_provider_id = '49908861993';
select * from activity_providers where id IN (443, 202, 203, 227);
select * from activity_imports where id = 795889;
select c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id
where c.provider = 'hubspot';
select * from crm_configurations crm JOIN teams t on crm.team_id = t.id
where provider = 'hubspot';
SELECT * FROM teams WHERE id = 31;
SELECT * FROM users WHERE id = 257;
SELECT * FROM opportunities WHERE team_id = 2;
select * from opportunity_contacts where opportunity_id = 5124;
select * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)
select * from activities where crm_configuration_id = 13;
SELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141
select id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;
SELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;
SELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;
SELECT * FROM contacts WHERE team_id = 2 order by id desc;
select * from opportunity_contacts where contact_id = 6223;
SELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;
select * from crm_profiles where crm_configuration_id = 2;
select * from activities where account_id = 46;
Sync Changes
Hide This Notification
Code changed:
Hide...
|
2311
|
NULL
|
NULL
|
NULL
|
|
4888
|
175
|
21
|
2026-05-07T14:36:47.150247+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778164607150_m1.jpg...
|
PhpStorm
|
faVsco.js – HubspotPaginationService.php
|
True
|
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
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
6
1
6
Previous Highlighted Error
Next Highlighted Error
# [PASSWORD_DOTS] HS [PASSWORD_DOTS]
select * from teams where id = 2; # 2
select * from features; # 2
select * from team_features where team_id = 2; # 2
select * from crm_configurations where id = 2; # 2
select * from users where team_id = 2; #
select * from playbooks where team_id = 2; # event 38
select * from playbook_categories where playbook_id = 38; #
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;
https://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624
https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0
SELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;
# 609126 softphone tr. 11241
SELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;
# 608874 conference tr. 11226 crmId: 103422236596
select * from ai_prompts where transcription_id IN (11241, 11226);
select * from activity_summary_logs where activity_id = 608874;
select * from sidekick_settings;
select * from default_activity_types;
select * from crm_field_data where activity_id = 1223;
select * from crm_layouts where crm_configuration_id = 2;
SELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);
select * from crm_fields where crm_configuration_id = 11 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);
SELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;
SELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u
on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 2 and sa.provider = 'hubspot';
select * from social_accounts where id = 1499;
select * from opportunities where team_id = 2
and crm_provider_id IN ('51317301383');
select * from contacts where id = 85;
select * from opportunities where team_id = 2 order by id desc;
select * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112
select * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112
select * from opportunity_contacts where opportunity_id = 5117;
select * from crm_field_data where object_id = 1365;
SELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);
select * from features;
select * from team_features where team_id IN (1);
select * from team_features where feature_id IN (36);
SHOW CREATE TABLE opportunity_contacts;
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';
# $slug = 'HUBSPOT_WEBHOOK_SYNC';
# $team = Jiminny\Models\Team::find(2);
# $feature = Feature::query()->where('slug', $slug)->first();
# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);
# hubspot_webhook_metrics
select * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365
SELECT * FROM opportunity_contacts WHERE opportunity_id = '414';
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';
select * from contacts where id in (414, 464);
select * from activities where crm_configuration_id = 2;
select settings from crm_configurations where id = 11;
select * from teams; # 1, 2
select * from users;
select * from crm_configurations where id = 39;
select * from team_features where team_id = 2;
select * from features;
# SELECT * FROM opportunities WHERE crm_configuration_id = 2
# order by id desc;
# and crm_provider_id = '49908861993';
select * from activity_providers where id IN (443, 202, 203, 227);
select * from activity_imports where id = 795889;
select c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id
where c.provider = 'hubspot';
select * from crm_configurations crm JOIN teams t on crm.team_id = t.id
where provider = 'hubspot';
SELECT * FROM teams WHERE id = 31;
SELECT * FROM users WHERE id = 257;
SELECT * FROM opportunities WHERE team_id = 2;
select * from opportunity_contacts where opportunity_id = 5124;
select * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)
select * from activities where crm_configuration_id = 13;
SELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141
select id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;
SELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;
SELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;
SELECT * FROM contacts WHERE team_id = 2 order by id desc;
select * from opportunity_contacts where contact_id = 6223;
SELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;
select * from crm_profiles where crm_configuration_id = 2;
select * from activities where account_id = 46;
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":"Execute","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"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},{"role":"AXStaticText","text":"6","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"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":"# **************************** HS **************************************\n\nselect * from teams where id = 2; # 2\nselect * from features; # 2\nselect * from team_features where team_id = 2; # 2\nselect * from crm_configurations where id = 2; # 2\nselect * from users where team_id = 2; #\nselect * from playbooks where team_id = 2; # event 38\nselect * from playbook_categories where playbook_id = 38; #\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;\nhttps://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624\n https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0\n\nSELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;\n# 609126 softphone tr. 11241\n\nSELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;\n# 608874 conference tr. 11226 crmId: 103422236596\n\nselect * from ai_prompts where transcription_id IN (11241, 11226);\nselect * from activity_summary_logs where activity_id = 608874;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nselect * from crm_field_data where activity_id = 1223;\n\nselect * from crm_layouts where crm_configuration_id = 2;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);\nselect * from crm_fields where crm_configuration_id = 11 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);\n\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u\n on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 2 and sa.provider = 'hubspot';\n\nselect * from social_accounts where id = 1499;\n\nselect * from opportunities where team_id = 2\nand crm_provider_id IN ('51317301383');\n\nselect * from contacts where id = 85;\n\nselect * from opportunities where team_id = 2 order by id desc;\nselect * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112\nselect * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112\nselect * from opportunity_contacts where opportunity_id = 5117;\nselect * from crm_field_data where object_id = 1365;\nSELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);\n\nselect * from features;\nselect * from team_features where team_id IN (1);\nselect * from team_features where feature_id IN (36);\n\nSHOW CREATE TABLE opportunity_contacts;\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';\n\n# $slug = 'HUBSPOT_WEBHOOK_SYNC';\n# $team = Jiminny\\Models\\Team::find(2);\n# $feature = Feature::query()->where('slug', $slug)->first();\n# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);\n\n# hubspot_webhook_metrics\n\nselect * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365\nSELECT * FROM opportunity_contacts WHERE opportunity_id = '414';\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';\nselect * from contacts where id in (414, 464);\n\nselect * from activities where crm_configuration_id = 2;\n\nselect settings from crm_configurations where id = 11;\n\nselect * from teams; # 1, 2\nselect * from users;\nselect * from crm_configurations where id = 39;\nselect * from team_features where team_id = 2;\nselect * from features;\n# SELECT * FROM opportunities WHERE crm_configuration_id = 2\n# order by id desc;\n# and crm_provider_id = '49908861993';\n\n\nselect * from activity_providers where id IN (443, 202, 203, 227);\n\nselect * from activity_imports where id = 795889;\n\nselect c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id\nwhere c.provider = 'hubspot';\n\nselect * from crm_configurations crm JOIN teams t on crm.team_id = t.id\nwhere provider = 'hubspot';\nSELECT * FROM teams WHERE id = 31;\nSELECT * FROM users WHERE id = 257;\nSELECT * FROM opportunities WHERE team_id = 2;\n\nselect * from opportunity_contacts where opportunity_id = 5124;\nselect * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)\n\nselect * from activities where crm_configuration_id = 13;\n\nSELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141\n\n\nselect id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;\nSELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 order by id desc;\nselect * from opportunity_contacts where contact_id = 6223;\nSELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;\n\nselect * from crm_profiles where crm_configuration_id = 2;\n\nselect * from activities where account_id = 46;","depth":4,"on_screen":true,"value":"# **************************** HS **************************************\n\nselect * from teams where id = 2; # 2\nselect * from features; # 2\nselect * from team_features where team_id = 2; # 2\nselect * from crm_configurations where id = 2; # 2\nselect * from users where team_id = 2; #\nselect * from playbooks where team_id = 2; # event 38\nselect * from playbook_categories where playbook_id = 38; #\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;\nhttps://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624\n https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0\n\nSELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;\n# 609126 softphone tr. 11241\n\nSELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;\n# 608874 conference tr. 11226 crmId: 103422236596\n\nselect * from ai_prompts where transcription_id IN (11241, 11226);\nselect * from activity_summary_logs where activity_id = 608874;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nselect * from crm_field_data where activity_id = 1223;\n\nselect * from crm_layouts where crm_configuration_id = 2;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);\nselect * from crm_fields where crm_configuration_id = 11 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);\n\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u\n on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 2 and sa.provider = 'hubspot';\n\nselect * from social_accounts where id = 1499;\n\nselect * from opportunities where team_id = 2\nand crm_provider_id IN ('51317301383');\n\nselect * from contacts where id = 85;\n\nselect * from opportunities where team_id = 2 order by id desc;\nselect * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112\nselect * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112\nselect * from opportunity_contacts where opportunity_id = 5117;\nselect * from crm_field_data where object_id = 1365;\nSELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);\n\nselect * from features;\nselect * from team_features where team_id IN (1);\nselect * from team_features where feature_id IN (36);\n\nSHOW CREATE TABLE opportunity_contacts;\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';\n\n# $slug = 'HUBSPOT_WEBHOOK_SYNC';\n# $team = Jiminny\\Models\\Team::find(2);\n# $feature = Feature::query()->where('slug', $slug)->first();\n# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);\n\n# hubspot_webhook_metrics\n\nselect * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365\nSELECT * FROM opportunity_contacts WHERE opportunity_id = '414';\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';\nselect * from contacts where id in (414, 464);\n\nselect * from activities where crm_configuration_id = 2;\n\nselect settings from crm_configurations where id = 11;\n\nselect * from teams; # 1, 2\nselect * from users;\nselect * from crm_configurations where id = 39;\nselect * from team_features where team_id = 2;\nselect * from features;\n# SELECT * FROM opportunities WHERE crm_configuration_id = 2\n# order by id desc;\n# and crm_provider_id = '49908861993';\n\n\nselect * from activity_providers where id IN (443, 202, 203, 227);\n\nselect * from activity_imports where id = 795889;\n\nselect c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id\nwhere c.provider = 'hubspot';\n\nselect * from crm_configurations crm JOIN teams t on crm.team_id = t.id\nwhere provider = 'hubspot';\nSELECT * FROM teams WHERE id = 31;\nSELECT * FROM users WHERE id = 257;\nSELECT * FROM opportunities WHERE team_id = 2;\n\nselect * from opportunity_contacts where opportunity_id = 5124;\nselect * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)\n\nselect * from activities where crm_configuration_id = 13;\n\nSELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141\n\n\nselect id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;\nSELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 order by id desc;\nselect * from opportunity_contacts where contact_id = 6223;\nSELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;\n\nselect * from crm_profiles where crm_configuration_id = 2;\n\nselect * from activities where account_id = 46;","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}]...
|
-7747293802907390058
|
921758650370266701
|
click
|
accessibility
|
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
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
6
1
6
Previous Highlighted Error
Next Highlighted Error
# [PASSWORD_DOTS] HS [PASSWORD_DOTS]
select * from teams where id = 2; # 2
select * from features; # 2
select * from team_features where team_id = 2; # 2
select * from crm_configurations where id = 2; # 2
select * from users where team_id = 2; #
select * from playbooks where team_id = 2; # event 38
select * from playbook_categories where playbook_id = 38; #
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;
https://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624
https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0
SELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;
# 609126 softphone tr. 11241
SELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;
# 608874 conference tr. 11226 crmId: 103422236596
select * from ai_prompts where transcription_id IN (11241, 11226);
select * from activity_summary_logs where activity_id = 608874;
select * from sidekick_settings;
select * from default_activity_types;
select * from crm_field_data where activity_id = 1223;
select * from crm_layouts where crm_configuration_id = 2;
SELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);
select * from crm_fields where crm_configuration_id = 11 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);
SELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;
SELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u
on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 2 and sa.provider = 'hubspot';
select * from social_accounts where id = 1499;
select * from opportunities where team_id = 2
and crm_provider_id IN ('51317301383');
select * from contacts where id = 85;
select * from opportunities where team_id = 2 order by id desc;
select * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112
select * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112
select * from opportunity_contacts where opportunity_id = 5117;
select * from crm_field_data where object_id = 1365;
SELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);
select * from features;
select * from team_features where team_id IN (1);
select * from team_features where feature_id IN (36);
SHOW CREATE TABLE opportunity_contacts;
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';
# $slug = 'HUBSPOT_WEBHOOK_SYNC';
# $team = Jiminny\Models\Team::find(2);
# $feature = Feature::query()->where('slug', $slug)->first();
# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);
# hubspot_webhook_metrics
select * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365
SELECT * FROM opportunity_contacts WHERE opportunity_id = '414';
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';
select * from contacts where id in (414, 464);
select * from activities where crm_configuration_id = 2;
select settings from crm_configurations where id = 11;
select * from teams; # 1, 2
select * from users;
select * from crm_configurations where id = 39;
select * from team_features where team_id = 2;
select * from features;
# SELECT * FROM opportunities WHERE crm_configuration_id = 2
# order by id desc;
# and crm_provider_id = '49908861993';
select * from activity_providers where id IN (443, 202, 203, 227);
select * from activity_imports where id = 795889;
select c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id
where c.provider = 'hubspot';
select * from crm_configurations crm JOIN teams t on crm.team_id = t.id
where provider = 'hubspot';
SELECT * FROM teams WHERE id = 31;
SELECT * FROM users WHERE id = 257;
SELECT * FROM opportunities WHERE team_id = 2;
select * from opportunity_contacts where opportunity_id = 5124;
select * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)
select * from activities where crm_configuration_id = 13;
SELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141
select id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;
SELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;
SELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;
SELECT * FROM contacts WHERE team_id = 2 order by id desc;
select * from opportunity_contacts where contact_id = 6223;
SELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;
select * from crm_profiles where crm_configuration_id = 2;
select * from activities where account_id = 46;
Sync Changes
Hide This Notification
Code changed:
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
24376
|
1018
|
3
|
2026-05-12T09:07:37.466140+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778576857466_m1.jpg...
|
Firefox
|
(172) Papa Juan Pablo II hablando en 13 Idiomas - (172) Papa Juan Pablo II hablando en 13 Idiomas - YouTube — Personal...
|
True
|
www.youtube.com/watch?v=apLRKbprP54
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
New Tab
New Tab
Screenpipe — Archive
Screenpipe — New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
All docs · AFFiNE
All docs · AFFiNE
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
(172) Papa Juan Pablo II hablando en 13 Idiomas - YouTube
Mute tab
(172) Papa Juan Pablo II hablando en 13 Idiomas - YouTube
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Sprievodca
Domovská stránka YouTube
BG
Preskočiť navigáciu
Preskočiť navigáciu
Karol Wojtyla speaking langauges
Karol Wojtyla speaking langauges
Vymazať vyhľadávací dopyt
Search
Vyhľadávať hlasom
Vytvoriť
Vytvoriť
Upozornenia
9+
Ponuka účtu
Zobraziť karty
Vodoznak kanála
Prehrávanie (k)
Klávesová skratka pre akciu Stlmiť: m
3 min 38 s z 5 min 42 s
3:38
/
5:42
Automatické prehrávanie je zapnuté
Titulky alebo skryté titulky sú nedostupné
Nastavenia
Režim kina (t)
Celá obrazovka (f)
Papa Juan Pablo II hablando en 13 Idiomas
Papa Juan Pablo II hablando en 13 Idiomas
Manoloyy
Manoloyy
124 tis. odberateľov
Prihlásiť sa na odber kanála Manoloyy.
Odoberať
Označiť, že sa mi toto video páči, tak ako 7 562 ďalším osobám
7,5 tis.
Toto video sa mi nepáči
Zdieľať
Zdieľať
Uložiť do zoznamu
Uložiť
Ďalšie akcie
350 tis. zhliadnutí
pred 8 rokmi
El Papa Juan Pablo II (Karol Wojtyla) hablando en inglés, español, alemán, portugués, francés, italiano, ruso, japonés, croata, checo, ucraniano, latín y polaco
...viac
...viac
916 komentárov
916
komentárov
Zoradiť komentáre
Zoradiť podľa
Pridajte komentár…
@danielnainggolan6258
@danielnainggolan6258
@danielnainggolan6258
@danielnainggolan6258
pred 1 rokom
pred 1 rokom
0:03
0:03
English/Inglés 🇬🇧
0:33
0:33
Spanish/idioma español 🇪🇸
1:07
1:07
German/idioma alemán 🇩🇪
1:35
1:35
Portuguese/Portugués 🇵🇹
1:55
1:55
French/Francés 🇫🇷
2:18
2:18
Italian/italiano 🇮🇹
2:52
2:52
Russian/idioma ruso 🇷🇺
3:15
3:15
Japanese/Japonés 🇯🇵
3:33
3:33
Croatian/idioma croata
4:01
4:01
Czech/Idioma checo 🇨🇿
4:34
4:34
Ukranian/Ucraniano 🇺🇦
5:00
5:00
Latin/latín 🇻🇦
5:24
5:24
Polish/polaco 🇵🇱
Zobraziť viac
Preložiť do jazyka angličtina
Označiť, že sa vám tento komentár páči, tak ako 57 ďalším ľuďom
57
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
@Flori-an
@Flori-an
@Flori-an
@Flori-an
pred 2 rokmi
pred 2 rokmi
It is really impressive how much effort he has made to always know at least a few sentences in the language corresponding to the country he has visited. The words always sound clear, and his voice is absolutely unmistakable anyway. :)
Označiť, že sa vám tento komentár páči, tak ako 119 ďalším ľuďom
119
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
1 odpoveď
1 odpoveď
@Chavezoid
@Chavezoid
@Chavezoid
@Chavezoid
pred 6 rokmi
pred 6 rokmi...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"All docs · AFFiNE","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All docs · AFFiNE","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"DXP4800PLUS-B5F8","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"DXP4800PLUS-B5F8","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: archive.db","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: archive.db","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SQLite Web: db.sqlite","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SQLite Web: db.sqlite","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"(172) Papa Juan Pablo II hablando en 13 Idiomas - YouTube","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXButton","text":"Mute tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"(172) Papa Juan Pablo II hablando en 13 Idiomas - YouTube","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.48576388,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.5086806,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.53194445,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.5552083,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.5784722,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Sprievodca","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Domovská stránka YouTube","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BG","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Preskočiť navigáciu","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Preskočiť navigáciu","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXComboBox","text":"Karol Wojtyla speaking langauges","depth":15,"on_screen":true,"value":"Karol Wojtyla speaking langauges","help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Karol Wojtyla speaking langauges","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Vymazať vyhľadávací dopyt","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search","depth":13,"on_screen":true,"help_text":"Hľadať","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Vyhľadávať hlasom","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Vytvoriť","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vytvoriť","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Upozornenia","depth":15,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"9+","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Ponuka účtu","depth":14,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Zobraziť karty","depth":19,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Vodoznak kanála","depth":19,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Prehrávanie (k)","depth":20,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Klávesová skratka pre akciu Stlmiť: m","depth":21,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"3 min 38 s z 5 min 42 s","depth":22,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3:38","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5:42","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Automatické prehrávanie je zapnuté","depth":19,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Titulky alebo skryté titulky sú nedostupné","depth":19,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Nastavenia","depth":19,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Režim kina (t)","depth":19,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Celá obrazovka (f)","depth":19,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Papa Juan Pablo II hablando en 13 Idiomas","depth":16,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Papa Juan Pablo II hablando en 13 Idiomas","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Manoloyy","depth":22,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Manoloyy","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"124 tis. odberateľov","depth":20,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Prihlásiť sa na odber kanála Manoloyy.","depth":20,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Odoberať","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Označiť, že sa mi toto video páči, tak ako 7 562 ďalším osobám","depth":24,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7,5 tis.","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Toto video sa mi nepáči","depth":24,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Zdieľať","depth":22,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Zdieľať","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Uložiť do zoznamu","depth":22,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Uložiť","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Ďalšie akcie","depth":20,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"350 tis. zhliadnutí","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"pred 8 rokmi","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"El Papa Juan Pablo II (Karol Wojtyla) hablando en inglés, español, alemán, portugués, francés, italiano, ruso, japonés, croata, checo, ucraniano, latín y polaco","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"...viac","depth":19,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"...viac","depth":20,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"916 komentárov","depth":19,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"916","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"komentárov","depth":21,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Zoradiť komentáre","depth":24,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Zoradiť podľa","depth":26,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Pridajte komentár…","depth":19,"on_screen":true,"value":"Pridajte komentár…","help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"@danielnainggolan6258","depth":21,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"@danielnainggolan6258","depth":23,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"@danielnainggolan6258","depth":24,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"@danielnainggolan6258","depth":25,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"pred 1 rokom","depth":24,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"pred 1 rokom","depth":25,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0:03","depth":23,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0:03","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"English/Inglés 🇬🇧","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0:33","depth":23,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0:33","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Spanish/idioma español 🇪🇸","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1:07","depth":23,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1:07","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"German/idioma alemán 🇩🇪","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1:35","depth":23,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1:35","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Portuguese/Portugués 🇵🇹","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"1:55","depth":23,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1:55","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"French/Francés 🇫🇷","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2:18","depth":23,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2:18","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Italian/italiano 🇮🇹","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"2:52","depth":23,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2:52","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Russian/idioma ruso 🇷🇺","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"3:15","depth":23,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3:15","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Japanese/Japonés 🇯🇵","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"3:33","depth":23,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3:33","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Croatian/idioma croata","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"4:01","depth":23,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4:01","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Czech/Idioma checo 🇨🇿","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"4:34","depth":23,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"4:34","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ukranian/Ucraniano 🇺🇦","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"5:00","depth":23,"bounds":{"left":0.67083335,"top":0.0,"width":0.01875,"height":0.018333333},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5:00","depth":24,"bounds":{"left":0.67083335,"top":0.0,"width":0.01875,"height":0.018333333},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Latin/latín 🇻🇦","depth":23,"bounds":{"left":0.68958336,"top":0.0,"width":0.058680557,"height":0.020555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"5:24","depth":23,"bounds":{"left":0.67083335,"top":0.0,"width":0.01875,"height":0.018333333},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5:24","depth":24,"bounds":{"left":0.67083335,"top":0.0,"width":0.01875,"height":0.018333333},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Polish/polaco 🇵🇱","depth":23,"bounds":{"left":0.68958336,"top":0.0,"width":0.074652776,"height":0.020555556},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Zobraziť viac","depth":22,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Preložiť do jazyka angličtina","depth":22,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Označiť, že sa vám tento komentár páči, tak ako 57 ďalším ľuďom","depth":24,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"57","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Tento komentár sa mi nepáči","depth":24,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Odpovedať","depth":24,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Odpovedať","depth":27,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Ponuka akcií","depth":22,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"@Flori-an","depth":21,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"@Flori-an","depth":23,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"@Flori-an","depth":24,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"@Flori-an","depth":25,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"pred 2 rokmi","depth":24,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"pred 2 rokmi","depth":25,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"It is really impressive how much effort he has made to always know at least a few sentences in the language corresponding to the country he has visited. The words always sound clear, and his voice is absolutely unmistakable anyway. :)","depth":24,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Označiť, že sa vám tento komentár páči, tak ako 119 ďalším ľuďom","depth":24,"bounds":{"left":0.6652778,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"119","depth":24,"bounds":{"left":0.6875,"top":0.0,"width":0.014236111,"height":0.016111111},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Tento komentár sa mi nepáči","depth":24,"bounds":{"left":0.70729166,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Odpovedať","depth":24,"bounds":{"left":0.73506945,"top":0.0,"width":0.056944445,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Odpovedať","depth":27,"bounds":{"left":0.7434028,"top":0.0,"width":0.04027778,"height":0.016111111},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Ponuka akcií","depth":22,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"1 odpoveď","depth":22,"bounds":{"left":0.6597222,"top":0.0,"width":0.08472222,"height":0.04},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1 odpoveď","depth":25,"bounds":{"left":0.67083335,"top":0.0,"width":0.045833334,"height":0.018333333},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"@Chavezoid","depth":21,"bounds":{"left":0.63472223,"top":0.037777778,"width":0.025,"height":0.043333333},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"@Chavezoid","depth":23,"bounds":{"left":0.67083335,"top":0.037777778,"width":0.05277778,"height":0.022222223},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"@Chavezoid","depth":24,"bounds":{"left":0.67083335,"top":0.037777778,"width":0.05,"height":0.022222223},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"@Chavezoid","depth":25,"bounds":{"left":0.67083335,"top":0.03888889,"width":0.05,"height":0.017777778},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"pred 6 rokmi","depth":24,"bounds":{"left":0.7236111,"top":0.037777778,"width":0.046527777,"height":0.02},"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"pred 6 rokmi","depth":25,"bounds":{"left":0.7236111,"top":0.04,"width":0.046527777,"height":0.016111111},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-7746638097562614530
|
1254390506675307494
|
visual_change
|
accessibility
|
NULL
|
New Tab
New Tab
Screenpipe — Archive
Screenpipe — New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
All docs · AFFiNE
All docs · AFFiNE
DXP4800PLUS-B5F8
DXP4800PLUS-B5F8
New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
SQLite Web: archive.db
SQLite Web: archive.db
SQLite Web: db.sqlite
SQLite Web: db.sqlite
(172) Papa Juan Pablo II hablando en 13 Idiomas - YouTube
Mute tab
(172) Papa Juan Pablo II hablando en 13 Idiomas - YouTube
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Sprievodca
Domovská stránka YouTube
BG
Preskočiť navigáciu
Preskočiť navigáciu
Karol Wojtyla speaking langauges
Karol Wojtyla speaking langauges
Vymazať vyhľadávací dopyt
Search
Vyhľadávať hlasom
Vytvoriť
Vytvoriť
Upozornenia
9+
Ponuka účtu
Zobraziť karty
Vodoznak kanála
Prehrávanie (k)
Klávesová skratka pre akciu Stlmiť: m
3 min 38 s z 5 min 42 s
3:38
/
5:42
Automatické prehrávanie je zapnuté
Titulky alebo skryté titulky sú nedostupné
Nastavenia
Režim kina (t)
Celá obrazovka (f)
Papa Juan Pablo II hablando en 13 Idiomas
Papa Juan Pablo II hablando en 13 Idiomas
Manoloyy
Manoloyy
124 tis. odberateľov
Prihlásiť sa na odber kanála Manoloyy.
Odoberať
Označiť, že sa mi toto video páči, tak ako 7 562 ďalším osobám
7,5 tis.
Toto video sa mi nepáči
Zdieľať
Zdieľať
Uložiť do zoznamu
Uložiť
Ďalšie akcie
350 tis. zhliadnutí
pred 8 rokmi
El Papa Juan Pablo II (Karol Wojtyla) hablando en inglés, español, alemán, portugués, francés, italiano, ruso, japonés, croata, checo, ucraniano, latín y polaco
...viac
...viac
916 komentárov
916
komentárov
Zoradiť komentáre
Zoradiť podľa
Pridajte komentár…
@danielnainggolan6258
@danielnainggolan6258
@danielnainggolan6258
@danielnainggolan6258
pred 1 rokom
pred 1 rokom
0:03
0:03
English/Inglés 🇬🇧
0:33
0:33
Spanish/idioma español 🇪🇸
1:07
1:07
German/idioma alemán 🇩🇪
1:35
1:35
Portuguese/Portugués 🇵🇹
1:55
1:55
French/Francés 🇫🇷
2:18
2:18
Italian/italiano 🇮🇹
2:52
2:52
Russian/idioma ruso 🇷🇺
3:15
3:15
Japanese/Japonés 🇯🇵
3:33
3:33
Croatian/idioma croata
4:01
4:01
Czech/Idioma checo 🇨🇿
4:34
4:34
Ukranian/Ucraniano 🇺🇦
5:00
5:00
Latin/latín 🇻🇦
5:24
5:24
Polish/polaco 🇵🇱
Zobraziť viac
Preložiť do jazyka angličtina
Označiť, že sa vám tento komentár páči, tak ako 57 ďalším ľuďom
57
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
@Flori-an
@Flori-an
@Flori-an
@Flori-an
pred 2 rokmi
pred 2 rokmi
It is really impressive how much effort he has made to always know at least a few sentences in the language corresponding to the country he has visited. The words always sound clear, and his voice is absolutely unmistakable anyway. :)
Označiť, že sa vám tento komentár páči, tak ako 119 ďalším ľuďom
119
Tento komentár sa mi nepáči
Odpovedať
Odpovedať
Ponuka akcií
1 odpoveď
1 odpoveď
@Chavezoid
@Chavezoid
@Chavezoid
@Chavezoid
pred 6 rokmi
pred 6 rokmi...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
2339
|
101
|
28
|
2026-05-07T11:11:52.557166+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778152312557_m1.jpg...
|
iTerm2
|
NULL
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
iTerm2ShellEditViewSessionScriptsProfilesWindowHel iTerm2ShellEditViewSessionScriptsProfilesWindowHelp(ah]Support Daily • in 49 m100% [Thu 7 May 14:11:52DEV (docker)181DOCKERLast login: Thu MayO ₴1DEV (docker)7 09:44:56 on ttys006H82APP (-zsh)83-zsh• 84screenpipe*•$5-zsh₴6Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20773-fix-automated-reports-user-pilot-tracking) $ devroot@docker_lamp_1:/home/jiminny# php artisan crm:sync-opportunity --teamId=2 --from='2026-05-01 00:00:00*Syncing opportunity for HubspotYour HubSpotaccount has become disconnected. Please login to Jiminny to reconnect. skipping...root@docker_lamp_1:/home/jiminny# php artisan jiminny:token-info -A 1499 -RDEVaccess_tokenCFPAsBNZxoDp5kAcRyeB1QoE5SM7DSgNuYTFSAFoAYABo3tj9DHAAeAACNeR-JHgMxIZQLNQMl8kQEwrAgwACAkUAhIJBB4BAQEDBxiCiYwCIN7Y_Qwo0qwCMhTnG549n-YtNuc1jgj-2AsLPSmw3DoyQLNQM18kQEwrAiUACBkGawEFThwBARIBAQEEATEEAQEBAQEBAQEBAQUBEggBAQEBAY1access_token_expires_at= 2026-05-07 11:41:20refresh_token => d5ab04e2-2109-4c0b-b513-8cba1dd54371refresh_token_expires_at =root@docker_lamp_1:/home/jiminny#...
|
NULL
|
-7746457207336212820
|
NULL
|
click
|
ocr
|
NULL
|
iTerm2ShellEditViewSessionScriptsProfilesWindowHel iTerm2ShellEditViewSessionScriptsProfilesWindowHelp(ah]Support Daily • in 49 m100% [Thu 7 May 14:11:52DEV (docker)181DOCKERLast login: Thu MayO ₴1DEV (docker)7 09:44:56 on ttys006H82APP (-zsh)83-zsh• 84screenpipe*•$5-zsh₴6Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20773-fix-automated-reports-user-pilot-tracking) $ devroot@docker_lamp_1:/home/jiminny# php artisan crm:sync-opportunity --teamId=2 --from='2026-05-01 00:00:00*Syncing opportunity for HubspotYour HubSpotaccount has become disconnected. Please login to Jiminny to reconnect. skipping...root@docker_lamp_1:/home/jiminny# php artisan jiminny:token-info -A 1499 -RDEVaccess_tokenCFPAsBNZxoDp5kAcRyeB1QoE5SM7DSgNuYTFSAFoAYABo3tj9DHAAeAACNeR-JHgMxIZQLNQMl8kQEwrAgwACAkUAhIJBB4BAQEDBxiCiYwCIN7Y_Qwo0qwCMhTnG549n-YtNuc1jgj-2AsLPSmw3DoyQLNQM18kQEwrAiUACBkGawEFThwBARIBAQEEATEEAQEBAQEBAQEBAQUBEggBAQEBAY1access_token_expires_at= 2026-05-07 11:41:20refresh_token => d5ab04e2-2109-4c0b-b513-8cba1dd54371refresh_token_expires_at =root@docker_lamp_1:/home/jiminny#...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
3782
|
NULL
|
0
|
2026-05-07T12:40:43.744480+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778157643744_m1.jpg...
|
PhpStorm
|
faVsco.js – MatchActivityCrmData.php
|
True
|
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
A
1
Select All
5190
5190
0
4e3f2289-a3d2-5235-b410-b94ebb547490
4e3f2289-a3d2-5235-b410-b94ebb547490
Umbrella Corp
2
2
0
2
2
0
1212213464
1212213464
Umbrella Corp
430
430
0
579583316
579583316
Umbrella Corp
Umbrella Corp
Umbrella Corp
Umbrella Corp
[PHONE]
[PHONE]
Umbrella Corp
<null>
<null>
Umbrella Corp
<null>
<null>
Umbrella Corp
umbrellacorp.com
umbrellacorp.com
Umbrella Corp
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
Umbrella Corp
<null>
<null>
Umbrella Corp
0
0
0
<null>
<null>
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
2019-02-01 15:39:53
2019-02-01 15:39:53
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
id = 5190
Editor
1 row
Reload Page
Table Result Auto Refresh
Cancel Running Statements
Add Row
Delete Row
Revert Selected
Preview Pending Changes
Submit
Tx: Auto
DDL
Find on Current Page
Table Result Local Filter
Record View
Table Coloring Options
Show Geo Viewer
Show Chart
CSV
Export Data…
Copy to Database…
Compare Data
View as
Show Options Menu
Sync Changes
Hide This Notification
Code changed:
Hide
8
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Jobs\Crm;
use Exception;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Connection;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Jobs\Job;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Repositories\ActivityRepository;
use Jiminny\Services\Crm\CrmActivityService;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Throwable;
class MatchActivityCrmData extends Job implements ShouldQueue, ShouldBeUnique
{
use InteractsWithQueue;
use SerializesModels;
public int $tries = 3;
private int $activityId;
private ?Configuration $fromConfiguration;
private bool $remoteSearch;
public function __construct(
int $activityId,
?Configuration $fromConfiguration = null,
bool $remoteSearch = false,
) {
$this->activityId = $activityId;
$this->fromConfiguration = $fromConfiguration;
$this->remoteSearch = $remoteSearch;
$this->onQueue(Constants::QUEUE_ANALYTICS_LOW);
}
public function uniqueId(): string
{
$configId = $this->fromConfiguration?->getId() ?? 0;
$remote = $this->remoteSearch ? 'remote' : 'local';
return "$this->activityId:$configId:$remote";
}
public function timeout(): int
{
return 300; // 5 minutes max execution time
}
public function uniqueFor(): int
{
return $this->timeout() + 60; // timeout + 1 minute buffer
}
public function backoff(): array
{
return [30, 90, 180];
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws Exception|Throwable
*/
public function handle(
ActivityRepository $activityRepository,
CrmActivityService $crmActivityService,
Connection $connection,
): void {
$activity = $activityRepository->findById($this->activityId);
if ($activity === null) {
throw new InvalidArgumentException('[MatchActivityCrmData] Cannot find activity.');
}
try {
$connection->transaction(function () use ($activity, $crmActivityService, $activityRepository) {
Log::info('[MatchActivityCrmData] Starting CRM data matching', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'set_configuration' => $this->fromConfiguration?->getId(),
'old_state' => [
'lead_id' => $activity->getLead()?->getId(),
'contact_id' => $activity->getContact()?->getId(),
'account_id' => $activity->getAccount()?->getId(),
'opportunity_id' => $activity->getOpportunity()?->getId(),
'stage_id' => $activity->getStage()?->getId(),
],
]);
$this->resetCrmMappings($activity, $activityRepository);
$this->switchCrmConfigurationIfNeeded($activity);
$activity->refresh();
$crmActivityService->updateCrmData(
activity: $activity,
remoteSearch: $this->remoteSearch,
);
$hasMatch = $activity->getLead() !== null
|| $activity->getContact() !== null
|| $activity->getAccount() !== null
|| $activity->getOpportunity() !== null;
if ($hasMatch) {
Log::info('[MatchActivityCrmData] Successfully matched CRM data', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'lead_id' => $activity->getLead()?->getId(),
'contact_id' => $activity->getContact()?->getId(),
'account_id' => $activity->getAccount()?->getId(),
'opportunity_id' => $activity->getOpportunity()?->getId(),
'stage_id' => $activity->getStage()?->getId(),
]);
} else {
Log::info('[MatchActivityCrmData] No CRM match found', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
]);
}
});
} catch (Throwable $e) {
Log::error('[MatchActivityCrmData] Failed to match CRM data', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
throw $e;
}
}
public function failed(Throwable $exception): void
{
Log::error('[MatchActivityCrmData] Job permanently failed after all retries', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'from_configuration' => $this->fromConfiguration?->getId(),
'exception' => $exception->getMessage(),
'attempts' => $this->attempts(),
]);
}
private function resetCrmMappings(
Activity $activity,
ActivityRepository $activityRepository
): void {
$activity->update([
'lead_id' => null,
'contact_id' => null,
'account_id' => null,
'opportunity_id' => null,
'stage_id' => null,
]);
$participantsOldState = $activityRepository->getActivityParticipants($activity)
->map(function ($participant) {
return [
'id' => $participant->id,
'user_id' => $participant->user_id,
'contact_id' => $participant->contact_id,
'lead_id' => $participant->lead_id,
];
});
if ($participantsOldState->isNotEmpty()) {
Log::info('[MatchActivityCrmData] Participants old state', [
'activity' => $this->activityId,
'participants' => $participantsOldState->toArray(),
]);
}
$activity->participants()->update([
'user_id' => null,
'contact_id' => null,
'lead_id' => null,
]);
}
private function switchCrmConfigurationIfNeeded(Activity $activity): void
{
if ($this->fromConfiguration === null) {
return;
}
if ($activity->getCrm()?->getId() === $this->fromConfiguration->getId()) {
return;
}
Log::info('[MatchActivityCrmData] Switching CRM configuration', [
'activity' => $this->activityId,
'old_configuration' => $activity->getCrm()?->getId(),
'new_configuration' => $this->fromConfiguration->getId(),
]);
$activity->update([
'crm_configuration_id' => $this->fromConfiguration->getId(),
'crm_provider_id' => null,
]);
}
}
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":"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":"AXStaticText","text":"A","depth":4,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":5,"bounds":{"left":0.0,"top":0.0,"width":0.008333334,"height":0.03},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Select All","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"5190","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"5190","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"4e3f2289-a3d2-5235-b410-b94ebb547490","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"4e3f2289-a3d2-5235-b410-b94ebb547490","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"1212213464","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"1212213464","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"430","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"430","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"579583316","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"579583316","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"Umbrella Corp","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"Umbrella Corp","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"661-244-6711","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"661-244-6711","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"umbrellacorp.com","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"umbrellacorp.com","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"0","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"0","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2026-03-30 06:44:25","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2026-03-30 06:44:25","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2019-02-01 15:39:53","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2019-02-01 15:39:53","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2026-03-30 06:44:25","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2026-03-30 06:44:25","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"id = 5190","depth":4,"on_screen":true,"value":"id = 5190","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"Editor","depth":4,"on_screen":true,"role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"1 row","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reload Page","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Table Result Auto Refresh","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add Row","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Delete Row","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Revert Selected","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Preview Pending Changes","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Submit","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"DDL","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Find on Current Page","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Table Result Local Filter","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Record View","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Table Coloring Options","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Geo Viewer","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Chart","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"CSV","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Export Data…","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy to Database…","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Compare Data","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View as","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Options Menu","depth":4,"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},{"role":"AXStaticText","text":"8","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\\Jobs\\Crm;\n\nuse Exception;\nuse Illuminate\\Contracts\\Queue\\ShouldBeUnique;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Illuminate\\Queue\\SerializesModels;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Jobs\\Job;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Repositories\\ActivityRepository;\nuse Jiminny\\Services\\Crm\\CrmActivityService;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\nuse Throwable;\n\nclass MatchActivityCrmData extends Job implements ShouldQueue, ShouldBeUnique\n{\n use InteractsWithQueue;\n use SerializesModels;\n\n public int $tries = 3;\n\n private int $activityId;\n private ?Configuration $fromConfiguration;\n private bool $remoteSearch;\n\n public function __construct(\n int $activityId,\n ?Configuration $fromConfiguration = null,\n bool $remoteSearch = false,\n ) {\n $this->activityId = $activityId;\n $this->fromConfiguration = $fromConfiguration;\n $this->remoteSearch = $remoteSearch;\n\n $this->onQueue(Constants::QUEUE_ANALYTICS_LOW);\n }\n\n public function uniqueId(): string\n {\n $configId = $this->fromConfiguration?->getId() ?? 0;\n $remote = $this->remoteSearch ? 'remote' : 'local';\n\n return \"$this->activityId:$configId:$remote\";\n }\n\n public function timeout(): int\n {\n return 300; // 5 minutes max execution time\n }\n\n public function uniqueFor(): int\n {\n return $this->timeout() + 60; // timeout + 1 minute buffer\n }\n\n public function backoff(): array\n {\n return [30, 90, 180];\n }\n\n /**\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n * @throws Exception|Throwable\n */\n public function handle(\n ActivityRepository $activityRepository,\n CrmActivityService $crmActivityService,\n Connection $connection,\n ): void {\n $activity = $activityRepository->findById($this->activityId);\n if ($activity === null) {\n throw new InvalidArgumentException('[MatchActivityCrmData] Cannot find activity.');\n }\n\n try {\n $connection->transaction(function () use ($activity, $crmActivityService, $activityRepository) {\n Log::info('[MatchActivityCrmData] Starting CRM data matching', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'set_configuration' => $this->fromConfiguration?->getId(),\n 'old_state' => [\n 'lead_id' => $activity->getLead()?->getId(),\n 'contact_id' => $activity->getContact()?->getId(),\n 'account_id' => $activity->getAccount()?->getId(),\n 'opportunity_id' => $activity->getOpportunity()?->getId(),\n 'stage_id' => $activity->getStage()?->getId(),\n ],\n ]);\n\n $this->resetCrmMappings($activity, $activityRepository);\n\n $this->switchCrmConfigurationIfNeeded($activity);\n\n $activity->refresh();\n\n $crmActivityService->updateCrmData(\n activity: $activity,\n remoteSearch: $this->remoteSearch,\n );\n\n $hasMatch = $activity->getLead() !== null\n || $activity->getContact() !== null\n || $activity->getAccount() !== null\n || $activity->getOpportunity() !== null;\n\n if ($hasMatch) {\n Log::info('[MatchActivityCrmData] Successfully matched CRM data', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'lead_id' => $activity->getLead()?->getId(),\n 'contact_id' => $activity->getContact()?->getId(),\n 'account_id' => $activity->getAccount()?->getId(),\n 'opportunity_id' => $activity->getOpportunity()?->getId(),\n 'stage_id' => $activity->getStage()?->getId(),\n ]);\n } else {\n Log::info('[MatchActivityCrmData] No CRM match found', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n ]);\n }\n });\n } catch (Throwable $e) {\n Log::error('[MatchActivityCrmData] Failed to match CRM data', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'exception' => $e->getMessage(),\n 'trace' => $e->getTraceAsString(),\n ]);\n\n throw $e;\n }\n }\n\n public function failed(Throwable $exception): void\n {\n Log::error('[MatchActivityCrmData] Job permanently failed after all retries', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'from_configuration' => $this->fromConfiguration?->getId(),\n 'exception' => $exception->getMessage(),\n 'attempts' => $this->attempts(),\n ]);\n }\n\n private function resetCrmMappings(\n Activity $activity,\n ActivityRepository $activityRepository\n ): void {\n $activity->update([\n 'lead_id' => null,\n 'contact_id' => null,\n 'account_id' => null,\n 'opportunity_id' => null,\n 'stage_id' => null,\n ]);\n\n $participantsOldState = $activityRepository->getActivityParticipants($activity)\n ->map(function ($participant) {\n return [\n 'id' => $participant->id,\n 'user_id' => $participant->user_id,\n 'contact_id' => $participant->contact_id,\n 'lead_id' => $participant->lead_id,\n ];\n });\n\n if ($participantsOldState->isNotEmpty()) {\n Log::info('[MatchActivityCrmData] Participants old state', [\n 'activity' => $this->activityId,\n 'participants' => $participantsOldState->toArray(),\n ]);\n }\n\n $activity->participants()->update([\n 'user_id' => null,\n 'contact_id' => null,\n 'lead_id' => null,\n ]);\n }\n\n private function switchCrmConfigurationIfNeeded(Activity $activity): void\n {\n if ($this->fromConfiguration === null) {\n return;\n }\n\n if ($activity->getCrm()?->getId() === $this->fromConfiguration->getId()) {\n return;\n }\n\n Log::info('[MatchActivityCrmData] Switching CRM configuration', [\n 'activity' => $this->activityId,\n 'old_configuration' => $activity->getCrm()?->getId(),\n 'new_configuration' => $this->fromConfiguration->getId(),\n ]);\n\n $activity->update([\n 'crm_configuration_id' => $this->fromConfiguration->getId(),\n 'crm_provider_id' => null,\n ]);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Jobs\\Crm;\n\nuse Exception;\nuse Illuminate\\Contracts\\Queue\\ShouldBeUnique;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Illuminate\\Queue\\SerializesModels;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Jobs\\Job;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Repositories\\ActivityRepository;\nuse Jiminny\\Services\\Crm\\CrmActivityService;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\nuse Throwable;\n\nclass MatchActivityCrmData extends Job implements ShouldQueue, ShouldBeUnique\n{\n use InteractsWithQueue;\n use SerializesModels;\n\n public int $tries = 3;\n\n private int $activityId;\n private ?Configuration $fromConfiguration;\n private bool $remoteSearch;\n\n public function __construct(\n int $activityId,\n ?Configuration $fromConfiguration = null,\n bool $remoteSearch = false,\n ) {\n $this->activityId = $activityId;\n $this->fromConfiguration = $fromConfiguration;\n $this->remoteSearch = $remoteSearch;\n\n $this->onQueue(Constants::QUEUE_ANALYTICS_LOW);\n }\n\n public function uniqueId(): string\n {\n $configId = $this->fromConfiguration?->getId() ?? 0;\n $remote = $this->remoteSearch ? 'remote' : 'local';\n\n return \"$this->activityId:$configId:$remote\";\n }\n\n public function timeout(): int\n {\n return 300; // 5 minutes max execution time\n }\n\n public function uniqueFor(): int\n {\n return $this->timeout() + 60; // timeout + 1 minute buffer\n }\n\n public function backoff(): array\n {\n return [30, 90, 180];\n }\n\n /**\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n * @throws Exception|Throwable\n */\n public function handle(\n ActivityRepository $activityRepository,\n CrmActivityService $crmActivityService,\n Connection $connection,\n ): void {\n $activity = $activityRepository->findById($this->activityId);\n if ($activity === null) {\n throw new InvalidArgumentException('[MatchActivityCrmData] Cannot find activity.');\n }\n\n try {\n $connection->transaction(function () use ($activity, $crmActivityService, $activityRepository) {\n Log::info('[MatchActivityCrmData] Starting CRM data matching', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'set_configuration' => $this->fromConfiguration?->getId(),\n 'old_state' => [\n 'lead_id' => $activity->getLead()?->getId(),\n 'contact_id' => $activity->getContact()?->getId(),\n 'account_id' => $activity->getAccount()?->getId(),\n 'opportunity_id' => $activity->getOpportunity()?->getId(),\n 'stage_id' => $activity->getStage()?->getId(),\n ],\n ]);\n\n $this->resetCrmMappings($activity, $activityRepository);\n\n $this->switchCrmConfigurationIfNeeded($activity);\n\n $activity->refresh();\n\n $crmActivityService->updateCrmData(\n activity: $activity,\n remoteSearch: $this->remoteSearch,\n );\n\n $hasMatch = $activity->getLead() !== null\n || $activity->getContact() !== null\n || $activity->getAccount() !== null\n || $activity->getOpportunity() !== null;\n\n if ($hasMatch) {\n Log::info('[MatchActivityCrmData] Successfully matched CRM data', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'lead_id' => $activity->getLead()?->getId(),\n 'contact_id' => $activity->getContact()?->getId(),\n 'account_id' => $activity->getAccount()?->getId(),\n 'opportunity_id' => $activity->getOpportunity()?->getId(),\n 'stage_id' => $activity->getStage()?->getId(),\n ]);\n } else {\n Log::info('[MatchActivityCrmData] No CRM match found', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n ]);\n }\n });\n } catch (Throwable $e) {\n Log::error('[MatchActivityCrmData] Failed to match CRM data', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'exception' => $e->getMessage(),\n 'trace' => $e->getTraceAsString(),\n ]);\n\n throw $e;\n }\n }\n\n public function failed(Throwable $exception): void\n {\n Log::error('[MatchActivityCrmData] Job permanently failed after all retries', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'from_configuration' => $this->fromConfiguration?->getId(),\n 'exception' => $exception->getMessage(),\n 'attempts' => $this->attempts(),\n ]);\n }\n\n private function resetCrmMappings(\n Activity $activity,\n ActivityRepository $activityRepository\n ): void {\n $activity->update([\n 'lead_id' => null,\n 'contact_id' => null,\n 'account_id' => null,\n 'opportunity_id' => null,\n 'stage_id' => null,\n ]);\n\n $participantsOldState = $activityRepository->getActivityParticipants($activity)\n ->map(function ($participant) {\n return [\n 'id' => $participant->id,\n 'user_id' => $participant->user_id,\n 'contact_id' => $participant->contact_id,\n 'lead_id' => $participant->lead_id,\n ];\n });\n\n if ($participantsOldState->isNotEmpty()) {\n Log::info('[MatchActivityCrmData] Participants old state', [\n 'activity' => $this->activityId,\n 'participants' => $participantsOldState->toArray(),\n ]);\n }\n\n $activity->participants()->update([\n 'user_id' => null,\n 'contact_id' => null,\n 'lead_id' => null,\n ]);\n }\n\n private function switchCrmConfigurationIfNeeded(Activity $activity): void\n {\n if ($this->fromConfiguration === null) {\n return;\n }\n\n if ($activity->getCrm()?->getId() === $this->fromConfiguration->getId()) {\n return;\n }\n\n Log::info('[MatchActivityCrmData] Switching CRM configuration', [\n 'activity' => $this->activityId,\n 'old_configuration' => $activity->getCrm()?->getId(),\n 'new_configuration' => $this->fromConfiguration->getId(),\n ]);\n\n $activity->update([\n 'crm_configuration_id' => $this->fromConfiguration->getId(),\n 'crm_provider_id' => null,\n ]);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"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}]...
|
-7745782060890281856
|
5513544986711540284
|
click
|
accessibility
|
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
A
1
Select All
5190
5190
0
4e3f2289-a3d2-5235-b410-b94ebb547490
4e3f2289-a3d2-5235-b410-b94ebb547490
Umbrella Corp
2
2
0
2
2
0
1212213464
1212213464
Umbrella Corp
430
430
0
579583316
579583316
Umbrella Corp
Umbrella Corp
Umbrella Corp
Umbrella Corp
[PHONE]
[PHONE]
Umbrella Corp
<null>
<null>
Umbrella Corp
<null>
<null>
Umbrella Corp
umbrellacorp.com
umbrellacorp.com
Umbrella Corp
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
Umbrella Corp
<null>
<null>
Umbrella Corp
0
0
0
<null>
<null>
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
2019-02-01 15:39:53
2019-02-01 15:39:53
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
id = 5190
Editor
1 row
Reload Page
Table Result Auto Refresh
Cancel Running Statements
Add Row
Delete Row
Revert Selected
Preview Pending Changes
Submit
Tx: Auto
DDL
Find on Current Page
Table Result Local Filter
Record View
Table Coloring Options
Show Geo Viewer
Show Chart
CSV
Export Data…
Copy to Database…
Compare Data
View as
Show Options Menu
Sync Changes
Hide This Notification
Code changed:
Hide
8
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Jobs\Crm;
use Exception;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Connection;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Jobs\Job;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Repositories\ActivityRepository;
use Jiminny\Services\Crm\CrmActivityService;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Throwable;
class MatchActivityCrmData extends Job implements ShouldQueue, ShouldBeUnique
{
use InteractsWithQueue;
use SerializesModels;
public int $tries = 3;
private int $activityId;
private ?Configuration $fromConfiguration;
private bool $remoteSearch;
public function __construct(
int $activityId,
?Configuration $fromConfiguration = null,
bool $remoteSearch = false,
) {
$this->activityId = $activityId;
$this->fromConfiguration = $fromConfiguration;
$this->remoteSearch = $remoteSearch;
$this->onQueue(Constants::QUEUE_ANALYTICS_LOW);
}
public function uniqueId(): string
{
$configId = $this->fromConfiguration?->getId() ?? 0;
$remote = $this->remoteSearch ? 'remote' : 'local';
return "$this->activityId:$configId:$remote";
}
public function timeout(): int
{
return 300; // 5 minutes max execution time
}
public function uniqueFor(): int
{
return $this->timeout() + 60; // timeout + 1 minute buffer
}
public function backoff(): array
{
return [30, 90, 180];
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws Exception|Throwable
*/
public function handle(
ActivityRepository $activityRepository,
CrmActivityService $crmActivityService,
Connection $connection,
): void {
$activity = $activityRepository->findById($this->activityId);
if ($activity === null) {
throw new InvalidArgumentException('[MatchActivityCrmData] Cannot find activity.');
}
try {
$connection->transaction(function () use ($activity, $crmActivityService, $activityRepository) {
Log::info('[MatchActivityCrmData] Starting CRM data matching', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'set_configuration' => $this->fromConfiguration?->getId(),
'old_state' => [
'lead_id' => $activity->getLead()?->getId(),
'contact_id' => $activity->getContact()?->getId(),
'account_id' => $activity->getAccount()?->getId(),
'opportunity_id' => $activity->getOpportunity()?->getId(),
'stage_id' => $activity->getStage()?->getId(),
],
]);
$this->resetCrmMappings($activity, $activityRepository);
$this->switchCrmConfigurationIfNeeded($activity);
$activity->refresh();
$crmActivityService->updateCrmData(
activity: $activity,
remoteSearch: $this->remoteSearch,
);
$hasMatch = $activity->getLead() !== null
|| $activity->getContact() !== null
|| $activity->getAccount() !== null
|| $activity->getOpportunity() !== null;
if ($hasMatch) {
Log::info('[MatchActivityCrmData] Successfully matched CRM data', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'lead_id' => $activity->getLead()?->getId(),
'contact_id' => $activity->getContact()?->getId(),
'account_id' => $activity->getAccount()?->getId(),
'opportunity_id' => $activity->getOpportunity()?->getId(),
'stage_id' => $activity->getStage()?->getId(),
]);
} else {
Log::info('[MatchActivityCrmData] No CRM match found', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
]);
}
});
} catch (Throwable $e) {
Log::error('[MatchActivityCrmData] Failed to match CRM data', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
throw $e;
}
}
public function failed(Throwable $exception): void
{
Log::error('[MatchActivityCrmData] Job permanently failed after all retries', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'from_configuration' => $this->fromConfiguration?->getId(),
'exception' => $exception->getMessage(),
'attempts' => $this->attempts(),
]);
}
private function resetCrmMappings(
Activity $activity,
ActivityRepository $activityRepository
): void {
$activity->update([
'lead_id' => null,
'contact_id' => null,
'account_id' => null,
'opportunity_id' => null,
'stage_id' => null,
]);
$participantsOldState = $activityRepository->getActivityParticipants($activity)
->map(function ($participant) {
return [
'id' => $participant->id,
'user_id' => $participant->user_id,
'contact_id' => $participant->contact_id,
'lead_id' => $participant->lead_id,
];
});
if ($participantsOldState->isNotEmpty()) {
Log::info('[MatchActivityCrmData] Participants old state', [
'activity' => $this->activityId,
'participants' => $participantsOldState->toArray(),
]);
}
$activity->participants()->update([
'user_id' => null,
'contact_id' => null,
'lead_id' => null,
]);
}
private function switchCrmConfigurationIfNeeded(Activity $activity): void
{
if ($this->fromConfiguration === null) {
return;
}
if ($activity->getCrm()?->getId() === $this->fromConfiguration->getId()) {
return;
}
Log::info('[MatchActivityCrmData] Switching CRM configuration', [
'activity' => $this->activityId,
'old_configuration' => $activity->getCrm()?->getId(),
'new_configuration' => $this->fromConfiguration->getId(),
]);
$activity->update([
'crm_configuration_id' => $this->fromConfiguration->getId(),
'crm_provider_id' => null,
]);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
3779
|
NULL
|
NULL
|
NULL
|
|
3783
|
138
|
0
|
2026-05-07T12:40:53.916547+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778157653916_m2.jpg...
|
PhpStorm
|
faVsco.js – MatchActivityCrmData.php
|
True
|
NULL
|
monitor_2
|
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
A
1
Select All
5190
5190
0
4e3f2289-a3d2-5235-b410-b94ebb547490
4e3f2289-a3d2-5235-b410-b94ebb547490
Umbrella Corp
2
2
0
2
2
0
1212213464
1212213464
Umbrella Corp
430
430
0
579583316
579583316
Umbrella Corp
Umbrella Corp
Umbrella Corp
Umbrella Corp
[PHONE]
[PHONE]
Umbrella Corp
<null>
<null>
Umbrella Corp
<null>
<null>
Umbrella Corp
umbrellacorp.com
umbrellacorp.com
Umbrella Corp
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
Umbrella Corp
<null>
<null>
Umbrella Corp
0
0
0
<null>
<null>
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
2019-02-01 15:39:53
2019-02-01 15:39:53
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
id = 5190
Editor
1 row
Reload Page
Table Result Auto Refresh
Cancel Running Statements
Add Row
Delete Row
Revert Selected
Preview Pending Changes
Submit
Tx: Auto
DDL
Find on Current Page
Table Result Local Filter
Record View
Table Coloring Options
Show Geo Viewer
Show Chart
CSV
Export Data…
Copy to Database…
Compare Data
View as
Show Options Menu
Sync Changes
Hide This Notification
Code changed:
Hide
8
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Jobs\Crm;
use Exception;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Connection;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Jobs\Job;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Repositories\ActivityRepository;
use Jiminny\Services\Crm\CrmActivityService;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Throwable;
class MatchActivityCrmData extends Job implements ShouldQueue, ShouldBeUnique
{
use InteractsWithQueue;
use SerializesModels;
public int $tries = 3;
private int $activityId;
private ?Configuration $fromConfiguration;
private bool $remoteSearch;
public function __construct(
int $activityId,
?Configuration $fromConfiguration = null,
bool $remoteSearch = false,
) {
$this->activityId = $activityId;
$this->fromConfiguration = $fromConfiguration;
$this->remoteSearch = $remoteSearch;
$this->onQueue(Constants::QUEUE_ANALYTICS_LOW);
}
public function uniqueId(): string
{
$configId = $this->fromConfiguration?->getId() ?? 0;
$remote = $this->remoteSearch ? 'remote' : 'local';
return "$this->activityId:$configId:$remote";
}
public function timeout(): int
{
return 300; // 5 minutes max execution time
}
public function uniqueFor(): int
{
return $this->timeout() + 60; // timeout + 1 minute buffer
}
public function backoff(): array
{
return [30, 90, 180];
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws Exception|Throwable
*/
public function handle(
ActivityRepository $activityRepository,
CrmActivityService $crmActivityService,
Connection $connection,
): void {
$activity = $activityRepository->findById($this->activityId);
if ($activity === null) {
throw new InvalidArgumentException('[MatchActivityCrmData] Cannot find activity.');
}
try {
$connection->transaction(function () use ($activity, $crmActivityService, $activityRepository) {
Log::info('[MatchActivityCrmData] Starting CRM data matching', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'set_configuration' => $this->fromConfiguration?->getId(),
'old_state' => [
'lead_id' => $activity->getLead()?->getId(),
'contact_id' => $activity->getContact()?->getId(),
'account_id' => $activity->getAccount()?->getId(),
'opportunity_id' => $activity->getOpportunity()?->getId(),
'stage_id' => $activity->getStage()?->getId(),
],
]);
$this->resetCrmMappings($activity, $activityRepository);
$this->switchCrmConfigurationIfNeeded($activity);
$activity->refresh();
$crmActivityService->updateCrmData(
activity: $activity,
remoteSearch: $this->remoteSearch,
);
$hasMatch = $activity->getLead() !== null
|| $activity->getContact() !== null
|| $activity->getAccount() !== null
|| $activity->getOpportunity() !== null;
if ($hasMatch) {
Log::info('[MatchActivityCrmData] Successfully matched CRM data', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'lead_id' => $activity->getLead()?->getId(),
'contact_id' => $activity->getContact()?->getId(),
'account_id' => $activity->getAccount()?->getId(),
'opportunity_id' => $activity->getOpportunity()?->getId(),
'stage_id' => $activity->getStage()?->getId(),
]);
} else {
Log::info('[MatchActivityCrmData] No CRM match found', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
]);
}
});
} catch (Throwable $e) {
Log::error('[MatchActivityCrmData] Failed to match CRM data', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
throw $e;
}
}
public function failed(Throwable $exception): void
{
Log::error('[MatchActivityCrmData] Job permanently failed after all retries', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'from_configuration' => $this->fromConfiguration?->getId(),
'exception' => $exception->getMessage(),
'attempts' => $this->attempts(),
]);
}
private function resetCrmMappings(
Activity $activity,
ActivityRepository $activityRepository
): void {
$activity->update([
'lead_id' => null,
'contact_id' => null,
'account_id' => null,
'opportunity_id' => null,
'stage_id' => null,
]);
$participantsOldState = $activityRepository->getActivityParticipants($activity)
->map(function ($participant) {
return [
'id' => $participant->id,
'user_id' => $participant->user_id,
'contact_id' => $participant->contact_id,
'lead_id' => $participant->lead_id,
];
});
if ($participantsOldState->isNotEmpty()) {
Log::info('[MatchActivityCrmData] Participants old state', [
'activity' => $this->activityId,
'participants' => $participantsOldState->toArray(),
]);
}
$activity->participants()->update([
'user_id' => null,
'contact_id' => null,
'lead_id' => null,
]);
}
private function switchCrmConfigurationIfNeeded(Activity $activity): void
{
if ($this->fromConfiguration === null) {
return;
}
if ($activity->getCrm()?->getId() === $this->fromConfiguration->getId()) {
return;
}
Log::info('[MatchActivityCrmData] Switching CRM configuration', [
'activity' => $this->activityId,
'old_configuration' => $activity->getCrm()?->getId(),
'new_configuration' => $this->fromConfiguration->getId(),
]);
$activity->update([
'crm_configuration_id' => $this->fromConfiguration->getId(),
'crm_provider_id' => null,
]);
}
}
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":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"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,"bounds":{"left":0.8081782,"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":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"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 'AskJiminnyReportActivityServiceTest'","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 'AskJiminnyReportActivityServiceTest'","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":"AXStaticText","text":"A","depth":4,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":5,"bounds":{"left":0.27027926,"top":1.0,"width":0.0039893617,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Select All","depth":4,"bounds":{"left":0.52859044,"top":0.118914604,"width":0.07180851,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"5190","depth":6,"bounds":{"left":0.6007314,"top":0.14046289,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"5190","depth":7,"bounds":{"left":0.6007314,"top":0.14046289,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"4e3f2289-a3d2-5235-b410-b94ebb547490","depth":6,"bounds":{"left":0.6007314,"top":0.16201118,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"4e3f2289-a3d2-5235-b410-b94ebb547490","depth":7,"bounds":{"left":0.6007314,"top":0.16201118,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2","depth":6,"bounds":{"left":0.6007314,"top":0.18355946,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2","depth":7,"bounds":{"left":0.6007314,"top":0.18355946,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2","depth":6,"bounds":{"left":0.6007314,"top":0.20510775,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2","depth":7,"bounds":{"left":0.6007314,"top":0.20510775,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"1212213464","depth":6,"bounds":{"left":0.6007314,"top":0.22665602,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"1212213464","depth":7,"bounds":{"left":0.6007314,"top":0.22665602,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"430","depth":6,"bounds":{"left":0.6007314,"top":0.2482043,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"430","depth":7,"bounds":{"left":0.6007314,"top":0.2482043,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"579583316","depth":6,"bounds":{"left":0.6007314,"top":0.2697526,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"579583316","depth":7,"bounds":{"left":0.6007314,"top":0.2697526,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"Umbrella Corp","depth":6,"bounds":{"left":0.6007314,"top":0.29130086,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"Umbrella Corp","depth":7,"bounds":{"left":0.6007314,"top":0.29130086,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"661-244-6711","depth":6,"bounds":{"left":0.6007314,"top":0.31284916,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"661-244-6711","depth":7,"bounds":{"left":0.6007314,"top":0.31284916,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"bounds":{"left":0.6007314,"top":0.33439744,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"bounds":{"left":0.6007314,"top":0.33439744,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"bounds":{"left":0.6007314,"top":0.35594574,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"bounds":{"left":0.6007314,"top":0.35594574,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"umbrellacorp.com","depth":6,"bounds":{"left":0.6007314,"top":0.377494,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"umbrellacorp.com","depth":7,"bounds":{"left":0.6007314,"top":0.377494,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png","depth":6,"bounds":{"left":0.6007314,"top":0.3990423,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png","depth":7,"bounds":{"left":0.6007314,"top":0.3990423,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"bounds":{"left":0.6007314,"top":0.42059058,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"bounds":{"left":0.6007314,"top":0.42059058,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"0","depth":6,"bounds":{"left":0.6007314,"top":0.44213888,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"0","depth":7,"bounds":{"left":0.6007314,"top":0.44213888,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"bounds":{"left":0.6007314,"top":0.46368715,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"bounds":{"left":0.6007314,"top":0.46368715,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2026-03-30 06:44:25","depth":6,"bounds":{"left":0.6007314,"top":0.48523542,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2026-03-30 06:44:25","depth":7,"bounds":{"left":0.6007314,"top":0.48523542,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2019-02-01 15:39:53","depth":6,"bounds":{"left":0.6007314,"top":0.5067837,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2019-02-01 15:39:53","depth":7,"bounds":{"left":0.6007314,"top":0.5067837,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2026-03-30 06:44:25","depth":6,"bounds":{"left":0.6007314,"top":0.528332,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2026-03-30 06:44:25","depth":7,"bounds":{"left":0.6007314,"top":0.528332,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"id = 5190","depth":4,"bounds":{"left":0.5382314,"top":0.09976058,"width":0.08045213,"height":0.014365523},"on_screen":true,"value":"id = 5190","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"Editor","depth":4,"bounds":{"left":0.63829786,"top":0.09976058,"width":0.34574467,"height":0.014365523},"on_screen":true,"role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"1 row","depth":4,"bounds":{"left":0.5299202,"top":0.075019956,"width":0.017952127,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reload Page","depth":4,"bounds":{"left":0.55019945,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Table Result Auto Refresh","depth":4,"bounds":{"left":0.5588431,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"bounds":{"left":0.5674867,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add Row","depth":4,"bounds":{"left":0.5784575,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Delete Row","depth":4,"bounds":{"left":0.58710104,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Revert Selected","depth":4,"bounds":{"left":0.59574467,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Preview Pending Changes","depth":4,"bounds":{"left":0.6043883,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Submit","depth":4,"bounds":{"left":0.6130319,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"bounds":{"left":0.62400264,"top":0.074221864,"width":0.024268618,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"DDL","depth":4,"bounds":{"left":0.6505984,"top":0.074221864,"width":0.011303191,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Find on Current Page","depth":4,"bounds":{"left":0.6619016,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Table Result Local Filter","depth":4,"bounds":{"left":0.6705452,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Record View","depth":4,"bounds":{"left":0.67918885,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Table Coloring Options","depth":4,"bounds":{"left":0.6878325,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Geo Viewer","depth":4,"bounds":{"left":0.69647604,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Chart","depth":4,"bounds":{"left":0.70511967,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"CSV","depth":4,"bounds":{"left":0.921875,"top":0.074221864,"width":0.017287234,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Export Data…","depth":4,"bounds":{"left":0.94148934,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy to Database…","depth":4,"bounds":{"left":0.95013297,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Compare Data","depth":4,"bounds":{"left":0.9587766,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View as","depth":4,"bounds":{"left":0.96974736,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Options Menu","depth":4,"bounds":{"left":0.97839093,"top":0.074221864,"width":0.008643617,"height":0.01915403},"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.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":"8","depth":4,"bounds":{"left":0.5043218,"top":0.17478053,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.51396275,"top":0.17318435,"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.5212766,"top":0.17318435,"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\\Jobs\\Crm;\n\nuse Exception;\nuse Illuminate\\Contracts\\Queue\\ShouldBeUnique;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Illuminate\\Queue\\SerializesModels;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Jobs\\Job;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Repositories\\ActivityRepository;\nuse Jiminny\\Services\\Crm\\CrmActivityService;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\nuse Throwable;\n\nclass MatchActivityCrmData extends Job implements ShouldQueue, ShouldBeUnique\n{\n use InteractsWithQueue;\n use SerializesModels;\n\n public int $tries = 3;\n\n private int $activityId;\n private ?Configuration $fromConfiguration;\n private bool $remoteSearch;\n\n public function __construct(\n int $activityId,\n ?Configuration $fromConfiguration = null,\n bool $remoteSearch = false,\n ) {\n $this->activityId = $activityId;\n $this->fromConfiguration = $fromConfiguration;\n $this->remoteSearch = $remoteSearch;\n\n $this->onQueue(Constants::QUEUE_ANALYTICS_LOW);\n }\n\n public function uniqueId(): string\n {\n $configId = $this->fromConfiguration?->getId() ?? 0;\n $remote = $this->remoteSearch ? 'remote' : 'local';\n\n return \"$this->activityId:$configId:$remote\";\n }\n\n public function timeout(): int\n {\n return 300; // 5 minutes max execution time\n }\n\n public function uniqueFor(): int\n {\n return $this->timeout() + 60; // timeout + 1 minute buffer\n }\n\n public function backoff(): array\n {\n return [30, 90, 180];\n }\n\n /**\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n * @throws Exception|Throwable\n */\n public function handle(\n ActivityRepository $activityRepository,\n CrmActivityService $crmActivityService,\n Connection $connection,\n ): void {\n $activity = $activityRepository->findById($this->activityId);\n if ($activity === null) {\n throw new InvalidArgumentException('[MatchActivityCrmData] Cannot find activity.');\n }\n\n try {\n $connection->transaction(function () use ($activity, $crmActivityService, $activityRepository) {\n Log::info('[MatchActivityCrmData] Starting CRM data matching', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'set_configuration' => $this->fromConfiguration?->getId(),\n 'old_state' => [\n 'lead_id' => $activity->getLead()?->getId(),\n 'contact_id' => $activity->getContact()?->getId(),\n 'account_id' => $activity->getAccount()?->getId(),\n 'opportunity_id' => $activity->getOpportunity()?->getId(),\n 'stage_id' => $activity->getStage()?->getId(),\n ],\n ]);\n\n $this->resetCrmMappings($activity, $activityRepository);\n\n $this->switchCrmConfigurationIfNeeded($activity);\n\n $activity->refresh();\n\n $crmActivityService->updateCrmData(\n activity: $activity,\n remoteSearch: $this->remoteSearch,\n );\n\n $hasMatch = $activity->getLead() !== null\n || $activity->getContact() !== null\n || $activity->getAccount() !== null\n || $activity->getOpportunity() !== null;\n\n if ($hasMatch) {\n Log::info('[MatchActivityCrmData] Successfully matched CRM data', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'lead_id' => $activity->getLead()?->getId(),\n 'contact_id' => $activity->getContact()?->getId(),\n 'account_id' => $activity->getAccount()?->getId(),\n 'opportunity_id' => $activity->getOpportunity()?->getId(),\n 'stage_id' => $activity->getStage()?->getId(),\n ]);\n } else {\n Log::info('[MatchActivityCrmData] No CRM match found', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n ]);\n }\n });\n } catch (Throwable $e) {\n Log::error('[MatchActivityCrmData] Failed to match CRM data', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'exception' => $e->getMessage(),\n 'trace' => $e->getTraceAsString(),\n ]);\n\n throw $e;\n }\n }\n\n public function failed(Throwable $exception): void\n {\n Log::error('[MatchActivityCrmData] Job permanently failed after all retries', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'from_configuration' => $this->fromConfiguration?->getId(),\n 'exception' => $exception->getMessage(),\n 'attempts' => $this->attempts(),\n ]);\n }\n\n private function resetCrmMappings(\n Activity $activity,\n ActivityRepository $activityRepository\n ): void {\n $activity->update([\n 'lead_id' => null,\n 'contact_id' => null,\n 'account_id' => null,\n 'opportunity_id' => null,\n 'stage_id' => null,\n ]);\n\n $participantsOldState = $activityRepository->getActivityParticipants($activity)\n ->map(function ($participant) {\n return [\n 'id' => $participant->id,\n 'user_id' => $participant->user_id,\n 'contact_id' => $participant->contact_id,\n 'lead_id' => $participant->lead_id,\n ];\n });\n\n if ($participantsOldState->isNotEmpty()) {\n Log::info('[MatchActivityCrmData] Participants old state', [\n 'activity' => $this->activityId,\n 'participants' => $participantsOldState->toArray(),\n ]);\n }\n\n $activity->participants()->update([\n 'user_id' => null,\n 'contact_id' => null,\n 'lead_id' => null,\n ]);\n }\n\n private function switchCrmConfigurationIfNeeded(Activity $activity): void\n {\n if ($this->fromConfiguration === null) {\n return;\n }\n\n if ($activity->getCrm()?->getId() === $this->fromConfiguration->getId()) {\n return;\n }\n\n Log::info('[MatchActivityCrmData] Switching CRM configuration', [\n 'activity' => $this->activityId,\n 'old_configuration' => $activity->getCrm()?->getId(),\n 'new_configuration' => $this->fromConfiguration->getId(),\n ]);\n\n $activity->update([\n 'crm_configuration_id' => $this->fromConfiguration->getId(),\n 'crm_provider_id' => null,\n ]);\n }\n}","depth":4,"bounds":{"left":0.122340426,"top":0.17158818,"width":0.40591756,"height":0.8284118},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Jobs\\Crm;\n\nuse Exception;\nuse Illuminate\\Contracts\\Queue\\ShouldBeUnique;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Illuminate\\Queue\\SerializesModels;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Jobs\\Job;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Repositories\\ActivityRepository;\nuse Jiminny\\Services\\Crm\\CrmActivityService;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\nuse Throwable;\n\nclass MatchActivityCrmData extends Job implements ShouldQueue, ShouldBeUnique\n{\n use InteractsWithQueue;\n use SerializesModels;\n\n public int $tries = 3;\n\n private int $activityId;\n private ?Configuration $fromConfiguration;\n private bool $remoteSearch;\n\n public function __construct(\n int $activityId,\n ?Configuration $fromConfiguration = null,\n bool $remoteSearch = false,\n ) {\n $this->activityId = $activityId;\n $this->fromConfiguration = $fromConfiguration;\n $this->remoteSearch = $remoteSearch;\n\n $this->onQueue(Constants::QUEUE_ANALYTICS_LOW);\n }\n\n public function uniqueId(): string\n {\n $configId = $this->fromConfiguration?->getId() ?? 0;\n $remote = $this->remoteSearch ? 'remote' : 'local';\n\n return \"$this->activityId:$configId:$remote\";\n }\n\n public function timeout(): int\n {\n return 300; // 5 minutes max execution time\n }\n\n public function uniqueFor(): int\n {\n return $this->timeout() + 60; // timeout + 1 minute buffer\n }\n\n public function backoff(): array\n {\n return [30, 90, 180];\n }\n\n /**\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n * @throws Exception|Throwable\n */\n public function handle(\n ActivityRepository $activityRepository,\n CrmActivityService $crmActivityService,\n Connection $connection,\n ): void {\n $activity = $activityRepository->findById($this->activityId);\n if ($activity === null) {\n throw new InvalidArgumentException('[MatchActivityCrmData] Cannot find activity.');\n }\n\n try {\n $connection->transaction(function () use ($activity, $crmActivityService, $activityRepository) {\n Log::info('[MatchActivityCrmData] Starting CRM data matching', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'set_configuration' => $this->fromConfiguration?->getId(),\n 'old_state' => [\n 'lead_id' => $activity->getLead()?->getId(),\n 'contact_id' => $activity->getContact()?->getId(),\n 'account_id' => $activity->getAccount()?->getId(),\n 'opportunity_id' => $activity->getOpportunity()?->getId(),\n 'stage_id' => $activity->getStage()?->getId(),\n ],\n ]);\n\n $this->resetCrmMappings($activity, $activityRepository);\n\n $this->switchCrmConfigurationIfNeeded($activity);\n\n $activity->refresh();\n\n $crmActivityService->updateCrmData(\n activity: $activity,\n remoteSearch: $this->remoteSearch,\n );\n\n $hasMatch = $activity->getLead() !== null\n || $activity->getContact() !== null\n || $activity->getAccount() !== null\n || $activity->getOpportunity() !== null;\n\n if ($hasMatch) {\n Log::info('[MatchActivityCrmData] Successfully matched CRM data', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'lead_id' => $activity->getLead()?->getId(),\n 'contact_id' => $activity->getContact()?->getId(),\n 'account_id' => $activity->getAccount()?->getId(),\n 'opportunity_id' => $activity->getOpportunity()?->getId(),\n 'stage_id' => $activity->getStage()?->getId(),\n ]);\n } else {\n Log::info('[MatchActivityCrmData] No CRM match found', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n ]);\n }\n });\n } catch (Throwable $e) {\n Log::error('[MatchActivityCrmData] Failed to match CRM data', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'exception' => $e->getMessage(),\n 'trace' => $e->getTraceAsString(),\n ]);\n\n throw $e;\n }\n }\n\n public function failed(Throwable $exception): void\n {\n Log::error('[MatchActivityCrmData] Job permanently failed after all retries', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'from_configuration' => $this->fromConfiguration?->getId(),\n 'exception' => $exception->getMessage(),\n 'attempts' => $this->attempts(),\n ]);\n }\n\n private function resetCrmMappings(\n Activity $activity,\n ActivityRepository $activityRepository\n ): void {\n $activity->update([\n 'lead_id' => null,\n 'contact_id' => null,\n 'account_id' => null,\n 'opportunity_id' => null,\n 'stage_id' => null,\n ]);\n\n $participantsOldState = $activityRepository->getActivityParticipants($activity)\n ->map(function ($participant) {\n return [\n 'id' => $participant->id,\n 'user_id' => $participant->user_id,\n 'contact_id' => $participant->contact_id,\n 'lead_id' => $participant->lead_id,\n ];\n });\n\n if ($participantsOldState->isNotEmpty()) {\n Log::info('[MatchActivityCrmData] Participants old state', [\n 'activity' => $this->activityId,\n 'participants' => $participantsOldState->toArray(),\n ]);\n }\n\n $activity->participants()->update([\n 'user_id' => null,\n 'contact_id' => null,\n 'lead_id' => null,\n ]);\n }\n\n private function switchCrmConfigurationIfNeeded(Activity $activity): void\n {\n if ($this->fromConfiguration === null) {\n return;\n }\n\n if ($activity->getCrm()?->getId() === $this->fromConfiguration->getId()) {\n return;\n }\n\n Log::info('[MatchActivityCrmData] Switching CRM configuration', [\n 'activity' => $this->activityId,\n 'old_configuration' => $activity->getCrm()?->getId(),\n 'new_configuration' => $this->fromConfiguration->getId(),\n ]);\n\n $activity->update([\n 'crm_configuration_id' => $this->fromConfiguration->getId(),\n 'crm_provider_id' => null,\n ]);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"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}]...
|
-7745782060890281856
|
5513544986711540284
|
click
|
accessibility
|
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
A
1
Select All
5190
5190
0
4e3f2289-a3d2-5235-b410-b94ebb547490
4e3f2289-a3d2-5235-b410-b94ebb547490
Umbrella Corp
2
2
0
2
2
0
1212213464
1212213464
Umbrella Corp
430
430
0
579583316
579583316
Umbrella Corp
Umbrella Corp
Umbrella Corp
Umbrella Corp
[PHONE]
[PHONE]
Umbrella Corp
<null>
<null>
Umbrella Corp
<null>
<null>
Umbrella Corp
umbrellacorp.com
umbrellacorp.com
Umbrella Corp
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
Umbrella Corp
<null>
<null>
Umbrella Corp
0
0
0
<null>
<null>
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
2019-02-01 15:39:53
2019-02-01 15:39:53
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
id = 5190
Editor
1 row
Reload Page
Table Result Auto Refresh
Cancel Running Statements
Add Row
Delete Row
Revert Selected
Preview Pending Changes
Submit
Tx: Auto
DDL
Find on Current Page
Table Result Local Filter
Record View
Table Coloring Options
Show Geo Viewer
Show Chart
CSV
Export Data…
Copy to Database…
Compare Data
View as
Show Options Menu
Sync Changes
Hide This Notification
Code changed:
Hide
8
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Jobs\Crm;
use Exception;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Connection;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Jobs\Job;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Repositories\ActivityRepository;
use Jiminny\Services\Crm\CrmActivityService;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Throwable;
class MatchActivityCrmData extends Job implements ShouldQueue, ShouldBeUnique
{
use InteractsWithQueue;
use SerializesModels;
public int $tries = 3;
private int $activityId;
private ?Configuration $fromConfiguration;
private bool $remoteSearch;
public function __construct(
int $activityId,
?Configuration $fromConfiguration = null,
bool $remoteSearch = false,
) {
$this->activityId = $activityId;
$this->fromConfiguration = $fromConfiguration;
$this->remoteSearch = $remoteSearch;
$this->onQueue(Constants::QUEUE_ANALYTICS_LOW);
}
public function uniqueId(): string
{
$configId = $this->fromConfiguration?->getId() ?? 0;
$remote = $this->remoteSearch ? 'remote' : 'local';
return "$this->activityId:$configId:$remote";
}
public function timeout(): int
{
return 300; // 5 minutes max execution time
}
public function uniqueFor(): int
{
return $this->timeout() + 60; // timeout + 1 minute buffer
}
public function backoff(): array
{
return [30, 90, 180];
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws Exception|Throwable
*/
public function handle(
ActivityRepository $activityRepository,
CrmActivityService $crmActivityService,
Connection $connection,
): void {
$activity = $activityRepository->findById($this->activityId);
if ($activity === null) {
throw new InvalidArgumentException('[MatchActivityCrmData] Cannot find activity.');
}
try {
$connection->transaction(function () use ($activity, $crmActivityService, $activityRepository) {
Log::info('[MatchActivityCrmData] Starting CRM data matching', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'set_configuration' => $this->fromConfiguration?->getId(),
'old_state' => [
'lead_id' => $activity->getLead()?->getId(),
'contact_id' => $activity->getContact()?->getId(),
'account_id' => $activity->getAccount()?->getId(),
'opportunity_id' => $activity->getOpportunity()?->getId(),
'stage_id' => $activity->getStage()?->getId(),
],
]);
$this->resetCrmMappings($activity, $activityRepository);
$this->switchCrmConfigurationIfNeeded($activity);
$activity->refresh();
$crmActivityService->updateCrmData(
activity: $activity,
remoteSearch: $this->remoteSearch,
);
$hasMatch = $activity->getLead() !== null
|| $activity->getContact() !== null
|| $activity->getAccount() !== null
|| $activity->getOpportunity() !== null;
if ($hasMatch) {
Log::info('[MatchActivityCrmData] Successfully matched CRM data', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'lead_id' => $activity->getLead()?->getId(),
'contact_id' => $activity->getContact()?->getId(),
'account_id' => $activity->getAccount()?->getId(),
'opportunity_id' => $activity->getOpportunity()?->getId(),
'stage_id' => $activity->getStage()?->getId(),
]);
} else {
Log::info('[MatchActivityCrmData] No CRM match found', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
]);
}
});
} catch (Throwable $e) {
Log::error('[MatchActivityCrmData] Failed to match CRM data', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
throw $e;
}
}
public function failed(Throwable $exception): void
{
Log::error('[MatchActivityCrmData] Job permanently failed after all retries', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'from_configuration' => $this->fromConfiguration?->getId(),
'exception' => $exception->getMessage(),
'attempts' => $this->attempts(),
]);
}
private function resetCrmMappings(
Activity $activity,
ActivityRepository $activityRepository
): void {
$activity->update([
'lead_id' => null,
'contact_id' => null,
'account_id' => null,
'opportunity_id' => null,
'stage_id' => null,
]);
$participantsOldState = $activityRepository->getActivityParticipants($activity)
->map(function ($participant) {
return [
'id' => $participant->id,
'user_id' => $participant->user_id,
'contact_id' => $participant->contact_id,
'lead_id' => $participant->lead_id,
];
});
if ($participantsOldState->isNotEmpty()) {
Log::info('[MatchActivityCrmData] Participants old state', [
'activity' => $this->activityId,
'participants' => $participantsOldState->toArray(),
]);
}
$activity->participants()->update([
'user_id' => null,
'contact_id' => null,
'lead_id' => null,
]);
}
private function switchCrmConfigurationIfNeeded(Activity $activity): void
{
if ($this->fromConfiguration === null) {
return;
}
if ($activity->getCrm()?->getId() === $this->fromConfiguration->getId()) {
return;
}
Log::info('[MatchActivityCrmData] Switching CRM configuration', [
'activity' => $this->activityId,
'old_configuration' => $activity->getCrm()?->getId(),
'new_configuration' => $this->fromConfiguration->getId(),
]);
$activity->update([
'crm_configuration_id' => $this->fromConfiguration->getId(),
'crm_provider_id' => null,
]);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
3803
|
138
|
12
|
2026-05-07T12:42:22.981499+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778157742981_m2.jpg...
|
PhpStorm
|
faVsco.js – MatchActivityCrmData.php
|
True
|
NULL
|
monitor_2
|
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
A
1
Select All
5190
5190
0
4e3f2289-a3d2-5235-b410-b94ebb547490
4e3f2289-a3d2-5235-b410-b94ebb547490
Umbrella Corp
2
2
0
2
2
0
1212213464
1212213464
Umbrella Corp
430
430
0
579583316
579583316
Umbrella Corp
Umbrella Corp
Umbrella Corp
Umbrella Corp
[PHONE]
[PHONE]
Umbrella Corp
<null>
<null>
Umbrella Corp
<null>
<null>
Umbrella Corp
umbrellacorp.com
umbrellacorp.com
Umbrella Corp
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
Umbrella Corp
<null>
<null>
Umbrella Corp
0
0
0
<null>
<null>
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
2019-02-01 15:39:53
2019-02-01 15:39:53
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
id = 5190
Editor
1 row
Reload Page
Table Result Auto Refresh
Cancel Running Statements
Add Row
Delete Row
Revert Selected
Preview Pending Changes
Submit
Tx: Auto
DDL
Find on Current Page
Table Result Local Filter
Record View
Table Coloring Options
Show Geo Viewer
Show Chart
CSV
Export Data…
Copy to Database…
Compare Data
View as
Show Options Menu
Sync Changes
Hide This Notification
Code changed:
Hide
8
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Jobs\Crm;
use Exception;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Connection;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Jobs\Job;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Repositories\ActivityRepository;
use Jiminny\Services\Crm\CrmActivityService;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Throwable;
class MatchActivityCrmData extends Job implements ShouldQueue, ShouldBeUnique
{
use InteractsWithQueue;
use SerializesModels;
public int $tries = 3;
private int $activityId;
private ?Configuration $fromConfiguration;
private bool $remoteSearch;
public function __construct(
int $activityId,
?Configuration $fromConfiguration = null,
bool $remoteSearch = false,
) {
$this->activityId = $activityId;
$this->fromConfiguration = $fromConfiguration;
$this->remoteSearch = $remoteSearch;
$this->onQueue(Constants::QUEUE_ANALYTICS_LOW);
}
public function uniqueId(): string
{
$configId = $this->fromConfiguration?->getId() ?? 0;
$remote = $this->remoteSearch ? 'remote' : 'local';
return "$this->activityId:$configId:$remote";
}
public function timeout(): int
{
return 300; // 5 minutes max execution time
}
public function uniqueFor(): int
{
return $this->timeout() + 60; // timeout + 1 minute buffer
}
public function backoff(): array
{
return [30, 90, 180];
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws Exception|Throwable
*/
public function handle(
ActivityRepository $activityRepository,
CrmActivityService $crmActivityService,
Connection $connection,
): void {
$activity = $activityRepository->findById($this->activityId);
if ($activity === null) {
throw new InvalidArgumentException('[MatchActivityCrmData] Cannot find activity.');
}
try {
$connection->transaction(function () use ($activity, $crmActivityService, $activityRepository) {
Log::info('[MatchActivityCrmData] Starting CRM data matching', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'set_configuration' => $this->fromConfiguration?->getId(),
'old_state' => [
'lead_id' => $activity->getLead()?->getId(),
'contact_id' => $activity->getContact()?->getId(),
'account_id' => $activity->getAccount()?->getId(),
'opportunity_id' => $activity->getOpportunity()?->getId(),
'stage_id' => $activity->getStage()?->getId(),
],
]);
$this->resetCrmMappings($activity, $activityRepository);
$this->switchCrmConfigurationIfNeeded($activity);
$activity->refresh();
$crmActivityService->updateCrmData(
activity: $activity,
remoteSearch: $this->remoteSearch,
);
$hasMatch = $activity->getLead() !== null
|| $activity->getContact() !== null
|| $activity->getAccount() !== null
|| $activity->getOpportunity() !== null;
if ($hasMatch) {
Log::info('[MatchActivityCrmData] Successfully matched CRM data', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'lead_id' => $activity->getLead()?->getId(),
'contact_id' => $activity->getContact()?->getId(),
'account_id' => $activity->getAccount()?->getId(),
'opportunity_id' => $activity->getOpportunity()?->getId(),
'stage_id' => $activity->getStage()?->getId(),
]);
} else {
Log::info('[MatchActivityCrmData] No CRM match found', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
]);
}
});
} catch (Throwable $e) {
Log::error('[MatchActivityCrmData] Failed to match CRM data', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
throw $e;
}
}
public function failed(Throwable $exception): void
{
Log::error('[MatchActivityCrmData] Job permanently failed after all retries', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'from_configuration' => $this->fromConfiguration?->getId(),
'exception' => $exception->getMessage(),
'attempts' => $this->attempts(),
]);
}
private function resetCrmMappings(
Activity $activity,
ActivityRepository $activityRepository
): void {
$activity->update([
'lead_id' => null,
'contact_id' => null,
'account_id' => null,
'opportunity_id' => null,
'stage_id' => null,
]);
$participantsOldState = $activityRepository->getActivityParticipants($activity)
->map(function ($participant) {
return [
'id' => $participant->id,
'user_id' => $participant->user_id,
'contact_id' => $participant->contact_id,
'lead_id' => $participant->lead_id,
];
});
if ($participantsOldState->isNotEmpty()) {
Log::info('[MatchActivityCrmData] Participants old state', [
'activity' => $this->activityId,
'participants' => $participantsOldState->toArray(),
]);
}
$activity->participants()->update([
'user_id' => null,
'contact_id' => null,
'lead_id' => null,
]);
}
private function switchCrmConfigurationIfNeeded(Activity $activity): void
{
if ($this->fromConfiguration === null) {
return;
}
if ($activity->getCrm()?->getId() === $this->fromConfiguration->getId()) {
return;
}
Log::info('[MatchActivityCrmData] Switching CRM configuration', [
'activity' => $this->activityId,
'old_configuration' => $activity->getCrm()?->getId(),
'new_configuration' => $this->fromConfiguration->getId(),
]);
$activity->update([
'crm_configuration_id' => $this->fromConfiguration->getId(),
'crm_provider_id' => null,
]);
}
}
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":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"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,"bounds":{"left":0.8081782,"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":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"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 'AskJiminnyReportActivityServiceTest'","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 'AskJiminnyReportActivityServiceTest'","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":"AXStaticText","text":"A","depth":4,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":5,"bounds":{"left":0.27027926,"top":1.0,"width":0.0039893617,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Select All","depth":4,"bounds":{"left":0.52859044,"top":0.118914604,"width":0.07180851,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"5190","depth":6,"bounds":{"left":0.6007314,"top":0.14046289,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"5190","depth":7,"bounds":{"left":0.6007314,"top":0.14046289,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"4e3f2289-a3d2-5235-b410-b94ebb547490","depth":6,"bounds":{"left":0.6007314,"top":0.16201118,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"4e3f2289-a3d2-5235-b410-b94ebb547490","depth":7,"bounds":{"left":0.6007314,"top":0.16201118,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2","depth":6,"bounds":{"left":0.6007314,"top":0.18355946,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2","depth":7,"bounds":{"left":0.6007314,"top":0.18355946,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2","depth":6,"bounds":{"left":0.6007314,"top":0.20510775,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2","depth":7,"bounds":{"left":0.6007314,"top":0.20510775,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"1212213464","depth":6,"bounds":{"left":0.6007314,"top":0.22665602,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"1212213464","depth":7,"bounds":{"left":0.6007314,"top":0.22665602,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"430","depth":6,"bounds":{"left":0.6007314,"top":0.2482043,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"430","depth":7,"bounds":{"left":0.6007314,"top":0.2482043,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"579583316","depth":6,"bounds":{"left":0.6007314,"top":0.2697526,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"579583316","depth":7,"bounds":{"left":0.6007314,"top":0.2697526,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"Umbrella Corp","depth":6,"bounds":{"left":0.6007314,"top":0.29130086,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"Umbrella Corp","depth":7,"bounds":{"left":0.6007314,"top":0.29130086,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"661-244-6711","depth":6,"bounds":{"left":0.6007314,"top":0.31284916,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"661-244-6711","depth":7,"bounds":{"left":0.6007314,"top":0.31284916,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"bounds":{"left":0.6007314,"top":0.33439744,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"bounds":{"left":0.6007314,"top":0.33439744,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"bounds":{"left":0.6007314,"top":0.35594574,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"bounds":{"left":0.6007314,"top":0.35594574,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"umbrellacorp.com","depth":6,"bounds":{"left":0.6007314,"top":0.377494,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"umbrellacorp.com","depth":7,"bounds":{"left":0.6007314,"top":0.377494,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png","depth":6,"bounds":{"left":0.6007314,"top":0.3990423,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png","depth":7,"bounds":{"left":0.6007314,"top":0.3990423,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"bounds":{"left":0.6007314,"top":0.42059058,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"bounds":{"left":0.6007314,"top":0.42059058,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"0","depth":6,"bounds":{"left":0.6007314,"top":0.44213888,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"0","depth":7,"bounds":{"left":0.6007314,"top":0.44213888,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"bounds":{"left":0.6007314,"top":0.46368715,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"bounds":{"left":0.6007314,"top":0.46368715,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2026-03-30 06:44:25","depth":6,"bounds":{"left":0.6007314,"top":0.48523542,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2026-03-30 06:44:25","depth":7,"bounds":{"left":0.6007314,"top":0.48523542,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2019-02-01 15:39:53","depth":6,"bounds":{"left":0.6007314,"top":0.5067837,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2019-02-01 15:39:53","depth":7,"bounds":{"left":0.6007314,"top":0.5067837,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2026-03-30 06:44:25","depth":6,"bounds":{"left":0.6007314,"top":0.528332,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2026-03-30 06:44:25","depth":7,"bounds":{"left":0.6007314,"top":0.528332,"width":0.10006649,"height":0.0207502},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.27027926,"top":1.0,"width":0.098071806,"height":0.0},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"id = 5190","depth":4,"bounds":{"left":0.5382314,"top":0.09976058,"width":0.08045213,"height":0.014365523},"on_screen":true,"value":"id = 5190","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"Editor","depth":4,"bounds":{"left":0.63829786,"top":0.09976058,"width":0.34574467,"height":0.014365523},"on_screen":true,"role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"1 row","depth":4,"bounds":{"left":0.5299202,"top":0.075019956,"width":0.017952127,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reload Page","depth":4,"bounds":{"left":0.55019945,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Table Result Auto Refresh","depth":4,"bounds":{"left":0.5588431,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"bounds":{"left":0.5674867,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add Row","depth":4,"bounds":{"left":0.5784575,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Delete Row","depth":4,"bounds":{"left":0.58710104,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Revert Selected","depth":4,"bounds":{"left":0.59574467,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Preview Pending Changes","depth":4,"bounds":{"left":0.6043883,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Submit","depth":4,"bounds":{"left":0.6130319,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"bounds":{"left":0.62400264,"top":0.074221864,"width":0.024268618,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"DDL","depth":4,"bounds":{"left":0.6505984,"top":0.074221864,"width":0.011303191,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Find on Current Page","depth":4,"bounds":{"left":0.6619016,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Table Result Local Filter","depth":4,"bounds":{"left":0.6705452,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Record View","depth":4,"bounds":{"left":0.67918885,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Table Coloring Options","depth":4,"bounds":{"left":0.6878325,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Geo Viewer","depth":4,"bounds":{"left":0.69647604,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Chart","depth":4,"bounds":{"left":0.70511967,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"CSV","depth":4,"bounds":{"left":0.921875,"top":0.074221864,"width":0.017287234,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Export Data…","depth":4,"bounds":{"left":0.94148934,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy to Database…","depth":4,"bounds":{"left":0.95013297,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Compare Data","depth":4,"bounds":{"left":0.9587766,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View as","depth":4,"bounds":{"left":0.96974736,"top":0.074221864,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Options Menu","depth":4,"bounds":{"left":0.97839093,"top":0.074221864,"width":0.008643617,"height":0.01915403},"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.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":"8","depth":4,"bounds":{"left":0.5043218,"top":0.17478053,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.51396275,"top":0.17318435,"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.5212766,"top":0.17318435,"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\\Jobs\\Crm;\n\nuse Exception;\nuse Illuminate\\Contracts\\Queue\\ShouldBeUnique;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Illuminate\\Queue\\SerializesModels;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Jobs\\Job;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Repositories\\ActivityRepository;\nuse Jiminny\\Services\\Crm\\CrmActivityService;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\nuse Throwable;\n\nclass MatchActivityCrmData extends Job implements ShouldQueue, ShouldBeUnique\n{\n use InteractsWithQueue;\n use SerializesModels;\n\n public int $tries = 3;\n\n private int $activityId;\n private ?Configuration $fromConfiguration;\n private bool $remoteSearch;\n\n public function __construct(\n int $activityId,\n ?Configuration $fromConfiguration = null,\n bool $remoteSearch = false,\n ) {\n $this->activityId = $activityId;\n $this->fromConfiguration = $fromConfiguration;\n $this->remoteSearch = $remoteSearch;\n\n $this->onQueue(Constants::QUEUE_ANALYTICS_LOW);\n }\n\n public function uniqueId(): string\n {\n $configId = $this->fromConfiguration?->getId() ?? 0;\n $remote = $this->remoteSearch ? 'remote' : 'local';\n\n return \"$this->activityId:$configId:$remote\";\n }\n\n public function timeout(): int\n {\n return 300; // 5 minutes max execution time\n }\n\n public function uniqueFor(): int\n {\n return $this->timeout() + 60; // timeout + 1 minute buffer\n }\n\n public function backoff(): array\n {\n return [30, 90, 180];\n }\n\n /**\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n * @throws Exception|Throwable\n */\n public function handle(\n ActivityRepository $activityRepository,\n CrmActivityService $crmActivityService,\n Connection $connection,\n ): void {\n $activity = $activityRepository->findById($this->activityId);\n if ($activity === null) {\n throw new InvalidArgumentException('[MatchActivityCrmData] Cannot find activity.');\n }\n\n try {\n $connection->transaction(function () use ($activity, $crmActivityService, $activityRepository) {\n Log::info('[MatchActivityCrmData] Starting CRM data matching', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'set_configuration' => $this->fromConfiguration?->getId(),\n 'old_state' => [\n 'lead_id' => $activity->getLead()?->getId(),\n 'contact_id' => $activity->getContact()?->getId(),\n 'account_id' => $activity->getAccount()?->getId(),\n 'opportunity_id' => $activity->getOpportunity()?->getId(),\n 'stage_id' => $activity->getStage()?->getId(),\n ],\n ]);\n\n $this->resetCrmMappings($activity, $activityRepository);\n\n $this->switchCrmConfigurationIfNeeded($activity);\n\n $activity->refresh();\n\n $crmActivityService->updateCrmData(\n activity: $activity,\n remoteSearch: $this->remoteSearch,\n );\n\n $hasMatch = $activity->getLead() !== null\n || $activity->getContact() !== null\n || $activity->getAccount() !== null\n || $activity->getOpportunity() !== null;\n\n if ($hasMatch) {\n Log::info('[MatchActivityCrmData] Successfully matched CRM data', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'lead_id' => $activity->getLead()?->getId(),\n 'contact_id' => $activity->getContact()?->getId(),\n 'account_id' => $activity->getAccount()?->getId(),\n 'opportunity_id' => $activity->getOpportunity()?->getId(),\n 'stage_id' => $activity->getStage()?->getId(),\n ]);\n } else {\n Log::info('[MatchActivityCrmData] No CRM match found', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n ]);\n }\n });\n } catch (Throwable $e) {\n Log::error('[MatchActivityCrmData] Failed to match CRM data', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'exception' => $e->getMessage(),\n 'trace' => $e->getTraceAsString(),\n ]);\n\n throw $e;\n }\n }\n\n public function failed(Throwable $exception): void\n {\n Log::error('[MatchActivityCrmData] Job permanently failed after all retries', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'from_configuration' => $this->fromConfiguration?->getId(),\n 'exception' => $exception->getMessage(),\n 'attempts' => $this->attempts(),\n ]);\n }\n\n private function resetCrmMappings(\n Activity $activity,\n ActivityRepository $activityRepository\n ): void {\n $activity->update([\n 'lead_id' => null,\n 'contact_id' => null,\n 'account_id' => null,\n 'opportunity_id' => null,\n 'stage_id' => null,\n ]);\n\n $participantsOldState = $activityRepository->getActivityParticipants($activity)\n ->map(function ($participant) {\n return [\n 'id' => $participant->id,\n 'user_id' => $participant->user_id,\n 'contact_id' => $participant->contact_id,\n 'lead_id' => $participant->lead_id,\n ];\n });\n\n if ($participantsOldState->isNotEmpty()) {\n Log::info('[MatchActivityCrmData] Participants old state', [\n 'activity' => $this->activityId,\n 'participants' => $participantsOldState->toArray(),\n ]);\n }\n\n $activity->participants()->update([\n 'user_id' => null,\n 'contact_id' => null,\n 'lead_id' => null,\n ]);\n }\n\n private function switchCrmConfigurationIfNeeded(Activity $activity): void\n {\n if ($this->fromConfiguration === null) {\n return;\n }\n\n if ($activity->getCrm()?->getId() === $this->fromConfiguration->getId()) {\n return;\n }\n\n Log::info('[MatchActivityCrmData] Switching CRM configuration', [\n 'activity' => $this->activityId,\n 'old_configuration' => $activity->getCrm()?->getId(),\n 'new_configuration' => $this->fromConfiguration->getId(),\n ]);\n\n $activity->update([\n 'crm_configuration_id' => $this->fromConfiguration->getId(),\n 'crm_provider_id' => null,\n ]);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Jobs\\Crm;\n\nuse Exception;\nuse Illuminate\\Contracts\\Queue\\ShouldBeUnique;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Illuminate\\Queue\\SerializesModels;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Jobs\\Job;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Repositories\\ActivityRepository;\nuse Jiminny\\Services\\Crm\\CrmActivityService;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\nuse Throwable;\n\nclass MatchActivityCrmData extends Job implements ShouldQueue, ShouldBeUnique\n{\n use InteractsWithQueue;\n use SerializesModels;\n\n public int $tries = 3;\n\n private int $activityId;\n private ?Configuration $fromConfiguration;\n private bool $remoteSearch;\n\n public function __construct(\n int $activityId,\n ?Configuration $fromConfiguration = null,\n bool $remoteSearch = false,\n ) {\n $this->activityId = $activityId;\n $this->fromConfiguration = $fromConfiguration;\n $this->remoteSearch = $remoteSearch;\n\n $this->onQueue(Constants::QUEUE_ANALYTICS_LOW);\n }\n\n public function uniqueId(): string\n {\n $configId = $this->fromConfiguration?->getId() ?? 0;\n $remote = $this->remoteSearch ? 'remote' : 'local';\n\n return \"$this->activityId:$configId:$remote\";\n }\n\n public function timeout(): int\n {\n return 300; // 5 minutes max execution time\n }\n\n public function uniqueFor(): int\n {\n return $this->timeout() + 60; // timeout + 1 minute buffer\n }\n\n public function backoff(): array\n {\n return [30, 90, 180];\n }\n\n /**\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n * @throws Exception|Throwable\n */\n public function handle(\n ActivityRepository $activityRepository,\n CrmActivityService $crmActivityService,\n Connection $connection,\n ): void {\n $activity = $activityRepository->findById($this->activityId);\n if ($activity === null) {\n throw new InvalidArgumentException('[MatchActivityCrmData] Cannot find activity.');\n }\n\n try {\n $connection->transaction(function () use ($activity, $crmActivityService, $activityRepository) {\n Log::info('[MatchActivityCrmData] Starting CRM data matching', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'set_configuration' => $this->fromConfiguration?->getId(),\n 'old_state' => [\n 'lead_id' => $activity->getLead()?->getId(),\n 'contact_id' => $activity->getContact()?->getId(),\n 'account_id' => $activity->getAccount()?->getId(),\n 'opportunity_id' => $activity->getOpportunity()?->getId(),\n 'stage_id' => $activity->getStage()?->getId(),\n ],\n ]);\n\n $this->resetCrmMappings($activity, $activityRepository);\n\n $this->switchCrmConfigurationIfNeeded($activity);\n\n $activity->refresh();\n\n $crmActivityService->updateCrmData(\n activity: $activity,\n remoteSearch: $this->remoteSearch,\n );\n\n $hasMatch = $activity->getLead() !== null\n || $activity->getContact() !== null\n || $activity->getAccount() !== null\n || $activity->getOpportunity() !== null;\n\n if ($hasMatch) {\n Log::info('[MatchActivityCrmData] Successfully matched CRM data', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'lead_id' => $activity->getLead()?->getId(),\n 'contact_id' => $activity->getContact()?->getId(),\n 'account_id' => $activity->getAccount()?->getId(),\n 'opportunity_id' => $activity->getOpportunity()?->getId(),\n 'stage_id' => $activity->getStage()?->getId(),\n ]);\n } else {\n Log::info('[MatchActivityCrmData] No CRM match found', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n ]);\n }\n });\n } catch (Throwable $e) {\n Log::error('[MatchActivityCrmData] Failed to match CRM data', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'exception' => $e->getMessage(),\n 'trace' => $e->getTraceAsString(),\n ]);\n\n throw $e;\n }\n }\n\n public function failed(Throwable $exception): void\n {\n Log::error('[MatchActivityCrmData] Job permanently failed after all retries', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'from_configuration' => $this->fromConfiguration?->getId(),\n 'exception' => $exception->getMessage(),\n 'attempts' => $this->attempts(),\n ]);\n }\n\n private function resetCrmMappings(\n Activity $activity,\n ActivityRepository $activityRepository\n ): void {\n $activity->update([\n 'lead_id' => null,\n 'contact_id' => null,\n 'account_id' => null,\n 'opportunity_id' => null,\n 'stage_id' => null,\n ]);\n\n $participantsOldState = $activityRepository->getActivityParticipants($activity)\n ->map(function ($participant) {\n return [\n 'id' => $participant->id,\n 'user_id' => $participant->user_id,\n 'contact_id' => $participant->contact_id,\n 'lead_id' => $participant->lead_id,\n ];\n });\n\n if ($participantsOldState->isNotEmpty()) {\n Log::info('[MatchActivityCrmData] Participants old state', [\n 'activity' => $this->activityId,\n 'participants' => $participantsOldState->toArray(),\n ]);\n }\n\n $activity->participants()->update([\n 'user_id' => null,\n 'contact_id' => null,\n 'lead_id' => null,\n ]);\n }\n\n private function switchCrmConfigurationIfNeeded(Activity $activity): void\n {\n if ($this->fromConfiguration === null) {\n return;\n }\n\n if ($activity->getCrm()?->getId() === $this->fromConfiguration->getId()) {\n return;\n }\n\n Log::info('[MatchActivityCrmData] Switching CRM configuration', [\n 'activity' => $this->activityId,\n 'old_configuration' => $activity->getCrm()?->getId(),\n 'new_configuration' => $this->fromConfiguration->getId(),\n ]);\n\n $activity->update([\n 'crm_configuration_id' => $this->fromConfiguration->getId(),\n 'crm_provider_id' => null,\n ]);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"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}]...
|
-7745782060890281856
|
5513544986711540284
|
click
|
accessibility
|
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
A
1
Select All
5190
5190
0
4e3f2289-a3d2-5235-b410-b94ebb547490
4e3f2289-a3d2-5235-b410-b94ebb547490
Umbrella Corp
2
2
0
2
2
0
1212213464
1212213464
Umbrella Corp
430
430
0
579583316
579583316
Umbrella Corp
Umbrella Corp
Umbrella Corp
Umbrella Corp
[PHONE]
[PHONE]
Umbrella Corp
<null>
<null>
Umbrella Corp
<null>
<null>
Umbrella Corp
umbrellacorp.com
umbrellacorp.com
Umbrella Corp
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
Umbrella Corp
<null>
<null>
Umbrella Corp
0
0
0
<null>
<null>
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
2019-02-01 15:39:53
2019-02-01 15:39:53
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
id = 5190
Editor
1 row
Reload Page
Table Result Auto Refresh
Cancel Running Statements
Add Row
Delete Row
Revert Selected
Preview Pending Changes
Submit
Tx: Auto
DDL
Find on Current Page
Table Result Local Filter
Record View
Table Coloring Options
Show Geo Viewer
Show Chart
CSV
Export Data…
Copy to Database…
Compare Data
View as
Show Options Menu
Sync Changes
Hide This Notification
Code changed:
Hide
8
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Jobs\Crm;
use Exception;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Connection;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Jobs\Job;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Repositories\ActivityRepository;
use Jiminny\Services\Crm\CrmActivityService;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Throwable;
class MatchActivityCrmData extends Job implements ShouldQueue, ShouldBeUnique
{
use InteractsWithQueue;
use SerializesModels;
public int $tries = 3;
private int $activityId;
private ?Configuration $fromConfiguration;
private bool $remoteSearch;
public function __construct(
int $activityId,
?Configuration $fromConfiguration = null,
bool $remoteSearch = false,
) {
$this->activityId = $activityId;
$this->fromConfiguration = $fromConfiguration;
$this->remoteSearch = $remoteSearch;
$this->onQueue(Constants::QUEUE_ANALYTICS_LOW);
}
public function uniqueId(): string
{
$configId = $this->fromConfiguration?->getId() ?? 0;
$remote = $this->remoteSearch ? 'remote' : 'local';
return "$this->activityId:$configId:$remote";
}
public function timeout(): int
{
return 300; // 5 minutes max execution time
}
public function uniqueFor(): int
{
return $this->timeout() + 60; // timeout + 1 minute buffer
}
public function backoff(): array
{
return [30, 90, 180];
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws Exception|Throwable
*/
public function handle(
ActivityRepository $activityRepository,
CrmActivityService $crmActivityService,
Connection $connection,
): void {
$activity = $activityRepository->findById($this->activityId);
if ($activity === null) {
throw new InvalidArgumentException('[MatchActivityCrmData] Cannot find activity.');
}
try {
$connection->transaction(function () use ($activity, $crmActivityService, $activityRepository) {
Log::info('[MatchActivityCrmData] Starting CRM data matching', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'set_configuration' => $this->fromConfiguration?->getId(),
'old_state' => [
'lead_id' => $activity->getLead()?->getId(),
'contact_id' => $activity->getContact()?->getId(),
'account_id' => $activity->getAccount()?->getId(),
'opportunity_id' => $activity->getOpportunity()?->getId(),
'stage_id' => $activity->getStage()?->getId(),
],
]);
$this->resetCrmMappings($activity, $activityRepository);
$this->switchCrmConfigurationIfNeeded($activity);
$activity->refresh();
$crmActivityService->updateCrmData(
activity: $activity,
remoteSearch: $this->remoteSearch,
);
$hasMatch = $activity->getLead() !== null
|| $activity->getContact() !== null
|| $activity->getAccount() !== null
|| $activity->getOpportunity() !== null;
if ($hasMatch) {
Log::info('[MatchActivityCrmData] Successfully matched CRM data', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'lead_id' => $activity->getLead()?->getId(),
'contact_id' => $activity->getContact()?->getId(),
'account_id' => $activity->getAccount()?->getId(),
'opportunity_id' => $activity->getOpportunity()?->getId(),
'stage_id' => $activity->getStage()?->getId(),
]);
} else {
Log::info('[MatchActivityCrmData] No CRM match found', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
]);
}
});
} catch (Throwable $e) {
Log::error('[MatchActivityCrmData] Failed to match CRM data', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
throw $e;
}
}
public function failed(Throwable $exception): void
{
Log::error('[MatchActivityCrmData] Job permanently failed after all retries', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'from_configuration' => $this->fromConfiguration?->getId(),
'exception' => $exception->getMessage(),
'attempts' => $this->attempts(),
]);
}
private function resetCrmMappings(
Activity $activity,
ActivityRepository $activityRepository
): void {
$activity->update([
'lead_id' => null,
'contact_id' => null,
'account_id' => null,
'opportunity_id' => null,
'stage_id' => null,
]);
$participantsOldState = $activityRepository->getActivityParticipants($activity)
->map(function ($participant) {
return [
'id' => $participant->id,
'user_id' => $participant->user_id,
'contact_id' => $participant->contact_id,
'lead_id' => $participant->lead_id,
];
});
if ($participantsOldState->isNotEmpty()) {
Log::info('[MatchActivityCrmData] Participants old state', [
'activity' => $this->activityId,
'participants' => $participantsOldState->toArray(),
]);
}
$activity->participants()->update([
'user_id' => null,
'contact_id' => null,
'lead_id' => null,
]);
}
private function switchCrmConfigurationIfNeeded(Activity $activity): void
{
if ($this->fromConfiguration === null) {
return;
}
if ($activity->getCrm()?->getId() === $this->fromConfiguration->getId()) {
return;
}
Log::info('[MatchActivityCrmData] Switching CRM configuration', [
'activity' => $this->activityId,
'old_configuration' => $activity->getCrm()?->getId(),
'new_configuration' => $this->fromConfiguration->getId(),
]);
$activity->update([
'crm_configuration_id' => $this->fromConfiguration->getId(),
'crm_provider_id' => null,
]);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
3804
|
137
|
8
|
2026-05-07T12:42:23.082836+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778157743082_m1.jpg...
|
PhpStorm
|
faVsco.js – MatchActivityCrmData.php
|
True
|
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
A
1
Select All
5190
5190
0
4e3f2289-a3d2-5235-b410-b94ebb547490
4e3f2289-a3d2-5235-b410-b94ebb547490
Umbrella Corp
2
2
0
2
2
0
1212213464
1212213464
Umbrella Corp
430
430
0
579583316
579583316
Umbrella Corp
Umbrella Corp
Umbrella Corp
Umbrella Corp
[PHONE]
[PHONE]
Umbrella Corp
<null>
<null>
Umbrella Corp
<null>
<null>
Umbrella Corp
umbrellacorp.com
umbrellacorp.com
Umbrella Corp
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
Umbrella Corp
<null>
<null>
Umbrella Corp
0
0
0
<null>
<null>
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
2019-02-01 15:39:53
2019-02-01 15:39:53
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
id = 5190
Editor
1 row
Reload Page
Table Result Auto Refresh
Cancel Running Statements
Add Row
Delete Row
Revert Selected
Preview Pending Changes
Submit
Tx: Auto
DDL
Find on Current Page
Table Result Local Filter
Record View
Table Coloring Options
Show Geo Viewer
Show Chart
CSV
Export Data…
Copy to Database…
Compare Data
View as
Show Options Menu
Sync Changes
Hide This Notification
Code changed:
Hide
8
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Jobs\Crm;
use Exception;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Connection;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Jobs\Job;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Repositories\ActivityRepository;
use Jiminny\Services\Crm\CrmActivityService;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Throwable;
class MatchActivityCrmData extends Job implements ShouldQueue, ShouldBeUnique
{
use InteractsWithQueue;
use SerializesModels;
public int $tries = 3;
private int $activityId;
private ?Configuration $fromConfiguration;
private bool $remoteSearch;
public function __construct(
int $activityId,
?Configuration $fromConfiguration = null,
bool $remoteSearch = false,
) {
$this->activityId = $activityId;
$this->fromConfiguration = $fromConfiguration;
$this->remoteSearch = $remoteSearch;
$this->onQueue(Constants::QUEUE_ANALYTICS_LOW);
}
public function uniqueId(): string
{
$configId = $this->fromConfiguration?->getId() ?? 0;
$remote = $this->remoteSearch ? 'remote' : 'local';
return "$this->activityId:$configId:$remote";
}
public function timeout(): int
{
return 300; // 5 minutes max execution time
}
public function uniqueFor(): int
{
return $this->timeout() + 60; // timeout + 1 minute buffer
}
public function backoff(): array
{
return [30, 90, 180];
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws Exception|Throwable
*/
public function handle(
ActivityRepository $activityRepository,
CrmActivityService $crmActivityService,
Connection $connection,
): void {
$activity = $activityRepository->findById($this->activityId);
if ($activity === null) {
throw new InvalidArgumentException('[MatchActivityCrmData] Cannot find activity.');
}
try {
$connection->transaction(function () use ($activity, $crmActivityService, $activityRepository) {
Log::info('[MatchActivityCrmData] Starting CRM data matching', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'set_configuration' => $this->fromConfiguration?->getId(),
'old_state' => [
'lead_id' => $activity->getLead()?->getId(),
'contact_id' => $activity->getContact()?->getId(),
'account_id' => $activity->getAccount()?->getId(),
'opportunity_id' => $activity->getOpportunity()?->getId(),
'stage_id' => $activity->getStage()?->getId(),
],
]);
$this->resetCrmMappings($activity, $activityRepository);
$this->switchCrmConfigurationIfNeeded($activity);
$activity->refresh();
$crmActivityService->updateCrmData(
activity: $activity,
remoteSearch: $this->remoteSearch,
);
$hasMatch = $activity->getLead() !== null
|| $activity->getContact() !== null
|| $activity->getAccount() !== null
|| $activity->getOpportunity() !== null;
if ($hasMatch) {
Log::info('[MatchActivityCrmData] Successfully matched CRM data', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'lead_id' => $activity->getLead()?->getId(),
'contact_id' => $activity->getContact()?->getId(),
'account_id' => $activity->getAccount()?->getId(),
'opportunity_id' => $activity->getOpportunity()?->getId(),
'stage_id' => $activity->getStage()?->getId(),
]);
} else {
Log::info('[MatchActivityCrmData] No CRM match found', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
]);
}
});
} catch (Throwable $e) {
Log::error('[MatchActivityCrmData] Failed to match CRM data', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
throw $e;
}
}
public function failed(Throwable $exception): void
{
Log::error('[MatchActivityCrmData] Job permanently failed after all retries', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'from_configuration' => $this->fromConfiguration?->getId(),
'exception' => $exception->getMessage(),
'attempts' => $this->attempts(),
]);
}
private function resetCrmMappings(
Activity $activity,
ActivityRepository $activityRepository
): void {
$activity->update([
'lead_id' => null,
'contact_id' => null,
'account_id' => null,
'opportunity_id' => null,
'stage_id' => null,
]);
$participantsOldState = $activityRepository->getActivityParticipants($activity)
->map(function ($participant) {
return [
'id' => $participant->id,
'user_id' => $participant->user_id,
'contact_id' => $participant->contact_id,
'lead_id' => $participant->lead_id,
];
});
if ($participantsOldState->isNotEmpty()) {
Log::info('[MatchActivityCrmData] Participants old state', [
'activity' => $this->activityId,
'participants' => $participantsOldState->toArray(),
]);
}
$activity->participants()->update([
'user_id' => null,
'contact_id' => null,
'lead_id' => null,
]);
}
private function switchCrmConfigurationIfNeeded(Activity $activity): void
{
if ($this->fromConfiguration === null) {
return;
}
if ($activity->getCrm()?->getId() === $this->fromConfiguration->getId()) {
return;
}
Log::info('[MatchActivityCrmData] Switching CRM configuration', [
'activity' => $this->activityId,
'old_configuration' => $activity->getCrm()?->getId(),
'new_configuration' => $this->fromConfiguration->getId(),
]);
$activity->update([
'crm_configuration_id' => $this->fromConfiguration->getId(),
'crm_provider_id' => null,
]);
}
}
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":"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":"AXStaticText","text":"A","depth":4,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":5,"bounds":{"left":0.0,"top":0.0,"width":0.008333334,"height":0.03},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Select All","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"5190","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"5190","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"4e3f2289-a3d2-5235-b410-b94ebb547490","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"4e3f2289-a3d2-5235-b410-b94ebb547490","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"1212213464","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"1212213464","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"430","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"430","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"579583316","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"579583316","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"Umbrella Corp","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"Umbrella Corp","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"661-244-6711","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"661-244-6711","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"umbrellacorp.com","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"umbrellacorp.com","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"0","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"0","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"0","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"0","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"<null>","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"<null>","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2026-03-30 06:44:25","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2026-03-30 06:44:25","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2019-02-01 15:39:53","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2019-02-01 15:39:53","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCell","text":"2026-03-30 06:44:25","depth":6,"on_screen":true,"role_description":"cell"},{"role":"AXStaticText","text":"2026-03-30 06:44:25","depth":7,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"Umbrella Corp","depth":8,"bounds":{"left":0.0,"top":0.0,"width":0.2048611,"height":0.024444444},"on_screen":false,"value":"Umbrella Corp","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"id = 5190","depth":4,"on_screen":true,"value":"id = 5190","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"Editor","depth":4,"on_screen":true,"role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"1 row","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Reload Page","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Table Result Auto Refresh","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Add Row","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Delete Row","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Revert Selected","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Preview Pending Changes","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Submit","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"DDL","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Find on Current Page","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Table Result Local Filter","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Record View","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Table Coloring Options","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Geo Viewer","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Chart","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"CSV","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Export Data…","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Copy to Database…","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Compare Data","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View as","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Options Menu","depth":4,"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},{"role":"AXStaticText","text":"8","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\\Jobs\\Crm;\n\nuse Exception;\nuse Illuminate\\Contracts\\Queue\\ShouldBeUnique;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Illuminate\\Queue\\SerializesModels;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Jobs\\Job;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Repositories\\ActivityRepository;\nuse Jiminny\\Services\\Crm\\CrmActivityService;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\nuse Throwable;\n\nclass MatchActivityCrmData extends Job implements ShouldQueue, ShouldBeUnique\n{\n use InteractsWithQueue;\n use SerializesModels;\n\n public int $tries = 3;\n\n private int $activityId;\n private ?Configuration $fromConfiguration;\n private bool $remoteSearch;\n\n public function __construct(\n int $activityId,\n ?Configuration $fromConfiguration = null,\n bool $remoteSearch = false,\n ) {\n $this->activityId = $activityId;\n $this->fromConfiguration = $fromConfiguration;\n $this->remoteSearch = $remoteSearch;\n\n $this->onQueue(Constants::QUEUE_ANALYTICS_LOW);\n }\n\n public function uniqueId(): string\n {\n $configId = $this->fromConfiguration?->getId() ?? 0;\n $remote = $this->remoteSearch ? 'remote' : 'local';\n\n return \"$this->activityId:$configId:$remote\";\n }\n\n public function timeout(): int\n {\n return 300; // 5 minutes max execution time\n }\n\n public function uniqueFor(): int\n {\n return $this->timeout() + 60; // timeout + 1 minute buffer\n }\n\n public function backoff(): array\n {\n return [30, 90, 180];\n }\n\n /**\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n * @throws Exception|Throwable\n */\n public function handle(\n ActivityRepository $activityRepository,\n CrmActivityService $crmActivityService,\n Connection $connection,\n ): void {\n $activity = $activityRepository->findById($this->activityId);\n if ($activity === null) {\n throw new InvalidArgumentException('[MatchActivityCrmData] Cannot find activity.');\n }\n\n try {\n $connection->transaction(function () use ($activity, $crmActivityService, $activityRepository) {\n Log::info('[MatchActivityCrmData] Starting CRM data matching', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'set_configuration' => $this->fromConfiguration?->getId(),\n 'old_state' => [\n 'lead_id' => $activity->getLead()?->getId(),\n 'contact_id' => $activity->getContact()?->getId(),\n 'account_id' => $activity->getAccount()?->getId(),\n 'opportunity_id' => $activity->getOpportunity()?->getId(),\n 'stage_id' => $activity->getStage()?->getId(),\n ],\n ]);\n\n $this->resetCrmMappings($activity, $activityRepository);\n\n $this->switchCrmConfigurationIfNeeded($activity);\n\n $activity->refresh();\n\n $crmActivityService->updateCrmData(\n activity: $activity,\n remoteSearch: $this->remoteSearch,\n );\n\n $hasMatch = $activity->getLead() !== null\n || $activity->getContact() !== null\n || $activity->getAccount() !== null\n || $activity->getOpportunity() !== null;\n\n if ($hasMatch) {\n Log::info('[MatchActivityCrmData] Successfully matched CRM data', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'lead_id' => $activity->getLead()?->getId(),\n 'contact_id' => $activity->getContact()?->getId(),\n 'account_id' => $activity->getAccount()?->getId(),\n 'opportunity_id' => $activity->getOpportunity()?->getId(),\n 'stage_id' => $activity->getStage()?->getId(),\n ]);\n } else {\n Log::info('[MatchActivityCrmData] No CRM match found', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n ]);\n }\n });\n } catch (Throwable $e) {\n Log::error('[MatchActivityCrmData] Failed to match CRM data', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'exception' => $e->getMessage(),\n 'trace' => $e->getTraceAsString(),\n ]);\n\n throw $e;\n }\n }\n\n public function failed(Throwable $exception): void\n {\n Log::error('[MatchActivityCrmData] Job permanently failed after all retries', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'from_configuration' => $this->fromConfiguration?->getId(),\n 'exception' => $exception->getMessage(),\n 'attempts' => $this->attempts(),\n ]);\n }\n\n private function resetCrmMappings(\n Activity $activity,\n ActivityRepository $activityRepository\n ): void {\n $activity->update([\n 'lead_id' => null,\n 'contact_id' => null,\n 'account_id' => null,\n 'opportunity_id' => null,\n 'stage_id' => null,\n ]);\n\n $participantsOldState = $activityRepository->getActivityParticipants($activity)\n ->map(function ($participant) {\n return [\n 'id' => $participant->id,\n 'user_id' => $participant->user_id,\n 'contact_id' => $participant->contact_id,\n 'lead_id' => $participant->lead_id,\n ];\n });\n\n if ($participantsOldState->isNotEmpty()) {\n Log::info('[MatchActivityCrmData] Participants old state', [\n 'activity' => $this->activityId,\n 'participants' => $participantsOldState->toArray(),\n ]);\n }\n\n $activity->participants()->update([\n 'user_id' => null,\n 'contact_id' => null,\n 'lead_id' => null,\n ]);\n }\n\n private function switchCrmConfigurationIfNeeded(Activity $activity): void\n {\n if ($this->fromConfiguration === null) {\n return;\n }\n\n if ($activity->getCrm()?->getId() === $this->fromConfiguration->getId()) {\n return;\n }\n\n Log::info('[MatchActivityCrmData] Switching CRM configuration', [\n 'activity' => $this->activityId,\n 'old_configuration' => $activity->getCrm()?->getId(),\n 'new_configuration' => $this->fromConfiguration->getId(),\n ]);\n\n $activity->update([\n 'crm_configuration_id' => $this->fromConfiguration->getId(),\n 'crm_provider_id' => null,\n ]);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Jobs\\Crm;\n\nuse Exception;\nuse Illuminate\\Contracts\\Queue\\ShouldBeUnique;\nuse Illuminate\\Contracts\\Queue\\ShouldQueue;\nuse Illuminate\\Database\\Connection;\nuse Illuminate\\Queue\\InteractsWithQueue;\nuse Illuminate\\Queue\\SerializesModels;\nuse Illuminate\\Support\\Facades\\Log;\nuse Jiminny\\Component\\Queue\\Constants;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Jobs\\Job;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Repositories\\ActivityRepository;\nuse Jiminny\\Services\\Crm\\CrmActivityService;\nuse Psr\\Container\\ContainerExceptionInterface;\nuse Psr\\Container\\NotFoundExceptionInterface;\nuse Throwable;\n\nclass MatchActivityCrmData extends Job implements ShouldQueue, ShouldBeUnique\n{\n use InteractsWithQueue;\n use SerializesModels;\n\n public int $tries = 3;\n\n private int $activityId;\n private ?Configuration $fromConfiguration;\n private bool $remoteSearch;\n\n public function __construct(\n int $activityId,\n ?Configuration $fromConfiguration = null,\n bool $remoteSearch = false,\n ) {\n $this->activityId = $activityId;\n $this->fromConfiguration = $fromConfiguration;\n $this->remoteSearch = $remoteSearch;\n\n $this->onQueue(Constants::QUEUE_ANALYTICS_LOW);\n }\n\n public function uniqueId(): string\n {\n $configId = $this->fromConfiguration?->getId() ?? 0;\n $remote = $this->remoteSearch ? 'remote' : 'local';\n\n return \"$this->activityId:$configId:$remote\";\n }\n\n public function timeout(): int\n {\n return 300; // 5 minutes max execution time\n }\n\n public function uniqueFor(): int\n {\n return $this->timeout() + 60; // timeout + 1 minute buffer\n }\n\n public function backoff(): array\n {\n return [30, 90, 180];\n }\n\n /**\n * @throws ContainerExceptionInterface\n * @throws NotFoundExceptionInterface\n * @throws Exception|Throwable\n */\n public function handle(\n ActivityRepository $activityRepository,\n CrmActivityService $crmActivityService,\n Connection $connection,\n ): void {\n $activity = $activityRepository->findById($this->activityId);\n if ($activity === null) {\n throw new InvalidArgumentException('[MatchActivityCrmData] Cannot find activity.');\n }\n\n try {\n $connection->transaction(function () use ($activity, $crmActivityService, $activityRepository) {\n Log::info('[MatchActivityCrmData] Starting CRM data matching', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'set_configuration' => $this->fromConfiguration?->getId(),\n 'old_state' => [\n 'lead_id' => $activity->getLead()?->getId(),\n 'contact_id' => $activity->getContact()?->getId(),\n 'account_id' => $activity->getAccount()?->getId(),\n 'opportunity_id' => $activity->getOpportunity()?->getId(),\n 'stage_id' => $activity->getStage()?->getId(),\n ],\n ]);\n\n $this->resetCrmMappings($activity, $activityRepository);\n\n $this->switchCrmConfigurationIfNeeded($activity);\n\n $activity->refresh();\n\n $crmActivityService->updateCrmData(\n activity: $activity,\n remoteSearch: $this->remoteSearch,\n );\n\n $hasMatch = $activity->getLead() !== null\n || $activity->getContact() !== null\n || $activity->getAccount() !== null\n || $activity->getOpportunity() !== null;\n\n if ($hasMatch) {\n Log::info('[MatchActivityCrmData] Successfully matched CRM data', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'lead_id' => $activity->getLead()?->getId(),\n 'contact_id' => $activity->getContact()?->getId(),\n 'account_id' => $activity->getAccount()?->getId(),\n 'opportunity_id' => $activity->getOpportunity()?->getId(),\n 'stage_id' => $activity->getStage()?->getId(),\n ]);\n } else {\n Log::info('[MatchActivityCrmData] No CRM match found', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n ]);\n }\n });\n } catch (Throwable $e) {\n Log::error('[MatchActivityCrmData] Failed to match CRM data', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'exception' => $e->getMessage(),\n 'trace' => $e->getTraceAsString(),\n ]);\n\n throw $e;\n }\n }\n\n public function failed(Throwable $exception): void\n {\n Log::error('[MatchActivityCrmData] Job permanently failed after all retries', [\n 'activity' => $this->activityId,\n 'remote_search' => $this->remoteSearch,\n 'from_configuration' => $this->fromConfiguration?->getId(),\n 'exception' => $exception->getMessage(),\n 'attempts' => $this->attempts(),\n ]);\n }\n\n private function resetCrmMappings(\n Activity $activity,\n ActivityRepository $activityRepository\n ): void {\n $activity->update([\n 'lead_id' => null,\n 'contact_id' => null,\n 'account_id' => null,\n 'opportunity_id' => null,\n 'stage_id' => null,\n ]);\n\n $participantsOldState = $activityRepository->getActivityParticipants($activity)\n ->map(function ($participant) {\n return [\n 'id' => $participant->id,\n 'user_id' => $participant->user_id,\n 'contact_id' => $participant->contact_id,\n 'lead_id' => $participant->lead_id,\n ];\n });\n\n if ($participantsOldState->isNotEmpty()) {\n Log::info('[MatchActivityCrmData] Participants old state', [\n 'activity' => $this->activityId,\n 'participants' => $participantsOldState->toArray(),\n ]);\n }\n\n $activity->participants()->update([\n 'user_id' => null,\n 'contact_id' => null,\n 'lead_id' => null,\n ]);\n }\n\n private function switchCrmConfigurationIfNeeded(Activity $activity): void\n {\n if ($this->fromConfiguration === null) {\n return;\n }\n\n if ($activity->getCrm()?->getId() === $this->fromConfiguration->getId()) {\n return;\n }\n\n Log::info('[MatchActivityCrmData] Switching CRM configuration', [\n 'activity' => $this->activityId,\n 'old_configuration' => $activity->getCrm()?->getId(),\n 'new_configuration' => $this->fromConfiguration->getId(),\n ]);\n\n $activity->update([\n 'crm_configuration_id' => $this->fromConfiguration->getId(),\n 'crm_provider_id' => null,\n ]);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"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}]...
|
-7745782060890281856
|
5513544986711540284
|
click
|
accessibility
|
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
A
1
Select All
5190
5190
0
4e3f2289-a3d2-5235-b410-b94ebb547490
4e3f2289-a3d2-5235-b410-b94ebb547490
Umbrella Corp
2
2
0
2
2
0
1212213464
1212213464
Umbrella Corp
430
430
0
579583316
579583316
Umbrella Corp
Umbrella Corp
Umbrella Corp
Umbrella Corp
[PHONE]
[PHONE]
Umbrella Corp
<null>
<null>
Umbrella Corp
<null>
<null>
Umbrella Corp
umbrellacorp.com
umbrellacorp.com
Umbrella Corp
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
/abae74b8-bfa8-4383-9a7f-89f4bf2bdbb4/avatars/1212213464.png
Umbrella Corp
<null>
<null>
Umbrella Corp
0
0
0
<null>
<null>
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
2019-02-01 15:39:53
2019-02-01 15:39:53
Umbrella Corp
2026-03-30 06:44:25
2026-03-30 06:44:25
Umbrella Corp
id = 5190
Editor
1 row
Reload Page
Table Result Auto Refresh
Cancel Running Statements
Add Row
Delete Row
Revert Selected
Preview Pending Changes
Submit
Tx: Auto
DDL
Find on Current Page
Table Result Local Filter
Record View
Table Coloring Options
Show Geo Viewer
Show Chart
CSV
Export Data…
Copy to Database…
Compare Data
View as
Show Options Menu
Sync Changes
Hide This Notification
Code changed:
Hide
8
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Jobs\Crm;
use Exception;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Database\Connection;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Log;
use Jiminny\Component\Queue\Constants;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Jobs\Job;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Repositories\ActivityRepository;
use Jiminny\Services\Crm\CrmActivityService;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Throwable;
class MatchActivityCrmData extends Job implements ShouldQueue, ShouldBeUnique
{
use InteractsWithQueue;
use SerializesModels;
public int $tries = 3;
private int $activityId;
private ?Configuration $fromConfiguration;
private bool $remoteSearch;
public function __construct(
int $activityId,
?Configuration $fromConfiguration = null,
bool $remoteSearch = false,
) {
$this->activityId = $activityId;
$this->fromConfiguration = $fromConfiguration;
$this->remoteSearch = $remoteSearch;
$this->onQueue(Constants::QUEUE_ANALYTICS_LOW);
}
public function uniqueId(): string
{
$configId = $this->fromConfiguration?->getId() ?? 0;
$remote = $this->remoteSearch ? 'remote' : 'local';
return "$this->activityId:$configId:$remote";
}
public function timeout(): int
{
return 300; // 5 minutes max execution time
}
public function uniqueFor(): int
{
return $this->timeout() + 60; // timeout + 1 minute buffer
}
public function backoff(): array
{
return [30, 90, 180];
}
/**
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws Exception|Throwable
*/
public function handle(
ActivityRepository $activityRepository,
CrmActivityService $crmActivityService,
Connection $connection,
): void {
$activity = $activityRepository->findById($this->activityId);
if ($activity === null) {
throw new InvalidArgumentException('[MatchActivityCrmData] Cannot find activity.');
}
try {
$connection->transaction(function () use ($activity, $crmActivityService, $activityRepository) {
Log::info('[MatchActivityCrmData] Starting CRM data matching', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'set_configuration' => $this->fromConfiguration?->getId(),
'old_state' => [
'lead_id' => $activity->getLead()?->getId(),
'contact_id' => $activity->getContact()?->getId(),
'account_id' => $activity->getAccount()?->getId(),
'opportunity_id' => $activity->getOpportunity()?->getId(),
'stage_id' => $activity->getStage()?->getId(),
],
]);
$this->resetCrmMappings($activity, $activityRepository);
$this->switchCrmConfigurationIfNeeded($activity);
$activity->refresh();
$crmActivityService->updateCrmData(
activity: $activity,
remoteSearch: $this->remoteSearch,
);
$hasMatch = $activity->getLead() !== null
|| $activity->getContact() !== null
|| $activity->getAccount() !== null
|| $activity->getOpportunity() !== null;
if ($hasMatch) {
Log::info('[MatchActivityCrmData] Successfully matched CRM data', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'lead_id' => $activity->getLead()?->getId(),
'contact_id' => $activity->getContact()?->getId(),
'account_id' => $activity->getAccount()?->getId(),
'opportunity_id' => $activity->getOpportunity()?->getId(),
'stage_id' => $activity->getStage()?->getId(),
]);
} else {
Log::info('[MatchActivityCrmData] No CRM match found', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
]);
}
});
} catch (Throwable $e) {
Log::error('[MatchActivityCrmData] Failed to match CRM data', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString(),
]);
throw $e;
}
}
public function failed(Throwable $exception): void
{
Log::error('[MatchActivityCrmData] Job permanently failed after all retries', [
'activity' => $this->activityId,
'remote_search' => $this->remoteSearch,
'from_configuration' => $this->fromConfiguration?->getId(),
'exception' => $exception->getMessage(),
'attempts' => $this->attempts(),
]);
}
private function resetCrmMappings(
Activity $activity,
ActivityRepository $activityRepository
): void {
$activity->update([
'lead_id' => null,
'contact_id' => null,
'account_id' => null,
'opportunity_id' => null,
'stage_id' => null,
]);
$participantsOldState = $activityRepository->getActivityParticipants($activity)
->map(function ($participant) {
return [
'id' => $participant->id,
'user_id' => $participant->user_id,
'contact_id' => $participant->contact_id,
'lead_id' => $participant->lead_id,
];
});
if ($participantsOldState->isNotEmpty()) {
Log::info('[MatchActivityCrmData] Participants old state', [
'activity' => $this->activityId,
'participants' => $participantsOldState->toArray(),
]);
}
$activity->participants()->update([
'user_id' => null,
'contact_id' => null,
'lead_id' => null,
]);
}
private function switchCrmConfigurationIfNeeded(Activity $activity): void
{
if ($this->fromConfiguration === null) {
return;
}
if ($activity->getCrm()?->getId() === $this->fromConfiguration->getId()) {
return;
}
Log::info('[MatchActivityCrmData] Switching CRM configuration', [
'activity' => $this->activityId,
'old_configuration' => $activity->getCrm()?->getId(),
'new_configuration' => $this->fromConfiguration->getId(),
]);
$activity->update([
'crm_configuration_id' => $this->fromConfiguration->getId(),
'crm_provider_id' => null,
]);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
23050
|
981
|
21
|
2026-05-12T07:31:14.434012+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778571074434_m2.jpg...
|
Firefox
|
Data Explorer — Work
|
True
|
ws.planhat.com/jiminny/home/data-explorer/usagemet ws.planhat.com/jiminny/home/data-explorer/usagemetricdef?preview=UsageMetricDef.69f2c6529c9f21b58804f123...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
New Tab
New Tab
Jy 20820 es reindex stream model h New Tab
New Tab
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
LLM pricing overview with the most actual prices - Google Search
LLM pricing overview with the most actual prices - Google Search
Planhat
Planhat
Data Explorer
Data Explorer
Close tab
Login
Login
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Copy prompt
Edit
You said I am on https://app-eu3.planhat.com/ how to get to ws.planhat.com
You said
I am on https://app-eu3.planhat.com/ how to get to ws.planhat.com
Listen
Gemini said
Gemini said
To get to
ws.planhat.com
(which is the address for the "Upgraded Planhat" or "Next Generation" interface) while you are currently on the EU regional server (
app-eu3.planhat.com
), you have two primary options:
1. The Manual URL Change
1. The Manual URL Change
Because Planhat uses specific subdomains for different versions and regions, you can try navigating directly. However, note that
ws.planhat.com
is a global entry point for the upgraded platform.
Try navigating to:
https://ws.planhat.com
https://ws.planhat.com
If your account has been migrated to the upgraded version, it should recognize your session or prompt you to log in.
Note:
If your data is specifically hosted on the
eu3
cluster, the system may automatically redirect you to a regional version of the upgraded UI (e.g.,
ws-eu3.planhat.com
).
2. The In-App "Switch" (If Available)
2. The In-App "Switch" (If Available)
If your tenant is eligible for the upgrade but you are still in the classic "app" view, look for these UI elements:
The Top Gray Bar:
Click on your
Tenant Name/Logo
in the top-left corner. This often opens the "Global Tools" menu.
Upgrade Prompts:
In some instances, Planhat places a "Try the new Planhat" or "Upgraded Planhat" toggle in the Help menu (the
"?" icon
in the top right) or as a banner at the top of the screen.
Why use ws.planhat.com?
Why use ws.planhat.com?
You likely need this URL to access newer "Global Tools" and features that are only available in the upgraded version, such as:
Data Model Manager:
For advanced field and object configuration.
Portal Manager:
To manage customer-facing portals.
Workflows:
The newer engine for automating projects and sequences.
Federated Search:
Located in the middle of the top gray bar in the
ws
version.
Important Troubleshooting:
Permissions:
If you try to access
ws.planhat.com
and get an error or a blank screen, your user
Role
may lack the "Admin Access" or "Upgraded Access" permissions. You will need a current Admin to enable these for you in the
Settings > Users & Roles
section of the current app.
NPS Campaigns:
Note that as of recent updates, some features like NPS configuration might still require you to briefly switch back to the classic
app.planhat.com
view while they are being finalized for the
ws
environment.
Good response
Bad response
Redo
Share & export
Copy
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Fast
Microphone
Send message
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
J J Jiminny
J
Jiminny
Search Jiminny ⌘K
Search Jiminny
⌘
K
L
Lukas
Content Explorer
Content Explorer
Data Explorer
Data Explorer
Calendar
Calendar
Notifications
Notifications
More
More
Sections
Sections
CS Day-to-day
🚀 Getting started Guide
🪬 Just CS Data
👉 Daily Operations
🗓️ Weekly prep
🤑 Renewals and Upsell
🚨 Risk and Churn Analytics
Implementation
Impl Projects
Trial Opps (Under Review)
Stoyan's clients
Metric
Tab icon Dataset
Dataset
aut
1 metric
Reset
Add chart
Add chart
Name
Type
Model
Description
Created By
Created date
Updated date
Featured
Group
EndUser
1
automated-reports-track-interest
automated-reports-track-interest
User Activities
EndUser
-
-
-
-
-
Name
automated-reports-track-interest
automated-reports-track-interest
Type
User Activities
Model
EndUser
Description
-
Created By
-
Created date
-
Updated date
-
Featured
Group
-
Search fields...
Global filters
Global filters
Advanced filter
Advanced filter
Default
Aggregation mode
Aggregation mode
Availability in Planhat
Availability in Planhat
Build Period
Build Period
Created By
Created By
Created date
Created date
Created date
Created date
Description
Description
Featured
Featured
Formula
Formula
Group
Group
Last Built
Last Built...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.0,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.013297873,"top":0.06304868,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.09577015,"width":0.16888298,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira","depth":4,"bounds":{"left":0.0,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.12849163,"width":0.16140293,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.15003991,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.16121309,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.18276137,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.19393456,"width":0.039228722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pull requests · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.21548285,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.22665602,"width":0.04537899,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20773] User Pilot not receiving events on report generated - Jira","depth":4,"bounds":{"left":0.0,"top":0.2482043,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20773] User Pilot not receiving events on report generated - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.25937748,"width":0.1200133,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.28092578,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.29209897,"width":0.19331782,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20776] Automated report - sentry - Jira","depth":4,"bounds":{"left":0.0,"top":0.31364724,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20776] Automated report - sentry - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.32482043,"width":0.07646277,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":4,"bounds":{"left":0.0,"top":0.3463687,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":5,"bounds":{"left":0.013297873,"top":0.3575419,"width":0.40475398,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":4,"bounds":{"left":0.0,"top":0.3790902,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":5,"bounds":{"left":0.013297873,"top":0.39026338,"width":0.40475398,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0,"top":0.41181165,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.42298484,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.4445331,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.4557063,"width":0.15159574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"LLM pricing overview with the most actual prices - Google Search","depth":4,"bounds":{"left":0.0,"top":0.4772546,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"LLM pricing overview with the most actual prices - Google Search","depth":5,"bounds":{"left":0.013297873,"top":0.4884278,"width":0.1143617,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Planhat","depth":4,"bounds":{"left":0.0,"top":0.509976,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Planhat","depth":5,"bounds":{"left":0.013297873,"top":0.5211492,"width":0.012965426,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Data Explorer","depth":4,"bounds":{"left":0.0,"top":0.54269755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Data Explorer","depth":5,"bounds":{"left":0.013297873,"top":0.55387074,"width":0.0234375,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.54988027,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Login","depth":4,"bounds":{"left":0.0,"top":0.575419,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login","depth":5,"bounds":{"left":0.013297873,"top":0.5865922,"width":0.009474734,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.6097366,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.1846742,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.1966423,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.1939827,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08361037,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.16605718,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.17935506,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said I am on https://app-eu3.planhat.com/ how to get to ws.planhat.com","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I am on https://app-eu3.planhat.com/ how to get to ws.planhat.com","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"bounds":{"left":0.1939827,"top":0.0,"width":0.013297873,"height":0.031923383},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":20,"bounds":{"left":0.08460771,"top":0.0,"width":0.0003324468,"height":0.0007980846},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"bounds":{"left":0.08460771,"top":0.0,"width":0.04105718,"height":0.01915403},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To get to","depth":24,"bounds":{"left":0.08759973,"top":0.0,"width":0.022606382,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ws.planhat.com","depth":24,"bounds":{"left":0.11020612,"top":0.0,"width":0.04105718,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(which is the address for the \"Upgraded Planhat\" or \"Next Generation\" interface) while you are currently on the EU regional server (","depth":24,"bounds":{"left":0.08759973,"top":0.0,"width":0.11702128,"height":0.07861133},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app-eu3.planhat.com","depth":24,"bounds":{"left":0.08759973,"top":0.015961692,"width":0.07662899,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), you have two primary options:","depth":24,"bounds":{"left":0.08759973,"top":0.03671189,"width":0.101230055,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. The Manual URL Change","depth":23,"bounds":{"left":0.08759973,"top":0.0981644,"width":0.11702128,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. The Manual URL Change","depth":24,"bounds":{"left":0.08759973,"top":0.09976058,"width":0.068317816,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Because Planhat uses specific subdomains for different versions and regions, you can try navigating directly. However, note that","depth":24,"bounds":{"left":0.08759973,"top":0.12609737,"width":0.11336436,"height":0.057861134},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ws.planhat.com","depth":24,"bounds":{"left":0.08759973,"top":0.18834797,"width":0.04105718,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is a global entry point for the upgraded platform.","depth":24,"bounds":{"left":0.08759973,"top":0.18834797,"width":0.11319814,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Try navigating to:","depth":26,"bounds":{"left":0.10023271,"top":0.2386273,"width":0.04288564,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"https://ws.planhat.com","depth":26,"bounds":{"left":0.14311835,"top":0.2386273,"width":0.05501995,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"https://ws.planhat.com","depth":27,"bounds":{"left":0.14311835,"top":0.2386273,"width":0.05501995,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If your account has been migrated to the upgraded version, it should recognize your session or prompt you to log in.","depth":26,"bounds":{"left":0.10023271,"top":0.26815644,"width":0.104222074,"height":0.057861134},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Note:","depth":26,"bounds":{"left":0.10023271,"top":0.33918595,"width":0.013962766,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If your data is specifically hosted on the","depth":26,"bounds":{"left":0.10023271,"top":0.33918595,"width":0.10322473,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"eu3","depth":27,"bounds":{"left":0.11153591,"top":0.36113328,"width":0.008477394,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cluster, the system may automatically redirect you to a regional version of the upgraded UI (e.g.,","depth":26,"bounds":{"left":0.10023271,"top":0.35993615,"width":0.09541223,"height":0.057861134},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ws-eu3.planhat.com","depth":27,"bounds":{"left":0.10023271,"top":0.40263367,"width":0.089428194,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"bounds":{"left":0.14411569,"top":0.42218676,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. The In-App \"Switch\" (If Available)","depth":23,"bounds":{"left":0.08759973,"top":0.46288908,"width":0.11702128,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. The In-App \"Switch\" (If Available)","depth":24,"bounds":{"left":0.08759973,"top":0.46448523,"width":0.092586435,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If your tenant is eligible for the upgrade but you are still in the classic \"app\" view, look for these UI elements:","depth":24,"bounds":{"left":0.08759973,"top":0.49082202,"width":0.116023935,"height":0.057861134},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Top Gray Bar:","depth":26,"bounds":{"left":0.10023271,"top":0.56185156,"width":0.046210106,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Click on your","depth":26,"bounds":{"left":0.14644282,"top":0.56185156,"width":0.033909574,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tenant Name/Logo","depth":26,"bounds":{"left":0.10023271,"top":0.56185156,"width":0.09923537,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"in the top-left corner. This often opens the \"Global Tools\" menu.","depth":26,"bounds":{"left":0.10023271,"top":0.5826017,"width":0.09524601,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upgrade Prompts:","depth":26,"bounds":{"left":0.10023271,"top":0.6328811,"width":0.047041222,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"In some instances, Planhat places a \"Try the new Planhat\" or \"Upgraded Planhat\" toggle in the Help menu (the","depth":26,"bounds":{"left":0.10023271,"top":0.6328811,"width":0.10106383,"height":0.07861133},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"?\" icon","depth":26,"bounds":{"left":0.1263298,"top":0.69513166,"width":0.019780586,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"in the top right) or as a banner at the top of the screen.","depth":26,"bounds":{"left":0.10023271,"top":0.69513166,"width":0.10372341,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Why use ws.planhat.com?","depth":23,"bounds":{"left":0.08759973,"top":0.7565842,"width":0.11702128,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Why use ws.planhat.com?","depth":24,"bounds":{"left":0.08759973,"top":0.7581804,"width":0.06732048,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You likely need this URL to access newer \"Global Tools\" and features that are only available in the upgraded version, such as:","depth":24,"bounds":{"left":0.08759973,"top":0.78451717,"width":0.11702128,"height":0.057861134},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Data Model Manager:","depth":26,"bounds":{"left":0.10023271,"top":0.8555467,"width":0.055352394,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"For advanced field and object configuration.","depth":26,"bounds":{"left":0.10023271,"top":0.8555467,"width":0.10289229,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Portal Manager:","depth":26,"bounds":{"left":0.10023271,"top":0.90582603,"width":0.04138963,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To manage customer-facing portals.","depth":26,"bounds":{"left":0.10023271,"top":0.90582603,"width":0.095578454,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Workflows:","depth":26,"bounds":{"left":0.10023271,"top":0.95610535,"width":0.028756648,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The newer engine for automating projects and sequences.","depth":26,"bounds":{"left":0.10023271,"top":0.95610535,"width":0.08809841,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Federated Search:","depth":26,"bounds":{"left":0.10023271,"top":1.0,"width":0.04737367,"height":-0.0063847303},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Located in the middle of the top gray bar in the","depth":26,"bounds":{"left":0.10023271,"top":1.0,"width":0.10239362,"height":-0.0063847303},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ws","depth":27,"bounds":{"left":0.16389628,"top":1.0,"width":0.0056515955,"height":-0.028331995},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"version.","depth":26,"bounds":{"left":0.17154256,"top":1.0,"width":0.019946808,"height":-0.027134895},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important Troubleshooting:","depth":24,"bounds":{"left":0.08759973,"top":1.0,"width":0.0709774,"height":-0.0606544},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Permissions:","depth":26,"bounds":{"left":0.10023271,"top":1.0,"width":0.03274601,"height":-0.090183616},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you try to access","depth":26,"bounds":{"left":0.13297872,"top":1.0,"width":0.04870346,"height":-0.090183616},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ws.planhat.com","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and get an error or a blank screen, your user","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Role","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"may lack the \"Admin Access\" or \"Upgraded Access\" permissions. You will need a current Admin to enable these for you in the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Settings > Users & Roles","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"section of the current app.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NPS Campaigns:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Note that as of recent updates, some features like NPS configuration might still require you to briefly switch back to the classic","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app.planhat.com","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"view while they are being finalized for the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ws","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"environment.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":21,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":21,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Redo","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Share & export","depth":20,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXTextArea","text":"Enter a prompt for Gemini\nencrypted","depth":20,"bounds":{"left":0.09291888,"top":0.8216281,"width":0.10638298,"height":0.01915403},"on_screen":true,"value":"Enter a prompt for Gemini\nencrypted","help_text":"","role_description":"text entry area","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enter a prompt for Gemini","depth":21,"bounds":{"left":0.099567816,"top":0.82202715,"width":0.069980055,"height":0.018355945},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"encrypted","depth":21,"bounds":{"left":0.091921546,"top":0.8216281,"width":0.0066489363,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open upload file menu","depth":20,"bounds":{"left":0.08892952,"top":0.8575419,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tools","depth":18,"bounds":{"left":0.10488697,"top":0.8575419,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open mode picker","depth":20,"bounds":{"left":0.16007313,"top":0.85514766,"width":0.027925532,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fast","depth":23,"bounds":{"left":0.1653923,"top":0.8639266,"width":0.00930851,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Microphone","depth":19,"bounds":{"left":0.18999335,"top":0.85514766,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send message","depth":19,"bounds":{"left":0.19630983,"top":0.85434955,"width":0.013962766,"height":0.033519555},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.","depth":17,"bounds":{"left":0.08510638,"top":0.90901834,"width":0.11951463,"height":0.025139665},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Your privacy & Gemini Opens in a new window","depth":17,"bounds":{"left":0.16705452,"top":0.92178774,"width":0.040059842,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your privacy & Gemini","depth":18,"bounds":{"left":0.16705452,"top":0.92178774,"width":0.040059842,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Opens in a new window","depth":19,"bounds":{"left":0.079288565,"top":0.92098963,"width":0.043218084,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Summarize page","depth":7,"bounds":{"left":0.08494016,"top":0.95730245,"width":0.053523935,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summarize page","depth":9,"bounds":{"left":0.09059176,"top":0.96249,"width":0.042220745,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"J J Jiminny","depth":8,"bounds":{"left":0.22074468,"top":0.058260176,"width":0.03474069,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"J","depth":11,"bounds":{"left":0.22423537,"top":0.07940942,"width":0.0023271276,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny","depth":9,"bounds":{"left":0.23204787,"top":0.06304868,"width":0.016123671,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search Jiminny ⌘K","depth":9,"bounds":{"left":0.508145,"top":0.058260176,"width":0.21143617,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search Jiminny","depth":11,"bounds":{"left":0.5187833,"top":0.06304868,"width":0.031416222,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"⌘","depth":10,"bounds":{"left":0.70478725,"top":0.06344773,"width":0.0039893617,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"K","depth":10,"bounds":{"left":0.71359706,"top":0.06344773,"width":0.0026595744,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"L","depth":11,"bounds":{"left":0.9734042,"top":0.06304868,"width":0.002493351,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Lukas","depth":10,"bounds":{"left":0.9812167,"top":0.06304868,"width":0.012300532,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Content Explorer","depth":12,"bounds":{"left":0.2209109,"top":0.09377494,"width":0.07114362,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Content Explorer","depth":14,"bounds":{"left":0.23287898,"top":0.09936153,"width":0.03474069,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Data Explorer","depth":12,"bounds":{"left":0.2209109,"top":0.11931365,"width":0.07114362,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Data Explorer","depth":14,"bounds":{"left":0.23287898,"top":0.12490024,"width":0.027925532,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":12,"bounds":{"left":0.2209109,"top":0.14485236,"width":0.07114362,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Calendar","depth":14,"bounds":{"left":0.23287898,"top":0.15043895,"width":0.01861702,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":12,"bounds":{"left":0.2209109,"top":0.17039107,"width":0.07114362,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":14,"bounds":{"left":0.23287898,"top":0.17597765,"width":0.026263298,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More","depth":12,"bounds":{"left":0.2209109,"top":0.19592977,"width":0.07114362,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"More","depth":14,"bounds":{"left":0.23287898,"top":0.20151636,"width":0.010638298,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Sections","depth":13,"bounds":{"left":0.2209109,"top":0.23264167,"width":0.07114362,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sections","depth":15,"bounds":{"left":0.22224069,"top":0.23782921,"width":0.01662234,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CS Day-to-day","depth":16,"bounds":{"left":0.23487367,"top":0.26456505,"width":0.030751329,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"🚀 Getting started Guide","depth":18,"bounds":{"left":0.23487367,"top":0.29010376,"width":0.049700797,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"🪬 Just CS Data","depth":18,"bounds":{"left":0.23487367,"top":0.3140463,"width":0.032081116,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"👉 Daily Operations","depth":18,"bounds":{"left":0.23487367,"top":0.33798882,"width":0.03956117,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"🗓️ Weekly prep","depth":18,"bounds":{"left":0.23487367,"top":0.36193135,"width":0.03125,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"🤑 Renewals and Upsell","depth":18,"bounds":{"left":0.23487367,"top":0.3858739,"width":0.048204787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"🚨 Risk and Churn Analytics","depth":18,"bounds":{"left":0.23487367,"top":0.40981644,"width":0.05718085,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Implementation","depth":16,"bounds":{"left":0.23487367,"top":0.44972068,"width":0.032579787,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Impl Projects","depth":18,"bounds":{"left":0.23487367,"top":0.47525936,"width":0.026761968,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Trial Opps (Under Review)","depth":18,"bounds":{"left":0.23487367,"top":0.49920192,"width":0.054022606,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Stoyan's clients","depth":18,"bounds":{"left":0.23487367,"top":0.5231444,"width":0.032579787,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Metric","depth":18,"bounds":{"left":0.31166887,"top":0.09856345,"width":0.012965426,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Tab icon Dataset","depth":16,"bounds":{"left":0.3402593,"top":0.087789305,"width":0.030585106,"height":0.035115723},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Dataset","depth":18,"bounds":{"left":0.35023272,"top":0.09856345,"width":0.015957447,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"aut","depth":19,"bounds":{"left":0.31050533,"top":0.12968874,"width":0.059175532,"height":0.0207502},"on_screen":true,"value":"aut","help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1 metric","depth":19,"bounds":{"left":0.3956117,"top":0.13328013,"width":0.015791224,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Reset","depth":18,"bounds":{"left":0.83410907,"top":0.13048683,"width":0.015625,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Add chart","depth":18,"bounds":{"left":0.85837764,"top":0.12889066,"width":0.032579787,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Add chart","depth":20,"bounds":{"left":0.8678524,"top":0.13328013,"width":0.020279255,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Name","depth":26,"bounds":{"left":0.31881648,"top":0.16679968,"width":0.012134309,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Type","depth":26,"bounds":{"left":0.41722074,"top":0.16679968,"width":0.010305851,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Model","depth":26,"bounds":{"left":0.46908244,"top":0.16679968,"width":0.012799202,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Description","depth":26,"bounds":{"left":0.52393615,"top":0.16679968,"width":0.023769947,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created By","depth":26,"bounds":{"left":0.6050532,"top":0.16679968,"width":0.022938829,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created date","depth":26,"bounds":{"left":0.64461434,"top":0.16679968,"width":0.026761968,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated date","depth":26,"bounds":{"left":0.6825133,"top":0.16679968,"width":0.027925532,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Featured","depth":26,"bounds":{"left":0.72041225,"top":0.16679968,"width":0.018284574,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Group","depth":26,"bounds":{"left":0.7702792,"top":0.16679968,"width":0.012632979,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EndUser","depth":25,"bounds":{"left":0.32280585,"top":0.19752593,"width":0.01761968,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":26,"bounds":{"left":0.3444149,"top":0.19752593,"width":0.0018284575,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"automated-reports-track-interest","depth":26,"bounds":{"left":0.31948137,"top":0.22705507,"width":0.07413564,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"automated-reports-track-interest","depth":28,"bounds":{"left":0.32214096,"top":0.23064645,"width":0.06881649,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"User Activities","depth":28,"bounds":{"left":0.41722074,"top":0.23064645,"width":0.029587766,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EndUser","depth":28,"bounds":{"left":0.46908244,"top":0.23064645,"width":0.017453458,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":27,"bounds":{"left":0.52393615,"top":0.23064645,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":27,"bounds":{"left":0.60638297,"top":0.23064645,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":26,"bounds":{"left":0.64461434,"top":0.23064645,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":26,"bounds":{"left":0.6825133,"top":0.23064645,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":26,"bounds":{"left":0.77293885,"top":0.23144454,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Name","depth":25,"bounds":{"left":0.31881648,"top":0.16679968,"width":0.012134309,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"automated-reports-track-interest","depth":25,"bounds":{"left":0.31948137,"top":0.22705507,"width":0.07413564,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"automated-reports-track-interest","depth":27,"bounds":{"left":0.32214096,"top":0.23064645,"width":0.06881649,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Type","depth":25,"bounds":{"left":0.41722074,"top":0.16679968,"width":0.010305851,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"User Activities","depth":27,"bounds":{"left":0.41722074,"top":0.23064645,"width":0.029587766,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Model","depth":25,"bounds":{"left":0.46908244,"top":0.16679968,"width":0.012799202,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EndUser","depth":27,"bounds":{"left":0.46908244,"top":0.23064645,"width":0.017453458,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Description","depth":25,"bounds":{"left":0.52393615,"top":0.16679968,"width":0.023769947,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":26,"bounds":{"left":0.52393615,"top":0.23064645,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created By","depth":25,"bounds":{"left":0.6050532,"top":0.16679968,"width":0.022938829,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":26,"bounds":{"left":0.60638297,"top":0.23064645,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created date","depth":25,"bounds":{"left":0.64461434,"top":0.16679968,"width":0.026761968,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":25,"bounds":{"left":0.64461434,"top":0.23064645,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated date","depth":25,"bounds":{"left":0.6825133,"top":0.16679968,"width":0.027925532,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":25,"bounds":{"left":0.6825133,"top":0.23064645,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Featured","depth":25,"bounds":{"left":0.72041225,"top":0.16679968,"width":0.018284574,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Group","depth":25,"bounds":{"left":0.7702792,"top":0.16679968,"width":0.012632979,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":25,"bounds":{"left":0.77293885,"top":0.23144454,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Search fields...","depth":20,"bounds":{"left":0.91107047,"top":0.12809257,"width":0.07962101,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Global filters","depth":19,"bounds":{"left":0.90043217,"top":0.16400638,"width":0.09291888,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Global filters","depth":21,"bounds":{"left":0.91107047,"top":0.16879489,"width":0.026263298,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Advanced filter","depth":19,"bounds":{"left":0.90043217,"top":0.18635276,"width":0.09291888,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Advanced filter","depth":21,"bounds":{"left":0.91107047,"top":0.19114126,"width":0.03158245,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Default","depth":19,"bounds":{"left":0.9030917,"top":0.21707901,"width":0.013796543,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Aggregation mode","depth":19,"bounds":{"left":0.90043217,"top":0.23503591,"width":0.09291888,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Aggregation mode","depth":21,"bounds":{"left":0.9030917,"top":0.23982441,"width":0.038231384,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Availability in Planhat","depth":19,"bounds":{"left":0.90043217,"top":0.25738227,"width":0.09291888,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Availability in Planhat","depth":21,"bounds":{"left":0.9030917,"top":0.2621708,"width":0.043716755,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Build Period","depth":19,"bounds":{"left":0.90043217,"top":0.27972865,"width":0.09291888,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Build Period","depth":21,"bounds":{"left":0.9030917,"top":0.28451717,"width":0.024767287,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Created By","depth":19,"bounds":{"left":0.90043217,"top":0.30207503,"width":0.09291888,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Created By","depth":21,"bounds":{"left":0.9030917,"top":0.30686352,"width":0.022938829,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Created date","depth":19,"bounds":{"left":0.90043217,"top":0.32442138,"width":0.09291888,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Created date","depth":21,"bounds":{"left":0.9030917,"top":0.3292099,"width":0.026761968,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Created date","depth":19,"bounds":{"left":0.90043217,"top":0.34676775,"width":0.09291888,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Created date","depth":21,"bounds":{"left":0.9030917,"top":0.35155627,"width":0.026761968,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Description","depth":19,"bounds":{"left":0.90043217,"top":0.36911413,"width":0.09291888,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Description","depth":21,"bounds":{"left":0.9030917,"top":0.37390262,"width":0.023769947,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Featured","depth":19,"bounds":{"left":0.90043217,"top":0.3914605,"width":0.09291888,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Featured","depth":21,"bounds":{"left":0.9030917,"top":0.396249,"width":0.018284574,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Formula","depth":19,"bounds":{"left":0.90043217,"top":0.41380686,"width":0.09291888,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Formula","depth":21,"bounds":{"left":0.9030917,"top":0.41859537,"width":0.016788565,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Group","depth":19,"bounds":{"left":0.90043217,"top":0.43615323,"width":0.09291888,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Group","depth":21,"bounds":{"left":0.9030917,"top":0.44094175,"width":0.012632979,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Last Built","depth":19,"bounds":{"left":0.90043217,"top":0.4584996,"width":0.09291888,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Last Built","depth":21,"bounds":{"left":0.9030917,"top":0.4632881,"width":0.018949468,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-7745177908608266910
|
-2881755988589839738
|
visual_change
|
accessibility
|
NULL
|
New Tab
New Tab
Jy 20820 es reindex stream model h New Tab
New Tab
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
LLM pricing overview with the most actual prices - Google Search
LLM pricing overview with the most actual prices - Google Search
Planhat
Planhat
Data Explorer
Data Explorer
Close tab
Login
Login
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Copy prompt
Edit
You said I am on https://app-eu3.planhat.com/ how to get to ws.planhat.com
You said
I am on https://app-eu3.planhat.com/ how to get to ws.planhat.com
Listen
Gemini said
Gemini said
To get to
ws.planhat.com
(which is the address for the "Upgraded Planhat" or "Next Generation" interface) while you are currently on the EU regional server (
app-eu3.planhat.com
), you have two primary options:
1. The Manual URL Change
1. The Manual URL Change
Because Planhat uses specific subdomains for different versions and regions, you can try navigating directly. However, note that
ws.planhat.com
is a global entry point for the upgraded platform.
Try navigating to:
https://ws.planhat.com
https://ws.planhat.com
If your account has been migrated to the upgraded version, it should recognize your session or prompt you to log in.
Note:
If your data is specifically hosted on the
eu3
cluster, the system may automatically redirect you to a regional version of the upgraded UI (e.g.,
ws-eu3.planhat.com
).
2. The In-App "Switch" (If Available)
2. The In-App "Switch" (If Available)
If your tenant is eligible for the upgrade but you are still in the classic "app" view, look for these UI elements:
The Top Gray Bar:
Click on your
Tenant Name/Logo
in the top-left corner. This often opens the "Global Tools" menu.
Upgrade Prompts:
In some instances, Planhat places a "Try the new Planhat" or "Upgraded Planhat" toggle in the Help menu (the
"?" icon
in the top right) or as a banner at the top of the screen.
Why use ws.planhat.com?
Why use ws.planhat.com?
You likely need this URL to access newer "Global Tools" and features that are only available in the upgraded version, such as:
Data Model Manager:
For advanced field and object configuration.
Portal Manager:
To manage customer-facing portals.
Workflows:
The newer engine for automating projects and sequences.
Federated Search:
Located in the middle of the top gray bar in the
ws
version.
Important Troubleshooting:
Permissions:
If you try to access
ws.planhat.com
and get an error or a blank screen, your user
Role
may lack the "Admin Access" or "Upgraded Access" permissions. You will need a current Admin to enable these for you in the
Settings > Users & Roles
section of the current app.
NPS Campaigns:
Note that as of recent updates, some features like NPS configuration might still require you to briefly switch back to the classic
app.planhat.com
view while they are being finalized for the
ws
environment.
Good response
Bad response
Redo
Share & export
Copy
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Fast
Microphone
Send message
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
J J Jiminny
J
Jiminny
Search Jiminny ⌘K
Search Jiminny
⌘
K
L
Lukas
Content Explorer
Content Explorer
Data Explorer
Data Explorer
Calendar
Calendar
Notifications
Notifications
More
More
Sections
Sections
CS Day-to-day
🚀 Getting started Guide
🪬 Just CS Data
👉 Daily Operations
🗓️ Weekly prep
🤑 Renewals and Upsell
🚨 Risk and Churn Analytics
Implementation
Impl Projects
Trial Opps (Under Review)
Stoyan's clients
Metric
Tab icon Dataset
Dataset
aut
1 metric
Reset
Add chart
Add chart
Name
Type
Model
Description
Created By
Created date
Updated date
Featured
Group
EndUser
1
automated-reports-track-interest
automated-reports-track-interest
User Activities
EndUser
-
-
-
-
-
Name
automated-reports-track-interest
automated-reports-track-interest
Type
User Activities
Model
EndUser
Description
-
Created By
-
Created date
-
Updated date
-
Featured
Group
-
Search fields...
Global filters
Global filters
Advanced filter
Advanced filter
Default
Aggregation mode
Aggregation mode
Availability in Planhat
Availability in Planhat
Build Period
Build Period
Created By
Created By
Created date
Created date
Created date
Created date
Description
Description
Featured
Featured
Formula
Formula
Group
Group
Last Built
Last Built...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
11168
|
502
|
5
|
2026-05-08T18:38:05.026255+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778265485026_m2.jpg...
|
Code
|
finance-hub — Implementation Plan — finance [SSH: finance-hub — Implementation Plan — finance [SSH: nas]...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G)
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Claude Code - 1 session waiting for input
1
Containers
EXPLORER
EXPLORER
Explorer Section: finance [SSH: nas]
Explorer Section: finance [SSH: nas]
FINANCE [SSH: NAS]
auth
dsk-uploader
payments-logger
Outline Section
OUTLINE
OUTLINE
Timeline Section
TIMELINE
TIMELINE
payments.js, preview, Editor Group 1
…
payments.js, preview, Editor Group 1
Design new payment-logge…, Editor Group 2
finance-hub — Implementation Plan, Editor Group 3
remote SSH: nas
SSH: nas
No Problems
0
0
No Ports Forwarded
0
Notifications
Sign In
Sign In
collapsed
Design new payment-logger and dsk-uploader hybrid app
Session history
New session
Message actions
payments.js
payments.js
ets create a new app that should be combination of payment-logger and dsk-uploader. It should have authorization via authentik (auth folder). All three folders (payment-logger, dsk-uploader and auth) are just refference these will be removed later. Auth project is separated it lives on its own. First reveiw them and see how these should be combined. It will be whole new app (also the folder name). Think very carefully of whatr these two apps do and how cold they be combined. THerer should be common db and uploader should store data the same way the /ingest does. It should be properly marked in UI if it is upload or ingest or both. FIrst think of tech stack and plan carefully.
Thinking
Thinking
I'll explore all three reference projects in parallel to understand their structure before planning.
Agent:
Explore payment-logger app structure and functionality
IN
Explore the /volume2/docker/finance/payments-logger directory thoroughly. I need to understand:
1. Tech stack (frontend framework, backend framework, database)
2. What the app does - its core purpose and features
3. Database schema - all tables, relationships
4. API routes - all endpoints, their purpose and request/response shapes
5. How data flows (ingest, storage, retrieval)
6. Any auth/middleware setup
7. Docker/deployment setup
8. Key files and their roles
Report with: directory structure, tech stack summary, database schema details, all API endpoints listed, UI features, and how data is ingested. Be thorough on the /ingest endpoint specifically.
Agent:
Explore dsk-uploader app structure and functionality
IN
Explore the /volume2/docker/finance/dsk-uploader directory thoroughly. I need to understand:
1. Tech stack (frontend framework, backend framework, database)
2. What the app does - its core purpose and features
3. Database schema - all tables, relationships
4. API routes - all endpoints, their purpose and request/response shapes
5. How file uploads work - what files, what format, how parsed
6. Any auth/middleware setup
7. Docker/deployment setup
8. Key files and their roles
Report with: directory structure, tech stack summary, database schema details, all API endpoints listed, UI features, how file upload parsing works, and what data is extracted from uploads. Be very thorough about the data model and what fields are stored.
Agent:
Explore auth folder and authentik integration
IN
Explore the /volume2/docker/finance/auth directory thoroughly. I need to understand:
1. What auth system is being used (Authentik)
2. How authentication/authorization is implemented - OAuth2, OIDC, session tokens, JWT?
3. Middleware - how is auth enforced on routes?
4. Any frontend auth flow - login redirect, token handling, protected routes
5. Environment variables related to auth
6. Docker/deployment setup for the auth service itself
7. Any example of how other apps integrate with this auth
Report with: directory structure, auth flow description, middleware code, environment variable names, and integration patterns. This is a reference for building auth into a new combined app.
Message actions
payments.js
payments.js
continue
Thinking
Thinking
Launching parallel exploration of all three reference projects.
Agent:
Explore payment-logger app structure
IN
Explore the /volume2/docker/finance/payments-logger directory thoroughly. I need to understand:
1. Full directory structure (tree)
2. Tech stack (frontend framework, backend framework, database, etc.)
3. What the app does - its core functionality
4. How data is ingested (look at /ingest route especially)
5. Database schema (what tables/collections exist)
6. API routes and their purposes
7. Frontend pages and components
8. Docker setup
9. Any auth/session handling
Please read key files: package.json files, main entry points, route files, database schema files, docker-compose.yml, and any frontend components. Be thorough - I need a complete picture to plan a new combined app.
Bash
IN
find /volume2/docker/finance/payments-logger -type f -name "*.json" -o -name "*.js" -o -name "*.jsx" -o -name "*.ts" -o -name "*.tsx" -o -name "*.py" -o -name "*.sql" -o -name "Dockerfile*" -o -name "docker-compose*" -o -name ".env*" 2>/dev/null | head -50
Copy code to clipboard
OUT
/volume2/docker/finance/payments-logger/.env
/volume2/docker/finance/payments-logger/.env.example
/volume2/docker/finance/payments-logger/docker-compose.yml
/volume2/docker/finance/payments-logger/.claude/settings.local.json
/volume2/docker/finance/payments-logger/backend/Dockerfile
/volume2/docker/finance/payments-logger/backend/package.json
/volume2/docker/finance/payments-logger/frontend/Dockerfile
/volume2/docker/finance/payments-logger/frontend/package.json
/volume2/docker/finance/payments-logger/frontend/postcss.config.js
/volume2/docker/finance/payments-logger/frontend/tailwind.config.js
/volume2/docker/finance/payments-logger/frontend/vite.config.js
/volume2/docker/finance/payments-logger/auth/.env
/volume2/docker/finance/payments-logger/auth/.env.example
/volume2/docker/finance/payments-logger/backend/src/auth.js
/volume2/docker/finance/payments-logger/backend/src/index.js
/volume2/docker/finance/payments-logger/backend/src/parser.js
/volume2/docker/finance/payments-logger/frontend/src/App.jsx
/volume2/docker/finance/payments-logger/frontend/src/auth.js
/volume2/docker/finance/payments-logger/frontend/src/main.jsx
/volume2/docker/finance/payments-logger/backend/src/routes/payments.js
/volume2/docker/finance/payments-logger/frontend/src/components/AuthProvider.jsx
/volume2/docker/finance/payments-logger/frontend/src/components/FilterBar.jsx
/volume2/docker/finance/payments-logger/frontend/src/components/PaymentCard.jsx
/volume2/docker/finance/payments-logger/frontend/src/components/PaymentList.jsx
/volume2/docker/finance/payments-logger/frontend/src/components/PaymentTable.jsx
/volume2/docker/finance/payments-logger/backend/prisma/migrations/20260210_init/migration.sql
/volume2/docker/finance/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql
/volume2/docker/finance/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql
/volume2/docker/finance/payments-logger/backend/prisma/migrations/20260508_add_users/migration.sql
Agent:
Explore dsk-uploader app structure
IN
Explore the /volume2/docker/finance/dsk-uploader directory thoroughly. I need to understand:
1. Full directory structure (tree)
2. Tech stack (frontend framework, backend framework, database, etc.)
3. What the app does - its core functionality
4. How file uploads work (what format, what processing happens)
5. Database schema (what tables/collections exist)
6. API routes and their purposes
7. Frontend pages and components
8. Docker setup
9. Any auth/session handling
Please read key files: package.json files, main entry points, route files, database schema files, docker-compose.yml, and any frontend components. Be thorough - I need a complete picture to plan a new combined app.
Bash
IN
find /volume2/docker/finance/dsk-uploader -type f -name "*.json" -o -type f -name "*.yml" -o -type f -name "*.yaml" | head -30
Copy code to clipboard
OUT
/volume2/docker/finance/dsk-uploader/docker-compose.yml
Bash
IN
cd /volume2/docker/finance/payments-logger && find . -type f \( -name "*.json" -o -name "*.js" -o -name "*.jsx" -o -name "*.ts" -o -name "*.tsx" -o -name "*.sql" -o -name "*.yml" -o -name "*.yaml" -o -name "Dockerfile*" -o -name ".env*" \) | grep -v node_modules | sort
Copy code to clipboard
OUT
./auth/.env
./auth/.env.example
./backend/Dockerfile
./backend/package.json
./backend/prisma/migrations/20260210_init/migration.sql
./backend/prisma/migrations/20260210_simplify/migration.sql
./backend/prisma/migrations/20260222_add_card/migration.sql
./backend/prisma/migrations/20260508_add_users/migration.sql
./backend/src/auth.js
./backend/src/index.js
./backend/src/parser.js
./backend/src/routes/payments.js
./.claude/settings.local.json
./docker-compose.yml
./.env
./.env.example
./frontend/Dockerfile
./frontend/package.json
./frontend/postcss.config.js
./frontend/src/App.jsx
./frontend/src/auth.js
./frontend/src/components/AuthProvider.jsx
./frontend/src/components/FilterBar.jsx
./frontend/src/components/PaymentCard.jsx
./frontend/src/components/PaymentList.jsx
./frontend/src/components/PaymentTable.jsx
./frontend/src/main.jsx
./frontend/tailwind.config.js
./frontend/vite.config.js
Agent:
Explore auth project structure
IN
Explore the /volume2/docker/finance/auth directory thoroughly. I need to understand:
1. Full directory structure (tree)
2. What authentication system is used (authentik integration details)
3. How OAuth/OIDC flow works
4. Any middleware or helper functions for protecting routes
5. Session management approach
6. How frontend handles auth state
7. Any example of how other apps integrate with this auth system
8. Docker setup and environment variables
Please read all files carefully - this auth system will be integrated into a new combined app. I need to understand exactly how to use it.
Bash
IN
cd /volume2/docker/finance/dsk-uploader && find . -type f | head -100
Copy code to clipboard
OUT
./.gitignore
./README.md
./USAGE.md
./app.py
./app_flask.py
./dskuploader.py
./requirements.txt
./.env
./.env.example
./Dockerfile
./docker-compose.yml
./.dockerignore
./.git/description
./.git/packed-refs
./.git/HEAD
./.git/FETCH_HEAD
./.git/index
./.git/COMMIT_EDITMSG
./.git/ORIG_HEAD
./notion_connector/__init__.py
./notion_connector/client.py
./templates/base.html
./templates/index.html
./templates/result.html
./notion_connector/resources/__init__.py
./notion_connector/resources/block.py
./notion_connector/resources/block_property.py
./notion_connector/resources/database.py
./notion_connector/resources/database_property.py
./notion_connector/resources/filter_builder.py
./notion_connector/resources/page.py
./notion_connector/resources/page_property.py
./notion_connector/resources/search.py
./.git/info/exclude
./.git/hooks/post-update.sample
./.git/hooks/pre-applypatch.sample
./.git/hooks/pre-commit.sample
./.git/hooks/applypatch-msg.sample
./.git/hooks/pre-rebase.sample
./.git/hooks/pre-merge-commit.sample
./.git/hooks/update.sample
./.git/hooks/pre-push.sample
./.git/hooks/push-to-checkout.sample
./.git/hooks/prepare-commit-msg.sample
./.git/hooks/commit-msg.sample
./.git/hooks/pre-receive.sample
./.git/hooks/fsmonitor-watchman.sample
./.git/logs/HEAD
./notion_connector/exceptions/__init__.py
./notion_connector/exceptions/exceptions.py
./.git/config
./.git/refs/heads/main
./.git/refs/remotes/origin/HEAD
./.git/refs/remotes/origin/main
./.git/objects/7c/3f071fef98751a68b7d93779f76cf5d5aa8ebf
./.git/objects/ed/8e93af8cc77c7a85f87a9f37573c51b839e571
./.git/objects/7b/2d7b18213f9516ec4544f309772ee4808146bb
./.git/objects/65/386fd3b4ac62094500e21c23845d05b9d18a4f
./.git/objects/ee/3d5f92e57deec809abda371386e371f32de9bb
./.git/logs/refs/heads/main
./.git/objects/pack/pack-ed5aca57f7f3b56e67172d9fb90e685087770006.pack
./.git/objects/pack/pack-ed5aca57f7f3b56e67172d9fb90e685087770006.idx
./.git/objects/85/b5483672f68c327c39ea8c29e94ae8b22b7bbf
./.git/objects/f3/98248da8f4911d463d9a33155fcf58a65092cc
./.git/objects/0b/918bed65202bedaa9fa092e539d607be2eea65
./.git/objects/8e/a1cbf78eae8a86c5990d0582db1847c0226b56
./.git/objects/11/b908125d2f0feebf7aca6d24e127f334bce611
./.git/objects/56/a2766ae5422b18e5b1a418fd231ad12fef08e6
./.git/logs/refs/remotes/origin/HEAD
./.git/logs/refs/remotes/origin/main
Bash
IN
find /volume2/docker/finance/auth -type f -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.tsx" -o -name "*.json" -o -name "*.yaml" -o -name "*.yml" -o -name "*.env*" -o -name "Dockerfile*" | head -100
Copy code to clipboard
OUT
/volume2/docker/finance/auth/.env
/volume2/docker/finance/auth/.env.example
/volume2/docker/finance/auth/docker-compose.yml
/volume2/docker/finance/auth/auth/.env
/volume2/docker/finance/auth/auth/.env.example
/volume2/docker/finance/auth/auth/docker-compose.yml
Read
dsk-uploader
dsk-uploader
Read
docker-compose.yml
docker-compose.yml
Read
package.json
package.json
Read
package.json
package.json
Read
.env.example
.env.example
Bash
IN
ls -la /volume2/docker/finance/auth/ && echo "---" && find /volume2/docker/finance/auth -type d | sort
Copy code to clipboard
OUT
total 20
drwxrwxrwx 1 Adm1n admin 108 May 8 21:08 .
drwxrwxrwx 1 Adm1n admin 62 May 8 21:10 ..
drwxrwxrwx 1 Adm1n admin 128 May 8 21:08 auth
drwxrwxrwx 1 Adm1n admin 0 May 8 21:06 certs
drwxrwxrwx 1 Adm1n admin 0 May 8 21:06 db
-rwxrwxrwx 1 Adm1n admin 3328 May 8 21:07 docker-compose.yml
-rwxrwxrwx 1 Adm1n admin 949 May 8 21:06 .env
-rwxrwxrwx 1 Adm1n admin 2258 May 8 21:06 .env.example
-rwxrwxrwx 1 Adm1n admin 5501 May 8 21:07 README.md
---
/volume2/docker/finance/auth
/volume2/docker/finance/auth/auth
/volume2/docker/finance/auth/auth/certs
/volume2/docker/finance/auth/auth/db
/volume2/docker/finance/auth/auth/db/base
/volume2/docker/finance/auth/auth/db/base/1
/volume2/docker/finance/auth/auth/db/base/16384
/volume2/docker/finance/auth/auth/db/base/4
/volume2/docker/finance/auth/auth/db/base/5
/volume2/docker/finance/auth/auth/db/global
/volume2/docker/finance/auth/auth/db/pg_commit_ts
/volume2/docker/finance/auth/auth/db/pg_dynshmem
/volume2/docker/finance/auth/auth/db/pg_logical
/volume2/docker/finance/auth/auth/db/pg_logical/mappings
/volume2/docker/finance/auth/auth/db/pg_logical/snapshots
/volume2/docker/finance/auth/auth/db/pg_multixact
/volume2/docker/finance/auth/auth/db/pg_multixact/members
/volume2/docker/finance/auth/auth/db/pg_multixact/offsets
/volume2/docker/finance/auth/auth/db/pg_notify
/volume2/docker/finance/auth/auth/db/pg_replslot
/volume2/docker/finance/auth/auth/db/pg_serial
/volume2/docker/finance/auth/auth/db/pg_snapshots
/volume2/docker/finance/auth/auth/db/pg_stat
/volume2/docker/finance/auth/auth/db/pg_stat_tmp
/volume2/docker/finance/auth/auth/db/pg_subtrans
/volume2/docker/finance/auth/auth/db/pg_tblspc
/volume2/docker/finance/auth/auth/db/pg_twophase
/volume2/docker/finance/auth/auth/db/pg_wal
/volume2/docker/finance/auth/auth/db/pg_wal/archive_status
/volume2/docker/finance/auth/auth/db/pg_xact
/volume2/docker/finance/auth/auth/media
/volume2/docker/finance/auth/auth/templates
/volume2/docker/finance/auth/certs
/volume2/docker/finance/auth/db
Read
README.md
README.md
Read
requirements.txt
requirements.txt
Read
index.js
index.js
Read
payments.js
payments.js
Read
auth.js
auth.js
Read
README.md
README.md
Read
.env
.env
Read
.env.example
.env.example
Read
docker-compose.yml
docker-compose.yml
Read
parser.js
parser.js
Bash
IN
find /volume2/docker/finance/auth/auth -type f | grep -v "^/volume2/docker/finance/auth/auth/db" | grep -v "^/volume2/docker/finance/auth/auth/certs" | grep -v "^/volume2/docker/finance/auth/auth/media" | sort
Copy code to clipboard
OUT
/volume2/docker/finance/auth/auth/docker-compose.yml
/volume2/docker/finance/auth/auth/.env
/volume2/docker/finance/auth/auth/.env.example
/volume2/docker/finance/auth/auth/README.md
Read
migration.sql
migration.sql
Read
migration.sql
migration.sql
Read
README.md
README.md
Read
.env
.env
Read
.env.example
.env.example
Read
docker-compose.yml
docker-compose.yml
Read
App.jsx
App.jsx
Read
main.jsx
main.jsx
Read
auth.js
auth.js
Bash
IN
find /volume2/docker/finance -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.tsx" 2>/dev/null | head -50
Copy code to clipboard
OUT
/volume2/docker/finance/dsk-uploader/app.py
/volume2/docker/finance/dsk-uploader/app_flask.py
/volume2/docker/finance/dsk-uploader/dskuploader.py
/volume2/docker/finance/payments-logger/frontend/postcss.config.js
/volume2/docker/finance/payments-logger/frontend/tailwind.config.js
/volume2/docker/finance/payments-logger/frontend/vite.config.js
/volume2/docker/finance/dsk-uploader/notion_connector/__init__.py
/volume2/docker/finance/dsk-uploader/notion_connector/client.py
/volume2/docker/finance/payments-logger/backend/src/auth.js
/volume2/docker/finance/payments-logger/backend/src/index.js
/volume2/docker/finance/payments-logger/backend/src/parser.js
/volume2/docker/finance/payments-logger/frontend/src/auth.js
/volume2/docker/finance/dsk-uploader/notion_connector/resources/__init__.py
/volume2/docker/finance/dsk-uploader/notion_connector/resources/block.py
/volume2/docker/finance/dsk-uploader/notion_connector/resources/block_property.py
/volume2/docker/finance/dsk-uploader/notion_connector/resources/database.py
/volume2/docker/finance/dsk-uploader/notion_connector/resources/database_property.py
/volume2/docker/finance/dsk-uploader/notion_connector/resources/filter_builder.py
/volume2/docker/finance/dsk-uploader/notion_connector/resources/page.py
/volume2/docker/finance/dsk-uploader/notion_connector/resources/page_property.py
/volume2/docker/finance/dsk-uploader/notion_connector/resources/search.py
/volume2/docker/finance/payments-logger/backend/src/routes/payments.js
/volume2/docker/finance/dsk-uploader/notion_connector/exceptions/__init__.py
/volume2/docker/finance/dsk-uploader/notion_connector/exceptions/exceptions.py
Read
AuthProvider.jsx
AuthProvider.jsx
Read
PaymentTable.jsx
PaymentTable.jsx
Read
FilterBar.jsx
FilterBar.jsx
Read
auth.js
auth.js
Read
auth.js
auth.js
Read
index.js
index.js
Read
Dockerfile
Dockerfile
Read
Dockerfile
Dockerfile
Read
migration.sql
migration.sql
Bash
IN
find /volume2/docker/finance/payments-logger -name "docker-compose.yml" -o -name ".env*" -o -name "package.json" | head -20
Copy code to clipboard
OUT
/volume2/docker/finance/payments-logger/.env
/volume2/docker/finance/payments-logger/.env.example
/volume2/docker/finance/payments-logger/docker-compose.yml
/volume2/docker/finance/payments-logger/backend/package.json
/volume2/docker/finance/payments-logger/frontend/package.json
/volume2/docker/finance/payments-logger/auth/.env
/volume2/docker/finance/payments-logger/auth/.env.example
Bash
IN
find /volume2/docker/finance/payments-logger -name "schema.prisma" -type f
Copy code to clipboard
OUT
/volume2/docker/finance/payments-logger/backend/prisma/schema.prisma
Read
docker-compose.yml
docker-compose.yml
Read
.env
.env
Read
.env.example
.env.example
Read
schema.prisma
schema.prisma
Bash
IN
ls -la /volume2/docker/finance/payments-logger/auth/ && echo "---" && find /volume2/docker/finance/payments-logger -name "Dockerfile*" | head -10
Copy code to clipboard
OUT
total 16
drwxrwxrwx 1 Adm1n admin 64 May 8 21:07 .
drwxrwxrwx 1 Adm1n admin 170 May 8 21:07 ..
drwxrwxrwx 1 Adm1n admin 0 May 8 21:07 certs
drwxrwxrwx 1 Adm1n admin 0 May 8 21:07 db
-rwxrwxrwx 1 Adm1n admin 949 May 8 21:07 .env
-rwxrwxrwx 1 Adm1n admin 2258 May 8 21:07 .env.example
-rwxrwxrwx 1 Adm1n admin 5501 May 8 21:07 README.md
---
/volume2/docker/finance/payments-logger/backend/Dockerfile
/volume2/docker/finance/payments-logger/frontend/Dockerfile
Bash
IN
cd /volume2/docker/finance/payments-logger && tree -L 3 -I 'node_modules|.next|dist|build' --charset ascii 2>/dev/null || find . -not -path '*/node_modules/*' -not -path '*/.git/*' -not -path '*/dist/*' -type f | head -60
Copy code to clipboard
OUT
.
|-- API.md
|-- auth
| |-- certs
| |-- db
| `-- README.md
|-- backend
| |-- Dockerfile
| |-- package.json
| |-- prisma
| | |-- migrations
| | `-- schema.prisma
| `-- src
| |-- auth.js
| |-- index.js
| |-- parser.js
| `-- routes
|-- docker-compose.yml
|-- frontend
| |-- Dockerfile
| |-- index.html
| |-- package.json
| |-- postcss.config.js
| |-- src
| | |-- App.jsx
| | |-- auth.js
| | |-- components
| | |-- index.css
| | `-- main.jsx
| |-- tailwind.config.js
| `-- vite.config.js
`-- README.md
12 directories, 20 files
Read
.env
.env
Read
.env.example
.env.example
Read
Dockerfile
Dockerfile
Read
Dockerfile
Dockerfile
Bash
IN
head -100 /volume2/docker/finance/payments-logger/backend/package.json && echo "---FRONTEND---" && head -100 /volume2/docker/finance/payments-logger/frontend/package.json
Copy code to clipboard
OUT
{
"name": "payments-logger-backend",
"version": "1.0.0",
"description": "Payment SMS logger backend",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js",
"prisma:generate": "prisma generate",
"prisma:migrate": "prisma migrate deploy",
"prisma:migrate:dev": "prisma migrate dev"
},
"dependencies": {
"@prisma/client": "^5.22.0",
"bcryptjs": "^2.4.3",
"cors": "^2.8.5",
"express": "^4.21.1",
"express-rate-limit": "^7.4.0",
"jose": "^5.9.6",
"morgan": "^1.10.0"
},
"devDependencies": {
"nodemon": "^3.1.7",
"prisma": "^5.22.0"
}
}
---FRONTEND---
{
"name": "payments-logger-frontend",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"lucide-react": "^0.460.0",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/react": "^18.3.12",
"@vitejs/plugin-react": "^4.3.4",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.49",
"tailwindcss": "^3.4.15",
"vite": "^6.0.1"
}
}
Read
payments.js
payments.js
Bash
IN
find /volume2/docker/finance -name "*.md" -type f | xargs grep -l "auth\|Authentik\|OAuth\|OIDC" 2>/dev/null | head -5
Copy code to clipboard
OUT
/volume2/docker/finance/payments-logger/API.md
/volume2/docker/finance/auth/README.md
/volume2/docker/finance/auth/auth/README.md
/volume2/docker/finance/payments-logger/auth/README.md
Read
API.md
API.md
Bash
IN
head -50 /volume2/docker/finance/payments-logger/frontend/src/main.jsx
Copy code to clipboard
OUT
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { AuthProvider } from './components/AuthProvider';
import './index.css';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<AuthProvider>
<App />
</AuthProvider>
</React.StrictMode>
);
Bash
IN
find /volume2/docker/finance/payments-logger/frontend/src -name "*.jsx" -o -name "*.js" | head -20
Copy code to clipboard
OUT
/volume2/docker/finance/payments-logger/frontend/src/App.jsx
/volume2/docker/finance/payments-logger/frontend/src/auth.js
/volume2/docker/finance/payments-logger/frontend/src/main.jsx
/volume2/docker/finance/payments-logger/frontend/src/components/AuthProvider.jsx
/volume2/docker/finance/payments-logger/frontend/src/components/FilterBar.jsx
/volume2/docker/finance/payments-logger/frontend/src/components/PaymentCard.jsx
/volume2/docker/finance/payments-logger/frontend/src/components/PaymentList.jsx
/volume2/docker/finance/payments-logger/frontend/src/components/PaymentTable.jsx
Read
AuthProvider.jsx
AuthProvider.jsx
Read
AuthProvider.jsx
AuthProvider.jsx
Bash
IN
head -50 /volume2/docker/finance/payments-logger/frontend/src/App.jsx
Copy code to clipboard
OUT
import React, { useState, useEffect, useCallback } from 'react';
import { CreditCard, RefreshCw, LogOut } from 'lucide-react';
import FilterBar from './components/FilterBar';
import PaymentTable from './components/PaymentTable';
import { useAuth } from './components/AuthProvider';
const API_BASE = '/api/payments';
export default function App() {
const { logout, getToken } = useAuth();
const [payments, setPayments] = useState([]);
const [total, setTotal] = useState(0);
const [page, setPage] = useState(1);
const [filters, setFilters] = useState({});
const [sortBy, setSortBy] = useState('createdAt');
const [sortDir, setSortDir] = useState('desc');
const [filterOptions, setFilterOptions] = useState({ types: [], recipients: [], tags: [] });
const [loading, setLoading] = useState(false);
const authFetch = useCallback(async (url, options = {}) => {
const token = await getToken();
const headers = { ...(options.headers || {}) };
if (token) headers['Authorization'] = `Bearer ${token}`;
return fetch(url, { ...options, headers });
}, [getToken]);
const fetchPayments = useCallback(async () => {
setLoading(true);
try {
const params = new URLSearchParams();
params.set('page', page);
params.set('limit', 50);
params.set('sortBy', sortBy);
params.set('sortDir', sortDir);
Object.entries(filters).forEach(([key, val]) => {
if (val) params.set(key, val);
});
const res = await authFetch(`${API_BASE}?${params}`);
const data = await res.json();
setPayments(data.payments || []);
setTotal(data.total || 0);
} catch (err) {
console.error('Failed to fetch payments:', err);
} finally {
setLoading(false);
}
}, [page, filters, sortBy, sortDir, authFetch]);
const fetchFilterOptions = useCallback(async () => {
try {
Read
docker-compose.yml
docker-compose.yml
Read
Dockerfile
Dockerfile
Read
.env.example
.env.example
Read
app.py
app.py
Read
app_flask.py
app_flask.py
Read
dskuploader.py
dskuploader.py
Read
client.py
client.py
Read
database.py
database.py
Read
index.html
index.html
Read
base.html
base.html
Read
result.html
result.html
Read
page_property.py
page_property.py
Read
USAGE.md
USAGE.md
Bash
IN
find /volume2/docker/finance/dsk-uploader -type f \( -name "*.py" -o -name "*.json" \) | grep -E "(exceptions|page\.py)" | head -10
Copy code to clipboard
OUT
/volume2/docker/finance/dsk-uploader/notion_connector/exceptions/__init__.py
/volume2/docker/finance/dsk-uploader/notion_connector/exceptions/exceptions.py
/volume2/docker/finance/dsk-uploader/notion_connector/resources/page.py
Read
page.py
page.py
Read
exceptions.py
exceptions.py
Bash
IN
tree -L 3 /volume2/docker/finance/dsk-uploader 2>/dev/null | head -80 || find /volume2/docker/finance/dsk-uploader -type d -not -path '.*/.git/*' | sort
Copy code to clipboard
OUT
/volume2/docker/finance/dsk-uploader
├── app_flask.py
├── app.py
├── docker-compose.yml
├── Dockerfile
├── dskuploader.py
├── notion_connector
│ ├── client.py
│ ├── exceptions
│ │ ├── exceptions.py
│ │ └── __init__.py
│ ├── __init__.py
│ └── resources
│ ├── block_property.py
│ ├── block.py
│ ├── database_property.py
│ ├── database.py
│ ├── filter_builder.py
│ ├── __init__.py
│ ├── page_property.py
│ ├── page.py
│ └── search.py
├── README.md
├── requirements.txt
├── templates
│ ├── base.html
│ ├── index.html
│ └── result.html
└── USAGE.md
5 directories, 24 files
Read
README.md
README.md
Read
API.md
API.md
Thinking
Thinking
Now I have a complete picture of all three. Let me design the plan.
Agent:
Design combined app architecture
IN
Design a detailed implementation plan for a new combined web app that merges two existing applications. Here is full context:
---
## App 1: payments-logger (Node.js)
- **Purpose**: Ingest Bulgarian bank SMS → parse → store in PostgreSQL → review/tag/notify in React UI
- **Stack**: Node.js 20 + Express + Prisma 5 + PostgreSQL 16 + React 18 + Vite + Tailwind CSS
- **Auth**: Custom JWT (bcryptjs + jose), tokens in localStorage
- **Ingest**: POST /api/payments/ingest (public) — SMS text OR structured JSON (Apple Wallet)
- **Schema** (PostgreSQL via Prisma):
- `payments` table: id, raw_message, date, type (POS/ATM/INTERNET/ECOM/P2P/WALLET), card, recipient, amount, balance, status (UNPROCESSED/SENT/SKIPPED), notifyPhone, notifiedAt, created_at, updated_at
- `tags` table: id, name, color — M2M with payments via `_PaymentToTag`
- `users` table: id, username, hashed_password (this will be REMOVED)
- **UI**: Single-page React app — PaymentTable (sortable, filterable, taggable), FilterBar, status actions (send/skip), notification system
- **Parser** (backend/src/parser.js): Regex parser for Bulgarian DSK Bank SMS, extracts date/time (DD/MM/YYYY HH:MM), card mask, transaction type, recipient, amount, balance
## App 2: dsk-uploader (Python/Flask)
- **Purpose**: Upload DSK bank CSV exports → parse/normalize → upload to Notion database
- **Stack**: Python 3.11 + Flask + Pandas + Custom Notion SDK + Bootstrap 5
- **Auth**: None (open)
- **CSV format** (DSK Bank Bulgarian format, columns):
- `Дата` (date, DD.MM.YYYY)
- `Вид на трансакцията` (transaction type, Bulgarian)
- `Основание` (reason/description — contains card number regex: `^\d{6}x{6}\d{4}$`)
- `Дебит BGN` (debit amount, may be empty)
- `Кредит BGN` (credit amount, may be empty)
- `Наредител/Получател` (orderer/recipient name)
- `Номер сметка на наредителя / получателя` (account number)
- **Processing**: merge multiple CSVs, normalize dates, extract card numbers from reason via regex, auto-generate tags (keyword heuristics: ЗАПЛАТА→Salary, NETFLIX→Subscriptions, etc.), filter internal transfers
- **Output**: Notion database pages (this will be REPLACED with local PostgreSQL)
## App 3: auth (Authentik)
- **Mode**: Proxy mode via NPM (forward auth)
- **How it works**: NPM intercepts all requests, calls Authentik outpost's auth endpoint. On success, NPM injects headers into proxied request:
- `X-authentik-username`
- `X-authentik-email`
- `X-authentik-groups`
- **No code integration needed** in the app itself — just trust these headers from NPM
- **Logout**: Redirect user to `/outpost.goauthentik.io/sign_out`
---
## What the New Combined App Must Do
1. **Single PostgreSQL database** for all transactions
2. **SMS Ingest** (public endpoint) — same as payments-logger /ingest, source=INGEST
3. **CSV Upload** (authenticated) — parse DSK CSV files, store transactions with source=UPLOAD into the same DB schema
4. **Unified UI** — show all payments in one table regardless of source
5. **Source indicator** in UI — badge showing "INGEST", "UPLOAD", or "BOTH" (if duplicate detection added)
6. **Source filter** in FilterBar — filter by All/Ingest/Upload
7. **Authentik auth** — remove custom JWT entirely; trust X-authentik-* headers from NPM
8. **All existing payments-logger features**: tagging, send notification, skip, status tracking, filters, sorting, pagination
9. **Remove Notion dependency entirely** — all data stays in local PostgreSQL
---
## Technical Constraints
- Keep Node.js backend (not Python) — extend payments-logger's stack
- CSV parsing: use `csv-parse` npm package (handles encoding, streaming)
- File upload: use `multer` npm middleware
- Auth middleware: read X-authentik-username header, 401 if missing (but /api/payments/ingest stays public)
- Add `source` enum field (INGEST/UPLOAD) to payments schema
- Add `currency` field (EUR for SMS ingest, BGN for CSV uploads) — or just store as-is
- Remove `users` table from schema
---
## Please Design
1. Complete folder structure for the new app (suggest name: "finance-hub" or similar — note this is a placeholder, user will confirm)
2. Prisma schema with new fields (`source`, `currency`)
3. All backend API routes
4. CSV parser design in Node.js (port of the Python logic)
5. Authentik auth middleware
6. Frontend component structure (React) — what's reused from payments-logger, what's new
7. Docker Compose setup
8. Environment variables needed
9. Step-by-step implementation order
10. Verification checklist
Be specific about file paths and code structure. This will be used to write actual implementation code.
Bash
List all files in finance directory
IN
find /volume2/docker/finance -type f | sort | head -100
Copy code to clipboard
OUT
/volume2/docker/finance/auth/auth/db/base/1/112
/volume2/docker/finance/auth/auth/db/base/1/113
/volume2/docker/finance/auth/auth/db/base/1/1247
/volume2/docker/finance/auth/auth/db/base/1/1247_fsm
/volume2/docker/finance/auth/auth/db/base/1/1247_vm
/volume2/docker/finance/auth/auth/db/base/1/1249
/volume2/docker/finance/auth/auth/db/base/1/1249_fsm
/volume2/docker/finance/auth/auth/db/base/1/1249_vm
/volume2/docker/finance/auth/auth/db/base/1/1255
/volume2/docker/finance/auth/auth/db/base/1/1255_fsm
/volume2/docker/finance/auth/auth/db/base/1/1255_vm
/volume2/docker/finance/auth/auth/db/base/1/1259
/volume2/docker/finance/auth/auth/db/base/1/1259_fsm
/volume2/docker/finance/auth/auth/db/base/1/1259_vm
/volume2/docker/finance/auth/auth/db/base/1/13457
/volume2/docker/finance/auth/auth/db/base/1/13457_fsm
/volume2/docker/finance/auth/auth/db/base/1/13457_vm
/volume2/docker/finance/auth/auth/db/base/1/13460
/volume2/docker/finance/auth/auth/db/base/1/13461
/volume2/docker/finance/auth/auth/db/base/1/13462
/volume2/docker/finance/auth/auth/db/base/1/13462_fsm
/volume2/docker/finance/auth/auth/db/base/1/13462_vm
/volume2/docker/finance/auth/auth/db/base/1/13465
/volume2/docker/finance/auth/auth/db/base/1/13466
/volume2/docker/finance/auth/auth/db/base/1/13467
/volume2/docker/finance/auth/auth/db/base/1/13467_fsm
/volume2/docker/finance/auth/auth/db/base/1/13467_vm
/volume2/docker/finance/auth/auth/db/base/1/13470
/volume2/docker/finance/auth/auth/db/base/1/13471
/volume2/docker/finance/auth/auth/db/base/1/13472
/volume2/docker/finance/auth/auth/db/base/1/13472_fsm
/volume2/docker/finance/auth/auth/db/base/1/13472_vm
/volume2/docker/finance/auth/auth/db/base/1/13475
/volume2/docker/finance/auth/auth/db/base/1/13476
/volume2/docker/finance/auth/auth/db/base/1/1417
/volume2/docker/finance/auth/auth/db/base/1/1418
/volume2/docker/finance/auth/auth/db/base/1/174
/volume2/docker/finance/auth/auth/db/base/1/175
/volume2/docker/finance/auth/auth/db/base/1/2187
/volume2/docker/finance/auth/auth/db/base/1/2224
/volume2/docker/finance/auth/auth/db/base/1/2228
/volume2/docker/finance/auth/auth/db/base/1/2328
/volume2/docker/finance/auth/auth/db/base/1/2336
/volume2/docker/finance/auth/auth/db/base/1/2337
/volume2/docker/finance/auth/auth/db/base/1/2579
/volume2/docker/finance/auth/auth/db/base/1/2600
/volume2/docker/finance/auth/auth/db/base/1/2600_fsm
/volume2/docker/finance/auth/auth/db/base/1/2600_vm
/volume2/docker/finance/auth/auth/db/base/1/2601
/volume2/docker/finance/auth/auth/db/base/1/2601_fsm
/volume2/docker/finance/auth/auth/db/base/1/2601_vm
/volume2/docker/finance/auth/auth/db/base/1/2602
/volume2/docker/finance/auth/auth/db/base/1/2602_fsm
/volume2/docker/finance/auth/auth/db/base/1/2602_vm
/volume2/docker/finance/auth/auth/db/base/1/2603
/volume2/docker/finance/auth/auth/db/base/1/2603_fsm
/volume2/docker/finance/auth/auth/db/base/1/2603_vm
/volume2/docker/finance/auth/auth/db/base/1/2604
/volume2/docker/finance/auth/auth/db/base/1/2605
/volume2/docker/finance/auth/auth/db/base/1/2605_fsm
/volume2/docker/finance/auth/auth/db/base/1/2605_vm
/volume2/docker/finance/auth/auth/db/base/1/2606
/volume2/docker/finance/auth/auth/db/base/1/2606_fsm
/volume2/docker/finance/auth/auth/db/base/1/2606_vm
/volume2/docker/finance/auth/auth/db/base/1/2607
/volume2/docker/finance/auth/auth/db/base/1/2607_fsm
/volume2/docker/finance/auth/auth/db/base/1/2607_vm
/volume2/docker/finance/auth/auth/db/base/1/2608
/volume2/docker/finance/auth/auth/db/base/1/2608_fsm
/volume2/docker/finance/auth/auth/db/base/1/2608_vm
/volume2/docker/finance/auth/auth/db/base/1/2609
/volume2/docker/finance/auth/auth/db/base/1/2609_fsm
/volume2/docker/finance/auth/auth/db/base/1/2609_vm
/volume2/docker/finance/auth/auth/db/base/1/2610
/volume2/docker/finance/auth/auth/db/base/1/2610_fsm
/volume2/docker/finance/auth/auth/db/base/1/2610_vm
/volume2/docker/finance/auth/auth/db/base/1/2611
/volume2/docker/finance/auth/auth/db/base/1/2612
/volume2/docker/finance/auth/auth/db/base/1/2612_fsm
/volume2/docker/finance/auth/auth/db/base/1/2612_vm
/volume2/docker/finance/auth/auth/db/base/1/2613
/volume2/docker/finance/auth/auth/db/base/1/2615
/volume2/docker/finance/auth/auth/db/base/1/2615_fsm
/volume2/docker/finance/auth/auth/db/base/1/2615_vm
/volume2/docker/finance/auth/auth/db/base/1/2616
/volume2/docker/finance/auth/auth/db/base/1/2616_fsm
/volume2/docker/finance/auth/auth/db/base/1/2616_vm
/volume2/docker/finance/auth/auth/db/base/1/2617
/volume2/docker/finance/auth/auth/db/base/1/2617_fsm
/volume2/docker/finance/auth/auth/db/base/1/2617_vm
/volume2/docker/finance/auth/auth/db/base/1/2618
/volume2/docker/finance/auth/auth/db/base/1/2618_fsm
/volume2/docker/finance/auth/auth/db/base/1/2618_vm
/volume2/docker/finance/auth/auth/db/base/1/2619
/volume2/docker/finance/auth/auth/db/base/1/2619_fsm
/volume2/docker/finance/auth/auth/db/base/1/2619_vm
/volume2/docker/finance/auth/auth/db/base/1/2620
/volume2/docker/finance/auth/auth/db/base/1/2650
/volume2/docker/finance/auth/auth/db/base/1/2651
/volume2/docker/finance/auth/auth/db/base/1/2652
Bash
List docker directory contents
IN
ls -la /volume2/docker/
Copy code to clipboard
OUT
total 40
drwxrwxrwx 1 root root 1160 May 8 21:05 .
drwxr-xr-x 1 root root 246 Apr 6 19:54 ..
drwxrwxrwx 1 Adm1n admin 20 Jul 28 2025 adguard
drwxrwxrwx 1 Adm1n admin 66 Apr 5 13:14 ai-stack
drwxrwxrwx 1 Adm1n admin 12 Aug 1 2025 app-db
drwxrwxr-x 1 appflowy users 138 Dec 14 18:21 appflowy
drwxrwxrwx 1 Adm1n admin 72 May 6 14:55 audiobookshelf
drwxrwxrwx 1 Adm1n admin 128 Mar 30 19:52 auth
drwxrwxrwx 1 Adm1n admin 102 May 8 21:02 beszel
drwxrwxrwx 1 Adm1n admin 38 Jun 16 2025 bitwarden
drwxrwxrwx 1 Adm1n admin 36 Aug 25 2025 dawarich
drwxrwxrwx 1 Adm1n admin 322 Aug 15 2025 dsk-uploader
-rwxrwxrwx 1 Adm1n admin 10244 Oct 29 2025 .DS_Store
drwxrwxrwx 1 Adm1n admin 62 May 8 21:10 finance
drwxrwxrwx 1 Adm1n admin 92 Aug 19 2025 flask-app
drwxrwxrwx 1 Adm1n admin 308 Oct 7 2025 garmin-connector
drwxrwxrwx 1 Adm1n admin 12 Jul 18 2025 gitea
drwxrwxrwx 1 Adm1n admin 0 Feb 16 19:30 health
drwxrwxrwx 1 Adm1n admin 220 Feb 16 21:09 health-tracker
drwxrwxrwx 1 Adm1n admin 0 Oct 31 2025 homarr
drwxrwxrwx 1 Adm1n admin 146 Mar 7 20:46 hst
drwxrwxrwx 1 Adm1n admin 66 Aug 31 2025 immich
drwxrwx--- 1 Adm1n Media 30 Jun 15 2025 jellyfinht
drwxrwxrwx 1 Adm1n admin 20 Aug 31 2025 kavita
drwxrwxrwx 1 Adm1n admin 0 Oct 12 2025 libreoffice
drwxrwxrwx 1 Adm1n admin 12 Dec 13 21:12 linkwarden
drwxrwxrwx 1 Adm1n admin 274 Apr 9 19:39 location-logger
drwxrwxrwx 1 dnsmasq systemd-journal 432 Aug 27 2025 mariadb
drwxrwxrwx 1 Adm1n admin 122 Apr 26 19:03 meeting-detector
drwxrwxrwx 1 Adm1n admin 0 Aug 15 2025 mindfulmama
drwxrwxrwx 1 Adm1n admin 22 Jul 16 2025 n8n
drwxrwxrwx 1 Adm1n admin 176 Feb 20 17:33 notifier-app
drwxrwxrwx 1 Adm1n admin 52 Jun 15 2025 npm
drwxrwxrwx 1 Adm1n admin 306 Mar 29 17:34 oauth
drwxrwxrwx 1 Adm1n admin 92 Jun 15 2025 obsidian
drwxr-xr-x 1 root root 60 Mar 7 20:56 ollama
drwxr-xr-x 1 911 911 128 Jul 28 2025 openttd
drwxrwxrwx 1 Adm1n admin 234 Mar 7 16:30 openvpn-client
drwxr-xr-x 1 root root 58 May 2 23:15 open-webui
drwxrwxrwx 1 Adm1n admin 134 Dec 31 13:13 orchestrator
drwxrwxrwx 1 Adm1n admin 406 Mar 25 20:39 outfit-app
drwxrwxrwx 1 Adm1n admin 90 Aug 28 2025 owntracks-stack
drwxrwxrwx 1 Adm1n admin 156 Mar 10 20:51 paperlessngx
drwxrwxrwx 1 Adm1n admin 162 May 8 20:36 payments-logger
drwxrwxrwx 1 Adm1n admin 0 Sep 28 2025 personal-log
drwxrwxrwx 1 Adm1n admin 616 Mar 7 20:46 personal-log-system
drwxrwxrwx 1 Adm1n admin 26 Feb 19 19:41 player
drwxrwxrwx 1 Adm1n admin 202 Feb 23 21:35 portainer
drwxrwxrwx 1 dnsmasq admin 484 Dec 4 19:31 portnotedb
drwxrwxrwx 1 Adm1n admin 140 Apr 4 15:49 reminders-app
drwxrwxrwx 1 Adm1n admin 60 Oct 29 2025 romm
drwxrwxrwx 1 Adm1n admin 108 Feb 23 20:15 second-brain
drwxrwxrwx 1 Adm1n admin 10 Dec 30 17:16 static
drwxrwxrwx 1 Adm1n admin 28 Jun 19 2025 stirling
drwxrwxrwx 1 Adm1n admin 86 Oct 25 2025 syncthing
drwxrwxrwx 1 root root 56 Jun 5 2025 tailscale
drwxrwxrwx 1 Adm1n admin 186 Sep 23 2025 temp-logger
drwxrwxrwx 1 Adm1n admin 122 Jul 19 2025 test-app
drwxrwxrwx 1 Adm1n admin 52 Jun 14 2025 tmp
drwxrwxrwx 1 Adm1n admin 36 Jul 13 2025 torrent-stack
drwxrwxrwx 1 Adm1n admin 48 Dec 19 10:58 tree
drwxrwxrwx 1 Adm1n admin 0 Oct 31 2025 trilium
drwxrwxrwx 1 Adm1n admin 34 Dec 3 21:18 tubearchivist
drwxrwxrwx 1 Adm1n admin 22 Jul 25 2025 twenty
drwxrwxrwx 1 Adm1n admin 0 Nov 2 2025 uptimekuma
drwxrwxrwx 1 Adm1n admin 30 Dec 7 17:30 ytptube
Bash
List all files in payments-logger directory
IN
find /volume2/docker/payments-logger -type f | sort
Copy code to clipboard
OUT
/volume2/docker/payments-logger/API.md
/volume2/docker/payments-logger/backend/Dockerfile
/volume2/docker/payments-logger/backend/.dockerignore
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260508_add_users/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
/volume2/docker/payments-logger/backend/prisma/schema.prisma
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/.claude/settings.local.json
/volume2/docker/payments-logger/docker-compose.yml
/volume2/docker/payments-logger/.env
/volume2/docker/payments-logger/.env.example
/volume2/docker/payments-logger/frontend/Dockerfile
/volume2/docker/payments-logger/frontend/.dockerignore
/volume2/docker/payments-logger/frontend/index.html
/volume2/docker/payments-logger/frontend/package.json
/volume2/docker/payments-logger/frontend/postcss.config.js
/volume2/docker/payments-logger/frontend/src/App.jsx
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx
/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx
/volume2/docker/payments-logger/frontend/src/index.css
/volume2/docker/payments-logger/frontend/src/main.jsx
/volume2/docker/payments-logger/frontend/tailwind.config.js
/volume2/docker/payments-logger/frontend/vite.config.js
/volume2/docker/payments-logger/.gitignore
/volume2/docker/payments-logger/README.md
Bash
List all files in dsk-uploader directory
IN
find /volume2/docker/dsk-uploader -type f | sort
Copy code to clipboard
OUT
/volume2/docker/dsk-uploader/app_flask.py
/volume2/docker/dsk-uploader/app.py
/volume2/docker/dsk-uploader/docker-compose.yml
/volume2/docker/dsk-uploader/Dockerfile
/volume2/docker/dsk-uploader/.dockerignore
/volume2/docker/dsk-uploader/dskuploader.py
/volume2/docker/dsk-uploader/.env
/volume2/docker/dsk-uploader/.env.example
/volume2/docker/dsk-uploader/.git/COMMIT_EDITMSG
/volume2/docker/dsk-uploader/.git/config
/volume2/docker/dsk-uploader/.git/description
/volume2/docker/dsk-uploader/.git/FETCH_HEAD
/volume2/docker/dsk-uploader/.git/HEAD
/volume2/docker/dsk-uploader/.git/hooks/applypatch-msg.sample
/volume2/docker/dsk-uploader/.git/hooks/commit-msg.sample
/volume2/docker/dsk-uploader/.git/hooks/fsmonitor-watchman.sample
/volume2/docker/dsk-uploader/.git/hooks/post-update.sample
/volume2/docker/dsk-uploader/.git/hooks/pre-applypatch.sample
/volume2/docker/dsk-uploader/.git/hooks/pre-commit.sample
/volume2/docker/dsk-uploader/.git/hooks/pre-merge-commit.sample
/volume2/docker/dsk-uploader/.git/hooks/prepare-commit-msg.sample
/volume2/docker/dsk-uploader/.git/hooks/pre-push.sample
/volume2/docker/dsk-uploader/.git/hooks/pre-rebase.sample
/volume2/docker/dsk-uploader/.git/hooks/pre-receive.sample
/volume2/docker/dsk-uploader/.git/hooks/push-to-checkout.sample
/volume2/docker/dsk-uploader/.git/hooks/update.sample
/volume2/docker/dsk-uploader/.gitignore
/volume2/docker/dsk-uploader/.git/index
/volume2/docker/dsk-uploader/.git/info/exclude
/volume2/docker/dsk-uploader/.git/logs/HEAD
/volume2/docker/dsk-uploader/.git/logs/refs/heads/main
/volume2/docker/dsk-uploader/.git/logs/refs/remotes/origin/HEAD
/volume2/docker/dsk-uploader/.git/logs/refs/remotes/origin/main
/volume2/docker/dsk-uploader/.git/objects/0b/918bed65202bedaa9fa092e539d607be2eea65
/volume2/docker/dsk-uploader/.git/objects/11/b908125d2f0feebf7aca6d24e127f334bce611
/volume2/docker/dsk-uploader/.git/objects/56/a2766ae5422b18e5b1a418fd231ad12fef08e6
/volume2/docker/dsk-uploader/.git/objects/65/386fd3b4ac62094500e21c23845d05b9d18a4f
/volume2/docker/dsk-uploader/.git/objects/7b/2d7b18213f9516ec4544f309772ee4808146bb
/volume2/docker/dsk-uploader/.git/objects/7c/3f071fef98751a68b7d93779f76cf5d5aa8ebf
/volume2/docker/dsk-uploader/.git/objects/85/b5483672f68c327c39ea8c29e94ae8b22b7bbf
/volume2/docker/dsk-uploader/.git/objects/8e/a1cbf78eae8a86c5990d0582db1847c0226b56
/volume2/docker/dsk-uploader/.git/objects/ed/8e93af8cc77c7a85f87a9f37573c51b839e571
/volume2/docker/dsk-uploader/.git/objects/ee/3d5f92e57deec809abda371386e371f32de9bb
/volume2/docker/dsk-uploader/.git/objects/f3/98248da8f4911d463d9a33155fcf58a65092cc
/volume2/docker/dsk-uploader/.git/objects/pack/pack-ed5aca57f7f3b56e67172d9fb90e685087770006.idx
/volume2/docker/dsk-uploader/.git/objects/pack/pack-ed5aca57f7f3b56e67172d9fb90e685087770006.pack
/volume2/docker/dsk-uploader/.git/ORIG_HEAD
/volume2/docker/dsk-uploader/.git/packed-refs
/volume2/docker/dsk-uploader/.git/refs/heads/main
/volume2/docker/dsk-uploader/.git/refs/remotes/origin/HEAD
/volume2/docker/dsk-uploader/.git/refs/remotes/origin/main
/volume2/docker/dsk-uploader/notion_connector/client.py
/volume2/docker/dsk-uploader/notion_connector/exceptions/exceptions.py
/volume2/docker/dsk-uploader/notion_connector/exceptions/__init__.py
/volume2/docker/dsk-uploader/notion_connector/__init__.py
/volume2/docker/dsk-uploader/notion_connector/resources/block_property.py
/volume2/docker/dsk-uploader/notion_connector/resources/block.py
/volume2/docker/dsk-uploader/notion_connector/resources/database_property.py
/volume2/docker/dsk-uploader/notion_connector/resources/database.py
/volume2/docker/dsk-uploader/notion_connector/resources/filter_builder.py
/volume2/docker/dsk-uploader/notion_connector/resources/__init__.py
/volume2/docker/dsk-uploader/notion_connector/resources/page_property.py
/volume2/docker/dsk-uploader/notion_connector/resources/page.py
/volume2/docker/dsk-uploader/notion_connector/resources/search.py
/volume2/docker/dsk-uploader/README.md
/volume2/docker/dsk-uploader/requirements.txt
/volume2/docker/dsk-uploader/templates/base.html
/volume2/docker/dsk-uploader/templates/index.html
/volume2/docker/dsk-uploader/templates/result.html
/volume2/docker/dsk-uploader/USAGE.md
Read
schema.prisma
schema.prisma
Read
parser.js
parser.js
Read
index.js
index.js
Read
auth.js
auth.js
Read
payments.js
payments.js
Read
package.json
package.json
Read
docker-compose.yml
docker-compose.yml
Read
.env.example
.env.example
Read
App.jsx
App.jsx
Read
FilterBar.jsx
FilterBar.jsx
Read
PaymentTable.jsx
PaymentTable.jsx
Read
AuthProvider.jsx
AuthProvider.jsx
Read
auth.js
auth.js
Read
app.py
app.py
Read
dskuploader.py
dskuploader.py
Read
app_flask.py
app_flask.py
Read
package.json
package.json
Read
vite.config.js
vite.config.js
Read
Dockerfile
Dockerfile
Read
Dockerfile
Dockerfile
Read
migration.sql
migration.sql
Read
migration.sql
migration.sql
Read
migration.sql
migration.sql
Read
migration.sql
migration.sql
Read
API.md
API.md
Read
docker-compose.yml
docker-compose.yml
Read
PaymentCard.jsx
PaymentCard.jsx
Read
PaymentList.jsx
PaymentList.jsx
Read
tailwind.config.js
tailwind.config.js
Read
main.jsx
main.jsx...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Explorer (⇧⌘E)","depth":19,"bounds":{"left":0.0,"top":0.047885075,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":true},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.057462092,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Search (⇧⌘F)","depth":19,"bounds":{"left":0.0,"top":0.08619314,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.09577015,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Source Control (⌃⇧G)","depth":19,"bounds":{"left":0.0,"top":0.1245012,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.13407822,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Run and Debug (⇧⌘D)","depth":19,"bounds":{"left":0.0,"top":0.16280925,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.17238627,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Remote Explorer","depth":19,"bounds":{"left":0.0,"top":0.20111732,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.21069433,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Extensions (⇧⌘X) - 2 require update","depth":19,"bounds":{"left":0.0,"top":0.23942538,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.2490024,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":22,"bounds":{"left":0.009640957,"top":0.2601756,"width":0.0019946808,"height":0.008778931},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Claude Code - 1 session waiting for input","depth":19,"bounds":{"left":0.0,"top":0.27773345,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":22,"bounds":{"left":0.009640957,"top":0.29848364,"width":0.0016622341,"height":0.008778931},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Containers","depth":19,"bounds":{"left":0.0,"top":0.3160415,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"EXPLORER","depth":17,"bounds":{"left":0.022606382,"top":0.047885075,"width":0.018949468,"height":0.02793296},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"EXPLORER","depth":18,"bounds":{"left":0.022606382,"top":0.056664005,"width":0.018949468,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.022606382,"top":0.056664005,"width":0.0023271276,"height":0.0103751}},{"char_start":1,"char_count":7,"bounds":{"left":0.024933511,"top":0.056664005,"width":0.01662234,"height":0.0103751}}],"role_description":"text"},{"role":"AXButton","text":"Explorer Section: finance [SSH: nas]","depth":21,"bounds":{"left":0.015957447,"top":0.07581804,"width":0.09940159,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.01662234,"top":0.07821229,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"Explorer Section: finance [SSH: nas]","depth":22,"bounds":{"left":0.022606382,"top":0.07581804,"width":0.039228722,"height":0.017557861},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"FINANCE [SSH: NAS]","depth":23,"bounds":{"left":0.022606382,"top":0.079010375,"width":0.039228722,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.022606382,"top":0.07980846,"width":0.0023271276,"height":0.0103751}},{"char_start":1,"char_count":17,"bounds":{"left":0.024933511,"top":0.07980846,"width":0.036901597,"height":0.0103751}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.09577015,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"auth","depth":27,"bounds":{"left":0.025930852,"top":0.09577015,"width":0.008976064,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.096568234,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":3,"bounds":{"left":0.02825798,"top":0.096568234,"width":0.0066489363,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.11332801,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"dsk-uploader","depth":27,"bounds":{"left":0.025930852,"top":0.11332801,"width":0.026928192,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.11412609,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":11,"bounds":{"left":0.028590426,"top":0.11412609,"width":0.024268618,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":26,"bounds":{"left":0.019614361,"top":0.13088587,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"payments-logger","depth":27,"bounds":{"left":0.025930852,"top":0.13088587,"width":0.034574468,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.13168396,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":14,"bounds":{"left":0.028590426,"top":0.13168396,"width":0.031914894,"height":0.011971269}}],"role_description":"text"},{"role":"AXButton","text":"Outline Section","depth":21,"bounds":{"left":0.015957447,"top":0.9473264,"width":0.09940159,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.01662234,"top":0.9497207,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"OUTLINE","depth":22,"bounds":{"left":0.022606382,"top":0.9473264,"width":0.01662234,"height":0.017557861},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"OUTLINE","depth":23,"bounds":{"left":0.022606382,"top":0.95131683,"width":0.01662234,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.022606382,"top":0.95131683,"width":0.0029920214,"height":0.0103751}},{"char_start":1,"char_count":6,"bounds":{"left":0.025598405,"top":0.95131683,"width":0.013630319,"height":0.0103751}}],"role_description":"text"},{"role":"AXButton","text":"Timeline Section","depth":21,"bounds":{"left":0.015957447,"top":0.9648843,"width":0.09940159,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.01662234,"top":0.96727854,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"TIMELINE","depth":22,"bounds":{"left":0.022606382,"top":0.9648843,"width":0.01761968,"height":0.017557861},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"TIMELINE","depth":23,"bounds":{"left":0.022606382,"top":0.9688747,"width":0.01761968,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.022606382,"top":0.9688747,"width":0.0026595744,"height":0.0103751}},{"char_start":1,"char_count":7,"bounds":{"left":0.025265958,"top":0.9688747,"width":0.015292553,"height":0.0103751}}],"role_description":"text"},{"role":"AXRadioButton","text":"payments.js, preview, Editor Group 1","depth":28,"bounds":{"left":0.11569149,"top":0.047885075,"width":0.04488032,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXStaticText","text":"","depth":29,"bounds":{"left":0.15525267,"top":0.07821229,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":29,"bounds":{"left":0.17785904,"top":0.07821229,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":29,"bounds":{"left":0.18949468,"top":0.07821229,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":29,"bounds":{"left":0.20744681,"top":0.07821229,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":29,"bounds":{"left":0.2443484,"top":0.07821229,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"…","depth":28,"bounds":{"left":0.24966756,"top":0.07821229,"width":0.003656915,"height":0.011971269},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"payments.js, preview, Editor Group 1","depth":28,"on_screen":false,"role_description":"editor","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"Design new payment-logge…, Editor Group 2","depth":28,"bounds":{"left":0.41023937,"top":0.047885075,"width":0.07912234,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXRadioButton","text":"finance-hub — Implementation Plan, Editor Group 3","depth":28,"bounds":{"left":0.70478725,"top":0.047885075,"width":0.09208777,"height":0.02793296},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":false},{"role":"AXButton","text":"remote SSH: nas","depth":16,"bounds":{"left":0.0006648936,"top":0.98244214,"width":0.028590426,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.0033244682,"top":0.9848364,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SSH: nas","depth":17,"bounds":{"left":0.008643617,"top":0.9856345,"width":0.017952127,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.008643617,"top":0.9856345,"width":0.0013297872,"height":0.011173184}},{"char_start":1,"char_count":7,"bounds":{"left":0.009973404,"top":0.9856345,"width":0.01462766,"height":0.011173184}}],"role_description":"text"},{"role":"AXButton","text":"No Problems","depth":16,"bounds":{"left":0.03025266,"top":0.98244214,"width":0.022606382,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.031914894,"top":0.9848364,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"bounds":{"left":0.03723404,"top":0.9856345,"width":0.004986702,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.041888297,"top":0.9848364,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"bounds":{"left":0.04720745,"top":0.9856345,"width":0.0039893617,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"No Ports Forwarded","depth":16,"bounds":{"left":0.054521278,"top":0.98244214,"width":0.012632979,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.05618351,"top":0.9848364,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"0","depth":17,"bounds":{"left":0.061502658,"top":0.9856345,"width":0.0039893617,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Notifications","depth":16,"bounds":{"left":0.9886968,"top":0.98244214,"width":0.010638298,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sign In","depth":16,"bounds":{"left":0.9650931,"top":0.98244214,"width":0.022606382,"height":0.01755786},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":17,"bounds":{"left":0.96675533,"top":0.9848364,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sign In","depth":17,"bounds":{"left":0.97207445,"top":0.9856345,"width":0.013962766,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.97207445,"top":0.9856345,"width":0.0013297872,"height":0.011173184}},{"char_start":1,"char_count":6,"bounds":{"left":0.9734042,"top":0.9856345,"width":0.010638298,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"collapsed","depth":12,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Design new payment-logger and dsk-uploader hybrid app","depth":19,"bounds":{"left":0.41256648,"top":0.08060654,"width":0.099734046,"height":0.022346368},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Session history","depth":19,"bounds":{"left":0.6831782,"top":0.08060654,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"Session history","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New session","depth":19,"bounds":{"left":0.6938165,"top":0.08060654,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"New session","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Message actions","depth":24,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"payments.js","depth":23,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"payments.js","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ets create a new app that should be combination of payment-logger and dsk-uploader. It should have authorization via authentik (auth folder). All three folders (payment-logger, dsk-uploader and auth) are just refference these will be removed later. Auth project is separated it lives on its own. First reveiw them and see how these should be combined. It will be whole new app (also the folder name). Think very carefully of whatr these two apps do and how cold they be combined. THerer should be common db and uploader should store data the same way the /ingest does. It should be properly marked in UI if it is upload or ingest or both. FIrst think of tech stack and plan carefully.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":23,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"I'll explore all three reference projects in parallel to understand their structure before planning.","depth":23,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore payment-logger app structure and functionality","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the /volume2/docker/finance/payments-logger directory thoroughly. I need to understand:\n1. Tech stack (frontend framework, backend framework, database)\n2. What the app does - its core purpose and features\n3. Database schema - all tables, relationships\n4. API routes - all endpoints, their purpose and request/response shapes\n5. How data flows (ingest, storage, retrieval)\n6. Any auth/middleware setup\n7. Docker/deployment setup\n8. Key files and their roles\n\nReport with: directory structure, tech stack summary, database schema details, all API endpoints listed, UI features, and how data is ingested. Be thorough on the /ingest endpoint specifically.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore dsk-uploader app structure and functionality","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the /volume2/docker/finance/dsk-uploader directory thoroughly. I need to understand:\n1. Tech stack (frontend framework, backend framework, database)\n2. What the app does - its core purpose and features\n3. Database schema - all tables, relationships\n4. API routes - all endpoints, their purpose and request/response shapes\n5. How file uploads work - what files, what format, how parsed\n6. Any auth/middleware setup\n7. Docker/deployment setup\n8. Key files and their roles\n\nReport with: directory structure, tech stack summary, database schema details, all API endpoints listed, UI features, how file upload parsing works, and what data is extracted from uploads. Be very thorough about the data model and what fields are stored.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore auth folder and authentik integration","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the /volume2/docker/finance/auth directory thoroughly. I need to understand:\n1. What auth system is being used (Authentik)\n2. How authentication/authorization is implemented - OAuth2, OIDC, session tokens, JWT?\n3. Middleware - how is auth enforced on routes?\n4. Any frontend auth flow - login redirect, token handling, protected routes\n5. Environment variables related to auth\n6. Docker/deployment setup for the auth service itself\n7. Any example of how other apps integrate with this auth\n\nReport with: directory structure, auth flow description, middleware code, environment variable names, and integration patterns. This is a reference for building auth into a new combined app.","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Message actions","depth":25,"bounds":{"left":0.69514626,"top":0.11173184,"width":0.0066489363,"height":0.015961692},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"payments.js","depth":24,"bounds":{"left":0.4195479,"top":0.123703115,"width":0.030917553,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"payments.js","depth":26,"bounds":{"left":0.42652926,"top":0.12769353,"width":0.021609042,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.42652926,"top":0.12769353,"width":0.0023271276,"height":0.011173184}},{"char_start":1,"char_count":10,"bounds":{"left":0.42885637,"top":0.12769353,"width":0.019281914,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"continue","depth":26,"bounds":{"left":0.4195479,"top":0.14924182,"width":0.01761968,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.4195479,"top":0.14924182,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":7,"bounds":{"left":0.421875,"top":0.14924182,"width":0.015292553,"height":0.011971269}}],"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":24,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Launching parallel exploration of all three reference projects.","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore payment-logger app structure","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the /volume2/docker/finance/payments-logger directory thoroughly. I need to understand:\n1. Full directory structure (tree)\n2. Tech stack (frontend framework, backend framework, database, etc.)\n3. What the app does - its core functionality\n4. How data is ingested (look at /ingest route especially)\n5. Database schema (what tables/collections exist)\n6. API routes and their purposes\n7. Frontend pages and components\n8. Docker setup\n9. Any auth/session handling\n\nPlease read key files: package.json files, main entry points, route files, database schema files, docker-compose.yml, and any frontend components. Be thorough - I need a complete picture to plan a new combined app.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/finance/payments-logger -type f -name \"*.json\" -o -name \"*.js\" -o -name \"*.jsx\" -o -name \"*.ts\" -o -name \"*.tsx\" -o -name \"*.py\" -o -name \"*.sql\" -o -name \"Dockerfile*\" -o -name \"docker-compose*\" -o -name \".env*\" 2>/dev/null | head -50","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/finance/payments-logger/.env\n/volume2/docker/finance/payments-logger/.env.example\n/volume2/docker/finance/payments-logger/docker-compose.yml\n/volume2/docker/finance/payments-logger/.claude/settings.local.json\n/volume2/docker/finance/payments-logger/backend/Dockerfile\n/volume2/docker/finance/payments-logger/backend/package.json\n/volume2/docker/finance/payments-logger/frontend/Dockerfile\n/volume2/docker/finance/payments-logger/frontend/package.json\n/volume2/docker/finance/payments-logger/frontend/postcss.config.js\n/volume2/docker/finance/payments-logger/frontend/tailwind.config.js\n/volume2/docker/finance/payments-logger/frontend/vite.config.js\n/volume2/docker/finance/payments-logger/auth/.env\n/volume2/docker/finance/payments-logger/auth/.env.example\n/volume2/docker/finance/payments-logger/backend/src/auth.js\n/volume2/docker/finance/payments-logger/backend/src/index.js\n/volume2/docker/finance/payments-logger/backend/src/parser.js\n/volume2/docker/finance/payments-logger/frontend/src/App.jsx\n/volume2/docker/finance/payments-logger/frontend/src/auth.js\n/volume2/docker/finance/payments-logger/frontend/src/main.jsx\n/volume2/docker/finance/payments-logger/backend/src/routes/payments.js\n/volume2/docker/finance/payments-logger/frontend/src/components/AuthProvider.jsx\n/volume2/docker/finance/payments-logger/frontend/src/components/FilterBar.jsx\n/volume2/docker/finance/payments-logger/frontend/src/components/PaymentCard.jsx\n/volume2/docker/finance/payments-logger/frontend/src/components/PaymentList.jsx\n/volume2/docker/finance/payments-logger/frontend/src/components/PaymentTable.jsx\n/volume2/docker/finance/payments-logger/backend/prisma/migrations/20260210_init/migration.sql\n/volume2/docker/finance/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql\n/volume2/docker/finance/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql\n/volume2/docker/finance/payments-logger/backend/prisma/migrations/20260508_add_users/migration.sql","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore dsk-uploader app structure","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the /volume2/docker/finance/dsk-uploader directory thoroughly. I need to understand:\n1. Full directory structure (tree)\n2. Tech stack (frontend framework, backend framework, database, etc.)\n3. What the app does - its core functionality\n4. How file uploads work (what format, what processing happens)\n5. Database schema (what tables/collections exist)\n6. API routes and their purposes\n7. Frontend pages and components\n8. Docker setup\n9. Any auth/session handling\n\nPlease read key files: package.json files, main entry points, route files, database schema files, docker-compose.yml, and any frontend components. Be thorough - I need a complete picture to plan a new combined app.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/finance/dsk-uploader -type f -name \"*.json\" -o -type f -name \"*.yml\" -o -type f -name \"*.yaml\" | head -30","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/finance/dsk-uploader/docker-compose.yml","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"cd /volume2/docker/finance/payments-logger && find . -type f \\( -name \"*.json\" -o -name \"*.js\" -o -name \"*.jsx\" -o -name \"*.ts\" -o -name \"*.tsx\" -o -name \"*.sql\" -o -name \"*.yml\" -o -name \"*.yaml\" -o -name \"Dockerfile*\" -o -name \".env*\" \\) | grep -v node_modules | sort","depth":27,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"./auth/.env\n./auth/.env.example\n./backend/Dockerfile\n./backend/package.json\n./backend/prisma/migrations/20260210_init/migration.sql\n./backend/prisma/migrations/20260210_simplify/migration.sql\n./backend/prisma/migrations/20260222_add_card/migration.sql\n./backend/prisma/migrations/20260508_add_users/migration.sql\n./backend/src/auth.js\n./backend/src/index.js\n./backend/src/parser.js\n./backend/src/routes/payments.js\n./.claude/settings.local.json\n./docker-compose.yml\n./.env\n./.env.example\n./frontend/Dockerfile\n./frontend/package.json\n./frontend/postcss.config.js\n./frontend/src/App.jsx\n./frontend/src/auth.js\n./frontend/src/components/AuthProvider.jsx\n./frontend/src/components/FilterBar.jsx\n./frontend/src/components/PaymentCard.jsx\n./frontend/src/components/PaymentList.jsx\n./frontend/src/components/PaymentTable.jsx\n./frontend/src/main.jsx\n./frontend/tailwind.config.js\n./frontend/vite.config.js","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore auth project structure","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Explore the /volume2/docker/finance/auth directory thoroughly. I need to understand:\n1. Full directory structure (tree)\n2. What authentication system is used (authentik integration details)\n3. How OAuth/OIDC flow works\n4. Any middleware or helper functions for protecting routes\n5. Session management approach\n6. How frontend handles auth state\n7. Any example of how other apps integrate with this auth system\n8. Docker setup and environment variables\n\nPlease read all files carefully - this auth system will be integrated into a new combined app. I need to understand exactly how to use it.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"cd /volume2/docker/finance/dsk-uploader && find . -type f | head -100","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"./.gitignore\n./README.md\n./USAGE.md\n./app.py\n./app_flask.py\n./dskuploader.py\n./requirements.txt\n./.env\n./.env.example\n./Dockerfile\n./docker-compose.yml\n./.dockerignore\n./.git/description\n./.git/packed-refs\n./.git/HEAD\n./.git/FETCH_HEAD\n./.git/index\n./.git/COMMIT_EDITMSG\n./.git/ORIG_HEAD\n./notion_connector/__init__.py\n./notion_connector/client.py\n./templates/base.html\n./templates/index.html\n./templates/result.html\n./notion_connector/resources/__init__.py\n./notion_connector/resources/block.py\n./notion_connector/resources/block_property.py\n./notion_connector/resources/database.py\n./notion_connector/resources/database_property.py\n./notion_connector/resources/filter_builder.py\n./notion_connector/resources/page.py\n./notion_connector/resources/page_property.py\n./notion_connector/resources/search.py\n./.git/info/exclude\n./.git/hooks/post-update.sample\n./.git/hooks/pre-applypatch.sample\n./.git/hooks/pre-commit.sample\n./.git/hooks/applypatch-msg.sample\n./.git/hooks/pre-rebase.sample\n./.git/hooks/pre-merge-commit.sample\n./.git/hooks/update.sample\n./.git/hooks/pre-push.sample\n./.git/hooks/push-to-checkout.sample\n./.git/hooks/prepare-commit-msg.sample\n./.git/hooks/commit-msg.sample\n./.git/hooks/pre-receive.sample\n./.git/hooks/fsmonitor-watchman.sample\n./.git/logs/HEAD\n./notion_connector/exceptions/__init__.py\n./notion_connector/exceptions/exceptions.py\n./.git/config\n./.git/refs/heads/main\n./.git/refs/remotes/origin/HEAD\n./.git/refs/remotes/origin/main\n./.git/objects/7c/3f071fef98751a68b7d93779f76cf5d5aa8ebf\n./.git/objects/ed/8e93af8cc77c7a85f87a9f37573c51b839e571\n./.git/objects/7b/2d7b18213f9516ec4544f309772ee4808146bb\n./.git/objects/65/386fd3b4ac62094500e21c23845d05b9d18a4f\n./.git/objects/ee/3d5f92e57deec809abda371386e371f32de9bb\n./.git/logs/refs/heads/main\n./.git/objects/pack/pack-ed5aca57f7f3b56e67172d9fb90e685087770006.pack\n./.git/objects/pack/pack-ed5aca57f7f3b56e67172d9fb90e685087770006.idx\n./.git/objects/85/b5483672f68c327c39ea8c29e94ae8b22b7bbf\n./.git/objects/f3/98248da8f4911d463d9a33155fcf58a65092cc\n./.git/objects/0b/918bed65202bedaa9fa092e539d607be2eea65\n./.git/objects/8e/a1cbf78eae8a86c5990d0582db1847c0226b56\n./.git/objects/11/b908125d2f0feebf7aca6d24e127f334bce611\n./.git/objects/56/a2766ae5422b18e5b1a418fd231ad12fef08e6\n./.git/logs/refs/remotes/origin/HEAD\n./.git/logs/refs/remotes/origin/main","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/finance/auth -type f -name \"*.py\" -o -name \"*.js\" -o -name \"*.ts\" -o -name \"*.tsx\" -o -name \"*.json\" -o -name \"*.yaml\" -o -name \"*.yml\" -o -name \"*.env*\" -o -name \"Dockerfile*\" | head -100","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/finance/auth/.env\n/volume2/docker/finance/auth/.env.example\n/volume2/docker/finance/auth/docker-compose.yml\n/volume2/docker/finance/auth/auth/.env\n/volume2/docker/finance/auth/auth/.env.example\n/volume2/docker/finance/auth/auth/docker-compose.yml","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"dsk-uploader","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"dsk-uploader","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"package.json","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"package.json","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"package.json","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"package.json","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env.example","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env.example","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ls -la /volume2/docker/finance/auth/ && echo \"---\" && find /volume2/docker/finance/auth -type d | sort","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"total 20\ndrwxrwxrwx 1 Adm1n admin 108 May 8 21:08 .\ndrwxrwxrwx 1 Adm1n admin 62 May 8 21:10 ..\ndrwxrwxrwx 1 Adm1n admin 128 May 8 21:08 auth\ndrwxrwxrwx 1 Adm1n admin 0 May 8 21:06 certs\ndrwxrwxrwx 1 Adm1n admin 0 May 8 21:06 db\n-rwxrwxrwx 1 Adm1n admin 3328 May 8 21:07 docker-compose.yml\n-rwxrwxrwx 1 Adm1n admin 949 May 8 21:06 .env\n-rwxrwxrwx 1 Adm1n admin 2258 May 8 21:06 .env.example\n-rwxrwxrwx 1 Adm1n admin 5501 May 8 21:07 README.md\n---\n/volume2/docker/finance/auth\n/volume2/docker/finance/auth/auth\n/volume2/docker/finance/auth/auth/certs\n/volume2/docker/finance/auth/auth/db\n/volume2/docker/finance/auth/auth/db/base\n/volume2/docker/finance/auth/auth/db/base/1\n/volume2/docker/finance/auth/auth/db/base/16384\n/volume2/docker/finance/auth/auth/db/base/4\n/volume2/docker/finance/auth/auth/db/base/5\n/volume2/docker/finance/auth/auth/db/global\n/volume2/docker/finance/auth/auth/db/pg_commit_ts\n/volume2/docker/finance/auth/auth/db/pg_dynshmem\n/volume2/docker/finance/auth/auth/db/pg_logical\n/volume2/docker/finance/auth/auth/db/pg_logical/mappings\n/volume2/docker/finance/auth/auth/db/pg_logical/snapshots\n/volume2/docker/finance/auth/auth/db/pg_multixact\n/volume2/docker/finance/auth/auth/db/pg_multixact/members\n/volume2/docker/finance/auth/auth/db/pg_multixact/offsets\n/volume2/docker/finance/auth/auth/db/pg_notify\n/volume2/docker/finance/auth/auth/db/pg_replslot\n/volume2/docker/finance/auth/auth/db/pg_serial\n/volume2/docker/finance/auth/auth/db/pg_snapshots\n/volume2/docker/finance/auth/auth/db/pg_stat\n/volume2/docker/finance/auth/auth/db/pg_stat_tmp\n/volume2/docker/finance/auth/auth/db/pg_subtrans\n/volume2/docker/finance/auth/auth/db/pg_tblspc\n/volume2/docker/finance/auth/auth/db/pg_twophase\n/volume2/docker/finance/auth/auth/db/pg_wal\n/volume2/docker/finance/auth/auth/db/pg_wal/archive_status\n/volume2/docker/finance/auth/auth/db/pg_xact\n/volume2/docker/finance/auth/auth/media\n/volume2/docker/finance/auth/auth/templates\n/volume2/docker/finance/auth/certs\n/volume2/docker/finance/auth/db","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"README.md","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"README.md","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"requirements.txt","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"requirements.txt","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.js","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.js","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"payments.js","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"payments.js","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"README.md","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"README.md","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env.example","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env.example","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"parser.js","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"parser.js","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/finance/auth/auth -type f | grep -v \"^/volume2/docker/finance/auth/auth/db\" | grep -v \"^/volume2/docker/finance/auth/auth/certs\" | grep -v \"^/volume2/docker/finance/auth/auth/media\" | sort","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/finance/auth/auth/docker-compose.yml\n/volume2/docker/finance/auth/auth/.env\n/volume2/docker/finance/auth/auth/.env.example\n/volume2/docker/finance/auth/auth/README.md","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"migration.sql","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"migration.sql","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"migration.sql","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"migration.sql","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"README.md","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"README.md","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env.example","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env.example","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"App.jsx","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"App.jsx","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"main.jsx","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"main.jsx","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/finance -name \"*.py\" -o -name \"*.js\" -o -name \"*.ts\" -o -name \"*.tsx\" 2>/dev/null | head -50","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/finance/dsk-uploader/app.py\n/volume2/docker/finance/dsk-uploader/app_flask.py\n/volume2/docker/finance/dsk-uploader/dskuploader.py\n/volume2/docker/finance/payments-logger/frontend/postcss.config.js\n/volume2/docker/finance/payments-logger/frontend/tailwind.config.js\n/volume2/docker/finance/payments-logger/frontend/vite.config.js\n/volume2/docker/finance/dsk-uploader/notion_connector/__init__.py\n/volume2/docker/finance/dsk-uploader/notion_connector/client.py\n/volume2/docker/finance/payments-logger/backend/src/auth.js\n/volume2/docker/finance/payments-logger/backend/src/index.js\n/volume2/docker/finance/payments-logger/backend/src/parser.js\n/volume2/docker/finance/payments-logger/frontend/src/auth.js\n/volume2/docker/finance/dsk-uploader/notion_connector/resources/__init__.py\n/volume2/docker/finance/dsk-uploader/notion_connector/resources/block.py\n/volume2/docker/finance/dsk-uploader/notion_connector/resources/block_property.py\n/volume2/docker/finance/dsk-uploader/notion_connector/resources/database.py\n/volume2/docker/finance/dsk-uploader/notion_connector/resources/database_property.py\n/volume2/docker/finance/dsk-uploader/notion_connector/resources/filter_builder.py\n/volume2/docker/finance/dsk-uploader/notion_connector/resources/page.py\n/volume2/docker/finance/dsk-uploader/notion_connector/resources/page_property.py\n/volume2/docker/finance/dsk-uploader/notion_connector/resources/search.py\n/volume2/docker/finance/payments-logger/backend/src/routes/payments.js\n/volume2/docker/finance/dsk-uploader/notion_connector/exceptions/__init__.py\n/volume2/docker/finance/dsk-uploader/notion_connector/exceptions/exceptions.py","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"AuthProvider.jsx","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"AuthProvider.jsx","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"PaymentTable.jsx","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"PaymentTable.jsx","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"FilterBar.jsx","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"FilterBar.jsx","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.js","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.js","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Dockerfile","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Dockerfile","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"migration.sql","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"migration.sql","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/finance/payments-logger -name \"docker-compose.yml\" -o -name \".env*\" -o -name \"package.json\" | head -20","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/finance/payments-logger/.env\n/volume2/docker/finance/payments-logger/.env.example\n/volume2/docker/finance/payments-logger/docker-compose.yml\n/volume2/docker/finance/payments-logger/backend/package.json\n/volume2/docker/finance/payments-logger/frontend/package.json\n/volume2/docker/finance/payments-logger/auth/.env\n/volume2/docker/finance/payments-logger/auth/.env.example","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/finance/payments-logger -name \"schema.prisma\" -type f","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/finance/payments-logger/backend/prisma/schema.prisma","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env.example","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env.example","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"schema.prisma","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"schema.prisma","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ls -la /volume2/docker/finance/payments-logger/auth/ && echo \"---\" && find /volume2/docker/finance/payments-logger -name \"Dockerfile*\" | head -10","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"total 16\ndrwxrwxrwx 1 Adm1n admin 64 May 8 21:07 .\ndrwxrwxrwx 1 Adm1n admin 170 May 8 21:07 ..\ndrwxrwxrwx 1 Adm1n admin 0 May 8 21:07 certs\ndrwxrwxrwx 1 Adm1n admin 0 May 8 21:07 db\n-rwxrwxrwx 1 Adm1n admin 949 May 8 21:07 .env\n-rwxrwxrwx 1 Adm1n admin 2258 May 8 21:07 .env.example\n-rwxrwxrwx 1 Adm1n admin 5501 May 8 21:07 README.md\n---\n/volume2/docker/finance/payments-logger/backend/Dockerfile\n/volume2/docker/finance/payments-logger/frontend/Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"cd /volume2/docker/finance/payments-logger && tree -L 3 -I 'node_modules|.next|dist|build' --charset ascii 2>/dev/null || find . -not -path '*/node_modules/*' -not -path '*/.git/*' -not -path '*/dist/*' -type f | head -60","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":".\n|-- API.md\n|-- auth\n| |-- certs\n| |-- db\n| `-- README.md\n|-- backend\n| |-- Dockerfile\n| |-- package.json\n| |-- prisma\n| | |-- migrations\n| | `-- schema.prisma\n| `-- src\n| |-- auth.js\n| |-- index.js\n| |-- parser.js\n| `-- routes\n|-- docker-compose.yml\n|-- frontend\n| |-- Dockerfile\n| |-- index.html\n| |-- package.json\n| |-- postcss.config.js\n| |-- src\n| | |-- App.jsx\n| | |-- auth.js\n| | |-- components\n| | |-- index.css\n| | `-- main.jsx\n| |-- tailwind.config.js\n| `-- vite.config.js\n`-- README.md\n\n12 directories, 20 files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env.example","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env.example","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Dockerfile","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Dockerfile","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"head -100 /volume2/docker/finance/payments-logger/backend/package.json && echo \"---FRONTEND---\" && head -100 /volume2/docker/finance/payments-logger/frontend/package.json","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"{\n \"name\": \"payments-logger-backend\",\n \"version\": \"1.0.0\",\n \"description\": \"Payment SMS logger backend\",\n \"main\": \"src/index.js\",\n \"scripts\": {\n \"start\": \"node src/index.js\",\n \"dev\": \"nodemon src/index.js\",\n \"prisma:generate\": \"prisma generate\",\n \"prisma:migrate\": \"prisma migrate deploy\",\n \"prisma:migrate:dev\": \"prisma migrate dev\"\n },\n \"dependencies\": {\n \"@prisma/client\": \"^5.22.0\",\n \"bcryptjs\": \"^2.4.3\",\n \"cors\": \"^2.8.5\",\n \"express\": \"^4.21.1\",\n \"express-rate-limit\": \"^7.4.0\",\n \"jose\": \"^5.9.6\",\n \"morgan\": \"^1.10.0\"\n },\n \"devDependencies\": {\n \"nodemon\": \"^3.1.7\",\n \"prisma\": \"^5.22.0\"\n }\n}\n---FRONTEND---\n{\n \"name\": \"payments-logger-frontend\",\n \"version\": \"1.0.0\",\n \"type\": \"module\",\n \"scripts\": {\n \"dev\": \"vite\",\n \"build\": \"vite build\",\n \"preview\": \"vite preview\"\n },\n \"dependencies\": {\n \"lucide-react\": \"^0.460.0\",\n \"react\": \"^18.3.1\",\n \"react-dom\": \"^18.3.1\"\n },\n \"devDependencies\": {\n \"@types/react\": \"^18.3.12\",\n \"@vitejs/plugin-react\": \"^4.3.4\",\n \"autoprefixer\": \"^10.4.20\",\n \"postcss\": \"^8.4.49\",\n \"tailwindcss\": \"^3.4.15\",\n \"vite\": \"^6.0.1\"\n }\n}","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"payments.js","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"payments.js","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/finance -name \"*.md\" -type f | xargs grep -l \"auth\\|Authentik\\|OAuth\\|OIDC\" 2>/dev/null | head -5","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/finance/payments-logger/API.md\n/volume2/docker/finance/auth/README.md\n/volume2/docker/finance/auth/auth/README.md\n/volume2/docker/finance/payments-logger/auth/README.md","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"API.md","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"API.md","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"head -50 /volume2/docker/finance/payments-logger/frontend/src/main.jsx","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport App from './App';\nimport { AuthProvider } from './components/AuthProvider';\nimport './index.css';\n\nReactDOM.createRoot(document.getElementById('root')).render(\n <React.StrictMode>\n <AuthProvider>\n <App />\n </AuthProvider>\n </React.StrictMode>\n);","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/finance/payments-logger/frontend/src -name \"*.jsx\" -o -name \"*.js\" | head -20","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/finance/payments-logger/frontend/src/App.jsx\n/volume2/docker/finance/payments-logger/frontend/src/auth.js\n/volume2/docker/finance/payments-logger/frontend/src/main.jsx\n/volume2/docker/finance/payments-logger/frontend/src/components/AuthProvider.jsx\n/volume2/docker/finance/payments-logger/frontend/src/components/FilterBar.jsx\n/volume2/docker/finance/payments-logger/frontend/src/components/PaymentCard.jsx\n/volume2/docker/finance/payments-logger/frontend/src/components/PaymentList.jsx\n/volume2/docker/finance/payments-logger/frontend/src/components/PaymentTable.jsx","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"AuthProvider.jsx","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"AuthProvider.jsx","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"AuthProvider.jsx","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"AuthProvider.jsx","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"head -50 /volume2/docker/finance/payments-logger/frontend/src/App.jsx","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"import React, { useState, useEffect, useCallback } from 'react';\nimport { CreditCard, RefreshCw, LogOut } from 'lucide-react';\nimport FilterBar from './components/FilterBar';\nimport PaymentTable from './components/PaymentTable';\nimport { useAuth } from './components/AuthProvider';\n\nconst API_BASE = '/api/payments';\n\nexport default function App() {\n const { logout, getToken } = useAuth();\n const [payments, setPayments] = useState([]);\n const [total, setTotal] = useState(0);\n const [page, setPage] = useState(1);\n const [filters, setFilters] = useState({});\n const [sortBy, setSortBy] = useState('createdAt');\n const [sortDir, setSortDir] = useState('desc');\n const [filterOptions, setFilterOptions] = useState({ types: [], recipients: [], tags: [] });\n const [loading, setLoading] = useState(false);\n\n const authFetch = useCallback(async (url, options = {}) => {\n const token = await getToken();\n const headers = { ...(options.headers || {}) };\n if (token) headers['Authorization'] = `Bearer ${token}`;\n return fetch(url, { ...options, headers });\n }, [getToken]);\n\n const fetchPayments = useCallback(async () => {\n setLoading(true);\n try {\n const params = new URLSearchParams();\n params.set('page', page);\n params.set('limit', 50);\n params.set('sortBy', sortBy);\n params.set('sortDir', sortDir);\n Object.entries(filters).forEach(([key, val]) => {\n if (val) params.set(key, val);\n });\n const res = await authFetch(`${API_BASE}?${params}`);\n const data = await res.json();\n setPayments(data.payments || []);\n setTotal(data.total || 0);\n } catch (err) {\n console.error('Failed to fetch payments:', err);\n } finally {\n setLoading(false);\n }\n }, [page, filters, sortBy, sortDir, authFetch]);\n\n const fetchFilterOptions = useCallback(async () => {\n try {","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Dockerfile","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env.example","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env.example","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"app.py","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app.py","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"app_flask.py","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app_flask.py","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"dskuploader.py","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"dskuploader.py","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"client.py","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"client.py","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"database.py","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"database.py","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.html","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.html","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"base.html","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"base.html","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"result.html","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"result.html","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"page_property.py","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"page_property.py","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"USAGE.md","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"USAGE.md","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/finance/dsk-uploader -type f \\( -name \"*.py\" -o -name \"*.json\" \\) | grep -E \"(exceptions|page\\.py)\" | head -10","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/finance/dsk-uploader/notion_connector/exceptions/__init__.py\n/volume2/docker/finance/dsk-uploader/notion_connector/exceptions/exceptions.py\n/volume2/docker/finance/dsk-uploader/notion_connector/resources/page.py","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"page.py","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"page.py","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"exceptions.py","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"exceptions.py","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"tree -L 3 /volume2/docker/finance/dsk-uploader 2>/dev/null | head -80 || find /volume2/docker/finance/dsk-uploader -type d -not -path '.*/.git/*' | sort","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/finance/dsk-uploader\n├── app_flask.py\n├── app.py\n├── docker-compose.yml\n├── Dockerfile\n├── dskuploader.py\n├── notion_connector\n│ ├── client.py\n│ ├── exceptions\n│ │ ├── exceptions.py\n│ │ └── __init__.py\n│ ├── __init__.py\n│ └── resources\n│ ├── block_property.py\n│ ├── block.py\n│ ├── database_property.py\n│ ├── database.py\n│ ├── filter_builder.py\n│ ├── __init__.py\n│ ├── page_property.py\n│ ├── page.py\n│ └── search.py\n├── README.md\n├── requirements.txt\n├── templates\n│ ├── base.html\n│ ├── index.html\n│ └── result.html\n└── USAGE.md\n\n5 directories, 24 files","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"README.md","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"README.md","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"API.md","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"API.md","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Thinking","depth":24,"on_screen":false,"role_description":"disclosure triangle","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Thinking","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Now I have a complete picture of all three. Let me design the plan.","depth":24,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Agent:","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Design combined app architecture","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Design a detailed implementation plan for a new combined web app that merges two existing applications. Here is full context:\n\n---\n\n## App 1: payments-logger (Node.js)\n- **Purpose**: Ingest Bulgarian bank SMS → parse → store in PostgreSQL → review/tag/notify in React UI\n- **Stack**: Node.js 20 + Express + Prisma 5 + PostgreSQL 16 + React 18 + Vite + Tailwind CSS\n- **Auth**: Custom JWT (bcryptjs + jose), tokens in localStorage\n- **Ingest**: POST /api/payments/ingest (public) — SMS text OR structured JSON (Apple Wallet)\n- **Schema** (PostgreSQL via Prisma):\n - `payments` table: id, raw_message, date, type (POS/ATM/INTERNET/ECOM/P2P/WALLET), card, recipient, amount, balance, status (UNPROCESSED/SENT/SKIPPED), notifyPhone, notifiedAt, created_at, updated_at\n - `tags` table: id, name, color — M2M with payments via `_PaymentToTag`\n - `users` table: id, username, hashed_password (this will be REMOVED)\n- **UI**: Single-page React app — PaymentTable (sortable, filterable, taggable), FilterBar, status actions (send/skip), notification system\n- **Parser** (backend/src/parser.js): Regex parser for Bulgarian DSK Bank SMS, extracts date/time (DD/MM/YYYY HH:MM), card mask, transaction type, recipient, amount, balance\n\n## App 2: dsk-uploader (Python/Flask)\n- **Purpose**: Upload DSK bank CSV exports → parse/normalize → upload to Notion database\n- **Stack**: Python 3.11 + Flask + Pandas + Custom Notion SDK + Bootstrap 5\n- **Auth**: None (open)\n- **CSV format** (DSK Bank Bulgarian format, columns):\n - `Дата` (date, DD.MM.YYYY)\n - `Вид на трансакцията` (transaction type, Bulgarian)\n - `Основание` (reason/description — contains card number regex: `^\\d{6}x{6}\\d{4}$`)\n - `Дебит BGN` (debit amount, may be empty)\n - `Кредит BGN` (credit amount, may be empty)\n - `Наредител/Получател` (orderer/recipient name)\n - `Номер сметка на наредителя / получателя` (account number)\n- **Processing**: merge multiple CSVs, normalize dates, extract card numbers from reason via regex, auto-generate tags (keyword heuristics: ЗАПЛАТА→Salary, NETFLIX→Subscriptions, etc.), filter internal transfers\n- **Output**: Notion database pages (this will be REPLACED with local PostgreSQL)\n\n## App 3: auth (Authentik)\n- **Mode**: Proxy mode via NPM (forward auth)\n- **How it works**: NPM intercepts all requests, calls Authentik outpost's auth endpoint. On success, NPM injects headers into proxied request:\n - `X-authentik-username` \n - `X-authentik-email`\n - `X-authentik-groups`\n- **No code integration needed** in the app itself — just trust these headers from NPM\n- **Logout**: Redirect user to `/outpost.goauthentik.io/sign_out`\n\n---\n\n## What the New Combined App Must Do\n\n1. **Single PostgreSQL database** for all transactions\n2. **SMS Ingest** (public endpoint) — same as payments-logger /ingest, source=INGEST\n3. **CSV Upload** (authenticated) — parse DSK CSV files, store transactions with source=UPLOAD into the same DB schema\n4. **Unified UI** — show all payments in one table regardless of source\n5. **Source indicator** in UI — badge showing \"INGEST\", \"UPLOAD\", or \"BOTH\" (if duplicate detection added)\n6. **Source filter** in FilterBar — filter by All/Ingest/Upload\n7. **Authentik auth** — remove custom JWT entirely; trust X-authentik-* headers from NPM\n8. **All existing payments-logger features**: tagging, send notification, skip, status tracking, filters, sorting, pagination\n9. **Remove Notion dependency entirely** — all data stays in local PostgreSQL\n\n---\n\n## Technical Constraints\n\n- Keep Node.js backend (not Python) — extend payments-logger's stack\n- CSV parsing: use `csv-parse` npm package (handles encoding, streaming)\n- File upload: use `multer` npm middleware\n- Auth middleware: read X-authentik-username header, 401 if missing (but /api/payments/ingest stays public)\n- Add `source` enum field (INGEST/UPLOAD) to payments schema\n- Add `currency` field (EUR for SMS ingest, BGN for CSV uploads) — or just store as-is\n- Remove `users` table from schema\n\n---\n\n## Please Design\n\n1. Complete folder structure for the new app (suggest name: \"finance-hub\" or similar — note this is a placeholder, user will confirm)\n2. Prisma schema with new fields (`source`, `currency`)\n3. All backend API routes\n4. CSV parser design in Node.js (port of the Python logic)\n5. Authentik auth middleware\n6. Frontend component structure (React) — what's reused from payments-logger, what's new\n7. Docker Compose setup\n8. Environment variables needed\n9. Step-by-step implementation order\n10. Verification checklist\n\nBe specific about file paths and code structure. This will be used to write actual implementation code.","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List all files in finance directory","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/finance -type f | sort | head -100","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/finance/auth/auth/db/base/1/112\n/volume2/docker/finance/auth/auth/db/base/1/113\n/volume2/docker/finance/auth/auth/db/base/1/1247\n/volume2/docker/finance/auth/auth/db/base/1/1247_fsm\n/volume2/docker/finance/auth/auth/db/base/1/1247_vm\n/volume2/docker/finance/auth/auth/db/base/1/1249\n/volume2/docker/finance/auth/auth/db/base/1/1249_fsm\n/volume2/docker/finance/auth/auth/db/base/1/1249_vm\n/volume2/docker/finance/auth/auth/db/base/1/1255\n/volume2/docker/finance/auth/auth/db/base/1/1255_fsm\n/volume2/docker/finance/auth/auth/db/base/1/1255_vm\n/volume2/docker/finance/auth/auth/db/base/1/1259\n/volume2/docker/finance/auth/auth/db/base/1/1259_fsm\n/volume2/docker/finance/auth/auth/db/base/1/1259_vm\n/volume2/docker/finance/auth/auth/db/base/1/13457\n/volume2/docker/finance/auth/auth/db/base/1/13457_fsm\n/volume2/docker/finance/auth/auth/db/base/1/13457_vm\n/volume2/docker/finance/auth/auth/db/base/1/13460\n/volume2/docker/finance/auth/auth/db/base/1/13461\n/volume2/docker/finance/auth/auth/db/base/1/13462\n/volume2/docker/finance/auth/auth/db/base/1/13462_fsm\n/volume2/docker/finance/auth/auth/db/base/1/13462_vm\n/volume2/docker/finance/auth/auth/db/base/1/13465\n/volume2/docker/finance/auth/auth/db/base/1/13466\n/volume2/docker/finance/auth/auth/db/base/1/13467\n/volume2/docker/finance/auth/auth/db/base/1/13467_fsm\n/volume2/docker/finance/auth/auth/db/base/1/13467_vm\n/volume2/docker/finance/auth/auth/db/base/1/13470\n/volume2/docker/finance/auth/auth/db/base/1/13471\n/volume2/docker/finance/auth/auth/db/base/1/13472\n/volume2/docker/finance/auth/auth/db/base/1/13472_fsm\n/volume2/docker/finance/auth/auth/db/base/1/13472_vm\n/volume2/docker/finance/auth/auth/db/base/1/13475\n/volume2/docker/finance/auth/auth/db/base/1/13476\n/volume2/docker/finance/auth/auth/db/base/1/1417\n/volume2/docker/finance/auth/auth/db/base/1/1418\n/volume2/docker/finance/auth/auth/db/base/1/174\n/volume2/docker/finance/auth/auth/db/base/1/175\n/volume2/docker/finance/auth/auth/db/base/1/2187\n/volume2/docker/finance/auth/auth/db/base/1/2224\n/volume2/docker/finance/auth/auth/db/base/1/2228\n/volume2/docker/finance/auth/auth/db/base/1/2328\n/volume2/docker/finance/auth/auth/db/base/1/2336\n/volume2/docker/finance/auth/auth/db/base/1/2337\n/volume2/docker/finance/auth/auth/db/base/1/2579\n/volume2/docker/finance/auth/auth/db/base/1/2600\n/volume2/docker/finance/auth/auth/db/base/1/2600_fsm\n/volume2/docker/finance/auth/auth/db/base/1/2600_vm\n/volume2/docker/finance/auth/auth/db/base/1/2601\n/volume2/docker/finance/auth/auth/db/base/1/2601_fsm\n/volume2/docker/finance/auth/auth/db/base/1/2601_vm\n/volume2/docker/finance/auth/auth/db/base/1/2602\n/volume2/docker/finance/auth/auth/db/base/1/2602_fsm\n/volume2/docker/finance/auth/auth/db/base/1/2602_vm\n/volume2/docker/finance/auth/auth/db/base/1/2603\n/volume2/docker/finance/auth/auth/db/base/1/2603_fsm\n/volume2/docker/finance/auth/auth/db/base/1/2603_vm\n/volume2/docker/finance/auth/auth/db/base/1/2604\n/volume2/docker/finance/auth/auth/db/base/1/2605\n/volume2/docker/finance/auth/auth/db/base/1/2605_fsm\n/volume2/docker/finance/auth/auth/db/base/1/2605_vm\n/volume2/docker/finance/auth/auth/db/base/1/2606\n/volume2/docker/finance/auth/auth/db/base/1/2606_fsm\n/volume2/docker/finance/auth/auth/db/base/1/2606_vm\n/volume2/docker/finance/auth/auth/db/base/1/2607\n/volume2/docker/finance/auth/auth/db/base/1/2607_fsm\n/volume2/docker/finance/auth/auth/db/base/1/2607_vm\n/volume2/docker/finance/auth/auth/db/base/1/2608\n/volume2/docker/finance/auth/auth/db/base/1/2608_fsm\n/volume2/docker/finance/auth/auth/db/base/1/2608_vm\n/volume2/docker/finance/auth/auth/db/base/1/2609\n/volume2/docker/finance/auth/auth/db/base/1/2609_fsm\n/volume2/docker/finance/auth/auth/db/base/1/2609_vm\n/volume2/docker/finance/auth/auth/db/base/1/2610\n/volume2/docker/finance/auth/auth/db/base/1/2610_fsm\n/volume2/docker/finance/auth/auth/db/base/1/2610_vm\n/volume2/docker/finance/auth/auth/db/base/1/2611\n/volume2/docker/finance/auth/auth/db/base/1/2612\n/volume2/docker/finance/auth/auth/db/base/1/2612_fsm\n/volume2/docker/finance/auth/auth/db/base/1/2612_vm\n/volume2/docker/finance/auth/auth/db/base/1/2613\n/volume2/docker/finance/auth/auth/db/base/1/2615\n/volume2/docker/finance/auth/auth/db/base/1/2615_fsm\n/volume2/docker/finance/auth/auth/db/base/1/2615_vm\n/volume2/docker/finance/auth/auth/db/base/1/2616\n/volume2/docker/finance/auth/auth/db/base/1/2616_fsm\n/volume2/docker/finance/auth/auth/db/base/1/2616_vm\n/volume2/docker/finance/auth/auth/db/base/1/2617\n/volume2/docker/finance/auth/auth/db/base/1/2617_fsm\n/volume2/docker/finance/auth/auth/db/base/1/2617_vm\n/volume2/docker/finance/auth/auth/db/base/1/2618\n/volume2/docker/finance/auth/auth/db/base/1/2618_fsm\n/volume2/docker/finance/auth/auth/db/base/1/2618_vm\n/volume2/docker/finance/auth/auth/db/base/1/2619\n/volume2/docker/finance/auth/auth/db/base/1/2619_fsm\n/volume2/docker/finance/auth/auth/db/base/1/2619_vm\n/volume2/docker/finance/auth/auth/db/base/1/2620\n/volume2/docker/finance/auth/auth/db/base/1/2650\n/volume2/docker/finance/auth/auth/db/base/1/2651\n/volume2/docker/finance/auth/auth/db/base/1/2652","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List docker directory contents","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"ls -la /volume2/docker/","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"total 40\ndrwxrwxrwx 1 root root 1160 May 8 21:05 .\ndrwxr-xr-x 1 root root 246 Apr 6 19:54 ..\ndrwxrwxrwx 1 Adm1n admin 20 Jul 28 2025 adguard\ndrwxrwxrwx 1 Adm1n admin 66 Apr 5 13:14 ai-stack\ndrwxrwxrwx 1 Adm1n admin 12 Aug 1 2025 app-db\ndrwxrwxr-x 1 appflowy users 138 Dec 14 18:21 appflowy\ndrwxrwxrwx 1 Adm1n admin 72 May 6 14:55 audiobookshelf\ndrwxrwxrwx 1 Adm1n admin 128 Mar 30 19:52 auth\ndrwxrwxrwx 1 Adm1n admin 102 May 8 21:02 beszel\ndrwxrwxrwx 1 Adm1n admin 38 Jun 16 2025 bitwarden\ndrwxrwxrwx 1 Adm1n admin 36 Aug 25 2025 dawarich\ndrwxrwxrwx 1 Adm1n admin 322 Aug 15 2025 dsk-uploader\n-rwxrwxrwx 1 Adm1n admin 10244 Oct 29 2025 .DS_Store\ndrwxrwxrwx 1 Adm1n admin 62 May 8 21:10 finance\ndrwxrwxrwx 1 Adm1n admin 92 Aug 19 2025 flask-app\ndrwxrwxrwx 1 Adm1n admin 308 Oct 7 2025 garmin-connector\ndrwxrwxrwx 1 Adm1n admin 12 Jul 18 2025 gitea\ndrwxrwxrwx 1 Adm1n admin 0 Feb 16 19:30 health\ndrwxrwxrwx 1 Adm1n admin 220 Feb 16 21:09 health-tracker\ndrwxrwxrwx 1 Adm1n admin 0 Oct 31 2025 homarr\ndrwxrwxrwx 1 Adm1n admin 146 Mar 7 20:46 hst\ndrwxrwxrwx 1 Adm1n admin 66 Aug 31 2025 immich\ndrwxrwx--- 1 Adm1n Media 30 Jun 15 2025 jellyfinht\ndrwxrwxrwx 1 Adm1n admin 20 Aug 31 2025 kavita\ndrwxrwxrwx 1 Adm1n admin 0 Oct 12 2025 libreoffice\ndrwxrwxrwx 1 Adm1n admin 12 Dec 13 21:12 linkwarden\ndrwxrwxrwx 1 Adm1n admin 274 Apr 9 19:39 location-logger\ndrwxrwxrwx 1 dnsmasq systemd-journal 432 Aug 27 2025 mariadb\ndrwxrwxrwx 1 Adm1n admin 122 Apr 26 19:03 meeting-detector\ndrwxrwxrwx 1 Adm1n admin 0 Aug 15 2025 mindfulmama\ndrwxrwxrwx 1 Adm1n admin 22 Jul 16 2025 n8n\ndrwxrwxrwx 1 Adm1n admin 176 Feb 20 17:33 notifier-app\ndrwxrwxrwx 1 Adm1n admin 52 Jun 15 2025 npm\ndrwxrwxrwx 1 Adm1n admin 306 Mar 29 17:34 oauth\ndrwxrwxrwx 1 Adm1n admin 92 Jun 15 2025 obsidian\ndrwxr-xr-x 1 root root 60 Mar 7 20:56 ollama\ndrwxr-xr-x 1 911 911 128 Jul 28 2025 openttd\ndrwxrwxrwx 1 Adm1n admin 234 Mar 7 16:30 openvpn-client\ndrwxr-xr-x 1 root root 58 May 2 23:15 open-webui\ndrwxrwxrwx 1 Adm1n admin 134 Dec 31 13:13 orchestrator\ndrwxrwxrwx 1 Adm1n admin 406 Mar 25 20:39 outfit-app\ndrwxrwxrwx 1 Adm1n admin 90 Aug 28 2025 owntracks-stack\ndrwxrwxrwx 1 Adm1n admin 156 Mar 10 20:51 paperlessngx\ndrwxrwxrwx 1 Adm1n admin 162 May 8 20:36 payments-logger\ndrwxrwxrwx 1 Adm1n admin 0 Sep 28 2025 personal-log\ndrwxrwxrwx 1 Adm1n admin 616 Mar 7 20:46 personal-log-system\ndrwxrwxrwx 1 Adm1n admin 26 Feb 19 19:41 player\ndrwxrwxrwx 1 Adm1n admin 202 Feb 23 21:35 portainer\ndrwxrwxrwx 1 dnsmasq admin 484 Dec 4 19:31 portnotedb\ndrwxrwxrwx 1 Adm1n admin 140 Apr 4 15:49 reminders-app\ndrwxrwxrwx 1 Adm1n admin 60 Oct 29 2025 romm\ndrwxrwxrwx 1 Adm1n admin 108 Feb 23 20:15 second-brain\ndrwxrwxrwx 1 Adm1n admin 10 Dec 30 17:16 static\ndrwxrwxrwx 1 Adm1n admin 28 Jun 19 2025 stirling\ndrwxrwxrwx 1 Adm1n admin 86 Oct 25 2025 syncthing\ndrwxrwxrwx 1 root root 56 Jun 5 2025 tailscale\ndrwxrwxrwx 1 Adm1n admin 186 Sep 23 2025 temp-logger\ndrwxrwxrwx 1 Adm1n admin 122 Jul 19 2025 test-app\ndrwxrwxrwx 1 Adm1n admin 52 Jun 14 2025 tmp\ndrwxrwxrwx 1 Adm1n admin 36 Jul 13 2025 torrent-stack\ndrwxrwxrwx 1 Adm1n admin 48 Dec 19 10:58 tree\ndrwxrwxrwx 1 Adm1n admin 0 Oct 31 2025 trilium\ndrwxrwxrwx 1 Adm1n admin 34 Dec 3 21:18 tubearchivist\ndrwxrwxrwx 1 Adm1n admin 22 Jul 25 2025 twenty\ndrwxrwxrwx 1 Adm1n admin 0 Nov 2 2025 uptimekuma\ndrwxrwxrwx 1 Adm1n admin 30 Dec 7 17:30 ytptube","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List all files in payments-logger directory","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/payments-logger -type f | sort","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/payments-logger/API.md\n/volume2/docker/payments-logger/backend/Dockerfile\n/volume2/docker/payments-logger/backend/.dockerignore\n/volume2/docker/payments-logger/backend/package.json\n/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql\n/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql\n/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql\n/volume2/docker/payments-logger/backend/prisma/migrations/20260508_add_users/migration.sql\n/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml\n/volume2/docker/payments-logger/backend/prisma/schema.prisma\n/volume2/docker/payments-logger/backend/src/auth.js\n/volume2/docker/payments-logger/backend/src/index.js\n/volume2/docker/payments-logger/backend/src/parser.js\n/volume2/docker/payments-logger/backend/src/routes/payments.js\n/volume2/docker/payments-logger/.claude/settings.local.json\n/volume2/docker/payments-logger/docker-compose.yml\n/volume2/docker/payments-logger/.env\n/volume2/docker/payments-logger/.env.example\n/volume2/docker/payments-logger/frontend/Dockerfile\n/volume2/docker/payments-logger/frontend/.dockerignore\n/volume2/docker/payments-logger/frontend/index.html\n/volume2/docker/payments-logger/frontend/package.json\n/volume2/docker/payments-logger/frontend/postcss.config.js\n/volume2/docker/payments-logger/frontend/src/App.jsx\n/volume2/docker/payments-logger/frontend/src/auth.js\n/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx\n/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx\n/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx\n/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx\n/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx\n/volume2/docker/payments-logger/frontend/src/index.css\n/volume2/docker/payments-logger/frontend/src/main.jsx\n/volume2/docker/payments-logger/frontend/tailwind.config.js\n/volume2/docker/payments-logger/frontend/vite.config.js\n/volume2/docker/payments-logger/.gitignore\n/volume2/docker/payments-logger/README.md","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Bash","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"List all files in dsk-uploader directory","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"IN","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"find /volume2/docker/dsk-uploader -type f | sort","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Copy code to clipboard","depth":25,"on_screen":false,"help_text":"Copy code","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"OUT","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"/volume2/docker/dsk-uploader/app_flask.py\n/volume2/docker/dsk-uploader/app.py\n/volume2/docker/dsk-uploader/docker-compose.yml\n/volume2/docker/dsk-uploader/Dockerfile\n/volume2/docker/dsk-uploader/.dockerignore\n/volume2/docker/dsk-uploader/dskuploader.py\n/volume2/docker/dsk-uploader/.env\n/volume2/docker/dsk-uploader/.env.example\n/volume2/docker/dsk-uploader/.git/COMMIT_EDITMSG\n/volume2/docker/dsk-uploader/.git/config\n/volume2/docker/dsk-uploader/.git/description\n/volume2/docker/dsk-uploader/.git/FETCH_HEAD\n/volume2/docker/dsk-uploader/.git/HEAD\n/volume2/docker/dsk-uploader/.git/hooks/applypatch-msg.sample\n/volume2/docker/dsk-uploader/.git/hooks/commit-msg.sample\n/volume2/docker/dsk-uploader/.git/hooks/fsmonitor-watchman.sample\n/volume2/docker/dsk-uploader/.git/hooks/post-update.sample\n/volume2/docker/dsk-uploader/.git/hooks/pre-applypatch.sample\n/volume2/docker/dsk-uploader/.git/hooks/pre-commit.sample\n/volume2/docker/dsk-uploader/.git/hooks/pre-merge-commit.sample\n/volume2/docker/dsk-uploader/.git/hooks/prepare-commit-msg.sample\n/volume2/docker/dsk-uploader/.git/hooks/pre-push.sample\n/volume2/docker/dsk-uploader/.git/hooks/pre-rebase.sample\n/volume2/docker/dsk-uploader/.git/hooks/pre-receive.sample\n/volume2/docker/dsk-uploader/.git/hooks/push-to-checkout.sample\n/volume2/docker/dsk-uploader/.git/hooks/update.sample\n/volume2/docker/dsk-uploader/.gitignore\n/volume2/docker/dsk-uploader/.git/index\n/volume2/docker/dsk-uploader/.git/info/exclude\n/volume2/docker/dsk-uploader/.git/logs/HEAD\n/volume2/docker/dsk-uploader/.git/logs/refs/heads/main\n/volume2/docker/dsk-uploader/.git/logs/refs/remotes/origin/HEAD\n/volume2/docker/dsk-uploader/.git/logs/refs/remotes/origin/main\n/volume2/docker/dsk-uploader/.git/objects/0b/918bed65202bedaa9fa092e539d607be2eea65\n/volume2/docker/dsk-uploader/.git/objects/11/b908125d2f0feebf7aca6d24e127f334bce611\n/volume2/docker/dsk-uploader/.git/objects/56/a2766ae5422b18e5b1a418fd231ad12fef08e6\n/volume2/docker/dsk-uploader/.git/objects/65/386fd3b4ac62094500e21c23845d05b9d18a4f\n/volume2/docker/dsk-uploader/.git/objects/7b/2d7b18213f9516ec4544f309772ee4808146bb\n/volume2/docker/dsk-uploader/.git/objects/7c/3f071fef98751a68b7d93779f76cf5d5aa8ebf\n/volume2/docker/dsk-uploader/.git/objects/85/b5483672f68c327c39ea8c29e94ae8b22b7bbf\n/volume2/docker/dsk-uploader/.git/objects/8e/a1cbf78eae8a86c5990d0582db1847c0226b56\n/volume2/docker/dsk-uploader/.git/objects/ed/8e93af8cc77c7a85f87a9f37573c51b839e571\n/volume2/docker/dsk-uploader/.git/objects/ee/3d5f92e57deec809abda371386e371f32de9bb\n/volume2/docker/dsk-uploader/.git/objects/f3/98248da8f4911d463d9a33155fcf58a65092cc\n/volume2/docker/dsk-uploader/.git/objects/pack/pack-ed5aca57f7f3b56e67172d9fb90e685087770006.idx\n/volume2/docker/dsk-uploader/.git/objects/pack/pack-ed5aca57f7f3b56e67172d9fb90e685087770006.pack\n/volume2/docker/dsk-uploader/.git/ORIG_HEAD\n/volume2/docker/dsk-uploader/.git/packed-refs\n/volume2/docker/dsk-uploader/.git/refs/heads/main\n/volume2/docker/dsk-uploader/.git/refs/remotes/origin/HEAD\n/volume2/docker/dsk-uploader/.git/refs/remotes/origin/main\n/volume2/docker/dsk-uploader/notion_connector/client.py\n/volume2/docker/dsk-uploader/notion_connector/exceptions/exceptions.py\n/volume2/docker/dsk-uploader/notion_connector/exceptions/__init__.py\n/volume2/docker/dsk-uploader/notion_connector/__init__.py\n/volume2/docker/dsk-uploader/notion_connector/resources/block_property.py\n/volume2/docker/dsk-uploader/notion_connector/resources/block.py\n/volume2/docker/dsk-uploader/notion_connector/resources/database_property.py\n/volume2/docker/dsk-uploader/notion_connector/resources/database.py\n/volume2/docker/dsk-uploader/notion_connector/resources/filter_builder.py\n/volume2/docker/dsk-uploader/notion_connector/resources/__init__.py\n/volume2/docker/dsk-uploader/notion_connector/resources/page_property.py\n/volume2/docker/dsk-uploader/notion_connector/resources/page.py\n/volume2/docker/dsk-uploader/notion_connector/resources/search.py\n/volume2/docker/dsk-uploader/README.md\n/volume2/docker/dsk-uploader/requirements.txt\n/volume2/docker/dsk-uploader/templates/base.html\n/volume2/docker/dsk-uploader/templates/index.html\n/volume2/docker/dsk-uploader/templates/result.html\n/volume2/docker/dsk-uploader/USAGE.md","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"schema.prisma","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"schema.prisma","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"parser.js","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"parser.js","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"index.js","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"index.js","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"payments.js","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"payments.js","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"package.json","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"package.json","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":".env.example","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":".env.example","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"App.jsx","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"App.jsx","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"FilterBar.jsx","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"FilterBar.jsx","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"PaymentTable.jsx","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"PaymentTable.jsx","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"AuthProvider.jsx","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"AuthProvider.jsx","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"auth.js","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"auth.js","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"app.py","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app.py","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"dskuploader.py","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"dskuploader.py","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"app_flask.py","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app_flask.py","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"package.json","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"package.json","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"vite.config.js","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"vite.config.js","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Dockerfile","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"Dockerfile","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Dockerfile","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"migration.sql","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"migration.sql","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"migration.sql","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"migration.sql","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"migration.sql","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"migration.sql","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"migration.sql","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"migration.sql","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"API.md","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"API.md","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"docker-compose.yml","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"docker-compose.yml","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"PaymentCard.jsx","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"PaymentCard.jsx","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"PaymentList.jsx","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"PaymentList.jsx","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"tailwind.config.js","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"tailwind.config.js","depth":26,"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Read","depth":25,"on_screen":false,"role_description":"text"},{"role":"AXLink","text":"main.jsx","depth":25,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"main.jsx","depth":26,"on_screen":false,"role_description":"text"}]...
|
-7744524905982221756
|
-4865117421593178485
|
visual_change
|
accessibility
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G)
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Claude Code - 1 session waiting for input
1
Containers
EXPLORER
EXPLORER
Explorer Section: finance [SSH: nas]
Explorer Section: finance [SSH: nas]
FINANCE [SSH: NAS]
auth
dsk-uploader
payments-logger
Outline Section
OUTLINE
OUTLINE
Timeline Section
TIMELINE
TIMELINE
payments.js, preview, Editor Group 1
…
payments.js, preview, Editor Group 1
Design new payment-logge…, Editor Group 2
finance-hub — Implementation Plan, Editor Group 3
remote SSH: nas
SSH: nas
No Problems
0
0
No Ports Forwarded
0
Notifications
Sign In
Sign In
collapsed
Design new payment-logger and dsk-uploader hybrid app
Session history
New session
Message actions
payments.js
payments.js
ets create a new app that should be combination of payment-logger and dsk-uploader. It should have authorization via authentik (auth folder). All three folders (payment-logger, dsk-uploader and auth) are just refference these will be removed later. Auth project is separated it lives on its own. First reveiw them and see how these should be combined. It will be whole new app (also the folder name). Think very carefully of whatr these two apps do and how cold they be combined. THerer should be common db and uploader should store data the same way the /ingest does. It should be properly marked in UI if it is upload or ingest or both. FIrst think of tech stack and plan carefully.
Thinking
Thinking
I'll explore all three reference projects in parallel to understand their structure before planning.
Agent:
Explore payment-logger app structure and functionality
IN
Explore the /volume2/docker/finance/payments-logger directory thoroughly. I need to understand:
1. Tech stack (frontend framework, backend framework, database)
2. What the app does - its core purpose and features
3. Database schema - all tables, relationships
4. API routes - all endpoints, their purpose and request/response shapes
5. How data flows (ingest, storage, retrieval)
6. Any auth/middleware setup
7. Docker/deployment setup
8. Key files and their roles
Report with: directory structure, tech stack summary, database schema details, all API endpoints listed, UI features, and how data is ingested. Be thorough on the /ingest endpoint specifically.
Agent:
Explore dsk-uploader app structure and functionality
IN
Explore the /volume2/docker/finance/dsk-uploader directory thoroughly. I need to understand:
1. Tech stack (frontend framework, backend framework, database)
2. What the app does - its core purpose and features
3. Database schema - all tables, relationships
4. API routes - all endpoints, their purpose and request/response shapes
5. How file uploads work - what files, what format, how parsed
6. Any auth/middleware setup
7. Docker/deployment setup
8. Key files and their roles
Report with: directory structure, tech stack summary, database schema details, all API endpoints listed, UI features, how file upload parsing works, and what data is extracted from uploads. Be very thorough about the data model and what fields are stored.
Agent:
Explore auth folder and authentik integration
IN
Explore the /volume2/docker/finance/auth directory thoroughly. I need to understand:
1. What auth system is being used (Authentik)
2. How authentication/authorization is implemented - OAuth2, OIDC, session tokens, JWT?
3. Middleware - how is auth enforced on routes?
4. Any frontend auth flow - login redirect, token handling, protected routes
5. Environment variables related to auth
6. Docker/deployment setup for the auth service itself
7. Any example of how other apps integrate with this auth
Report with: directory structure, auth flow description, middleware code, environment variable names, and integration patterns. This is a reference for building auth into a new combined app.
Message actions
payments.js
payments.js
continue
Thinking
Thinking
Launching parallel exploration of all three reference projects.
Agent:
Explore payment-logger app structure
IN
Explore the /volume2/docker/finance/payments-logger directory thoroughly. I need to understand:
1. Full directory structure (tree)
2. Tech stack (frontend framework, backend framework, database, etc.)
3. What the app does - its core functionality
4. How data is ingested (look at /ingest route especially)
5. Database schema (what tables/collections exist)
6. API routes and their purposes
7. Frontend pages and components
8. Docker setup
9. Any auth/session handling
Please read key files: package.json files, main entry points, route files, database schema files, docker-compose.yml, and any frontend components. Be thorough - I need a complete picture to plan a new combined app.
Bash
IN
find /volume2/docker/finance/payments-logger -type f -name "*.json" -o -name "*.js" -o -name "*.jsx" -o -name "*.ts" -o -name "*.tsx" -o -name "*.py" -o -name "*.sql" -o -name "Dockerfile*" -o -name "docker-compose*" -o -name ".env*" 2>/dev/null | head -50
Copy code to clipboard
OUT
/volume2/docker/finance/payments-logger/.env
/volume2/docker/finance/payments-logger/.env.example
/volume2/docker/finance/payments-logger/docker-compose.yml
/volume2/docker/finance/payments-logger/.claude/settings.local.json
/volume2/docker/finance/payments-logger/backend/Dockerfile
/volume2/docker/finance/payments-logger/backend/package.json
/volume2/docker/finance/payments-logger/frontend/Dockerfile
/volume2/docker/finance/payments-logger/frontend/package.json
/volume2/docker/finance/payments-logger/frontend/postcss.config.js
/volume2/docker/finance/payments-logger/frontend/tailwind.config.js
/volume2/docker/finance/payments-logger/frontend/vite.config.js
/volume2/docker/finance/payments-logger/auth/.env
/volume2/docker/finance/payments-logger/auth/.env.example
/volume2/docker/finance/payments-logger/backend/src/auth.js
/volume2/docker/finance/payments-logger/backend/src/index.js
/volume2/docker/finance/payments-logger/backend/src/parser.js
/volume2/docker/finance/payments-logger/frontend/src/App.jsx
/volume2/docker/finance/payments-logger/frontend/src/auth.js
/volume2/docker/finance/payments-logger/frontend/src/main.jsx
/volume2/docker/finance/payments-logger/backend/src/routes/payments.js
/volume2/docker/finance/payments-logger/frontend/src/components/AuthProvider.jsx
/volume2/docker/finance/payments-logger/frontend/src/components/FilterBar.jsx
/volume2/docker/finance/payments-logger/frontend/src/components/PaymentCard.jsx
/volume2/docker/finance/payments-logger/frontend/src/components/PaymentList.jsx
/volume2/docker/finance/payments-logger/frontend/src/components/PaymentTable.jsx
/volume2/docker/finance/payments-logger/backend/prisma/migrations/20260210_init/migration.sql
/volume2/docker/finance/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql
/volume2/docker/finance/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql
/volume2/docker/finance/payments-logger/backend/prisma/migrations/20260508_add_users/migration.sql
Agent:
Explore dsk-uploader app structure
IN
Explore the /volume2/docker/finance/dsk-uploader directory thoroughly. I need to understand:
1. Full directory structure (tree)
2. Tech stack (frontend framework, backend framework, database, etc.)
3. What the app does - its core functionality
4. How file uploads work (what format, what processing happens)
5. Database schema (what tables/collections exist)
6. API routes and their purposes
7. Frontend pages and components
8. Docker setup
9. Any auth/session handling
Please read key files: package.json files, main entry points, route files, database schema files, docker-compose.yml, and any frontend components. Be thorough - I need a complete picture to plan a new combined app.
Bash
IN
find /volume2/docker/finance/dsk-uploader -type f -name "*.json" -o -type f -name "*.yml" -o -type f -name "*.yaml" | head -30
Copy code to clipboard
OUT
/volume2/docker/finance/dsk-uploader/docker-compose.yml
Bash
IN
cd /volume2/docker/finance/payments-logger && find . -type f \( -name "*.json" -o -name "*.js" -o -name "*.jsx" -o -name "*.ts" -o -name "*.tsx" -o -name "*.sql" -o -name "*.yml" -o -name "*.yaml" -o -name "Dockerfile*" -o -name ".env*" \) | grep -v node_modules | sort
Copy code to clipboard
OUT
./auth/.env
./auth/.env.example
./backend/Dockerfile
./backend/package.json
./backend/prisma/migrations/20260210_init/migration.sql
./backend/prisma/migrations/20260210_simplify/migration.sql
./backend/prisma/migrations/20260222_add_card/migration.sql
./backend/prisma/migrations/20260508_add_users/migration.sql
./backend/src/auth.js
./backend/src/index.js
./backend/src/parser.js
./backend/src/routes/payments.js
./.claude/settings.local.json
./docker-compose.yml
./.env
./.env.example
./frontend/Dockerfile
./frontend/package.json
./frontend/postcss.config.js
./frontend/src/App.jsx
./frontend/src/auth.js
./frontend/src/components/AuthProvider.jsx
./frontend/src/components/FilterBar.jsx
./frontend/src/components/PaymentCard.jsx
./frontend/src/components/PaymentList.jsx
./frontend/src/components/PaymentTable.jsx
./frontend/src/main.jsx
./frontend/tailwind.config.js
./frontend/vite.config.js
Agent:
Explore auth project structure
IN
Explore the /volume2/docker/finance/auth directory thoroughly. I need to understand:
1. Full directory structure (tree)
2. What authentication system is used (authentik integration details)
3. How OAuth/OIDC flow works
4. Any middleware or helper functions for protecting routes
5. Session management approach
6. How frontend handles auth state
7. Any example of how other apps integrate with this auth system
8. Docker setup and environment variables
Please read all files carefully - this auth system will be integrated into a new combined app. I need to understand exactly how to use it.
Bash
IN
cd /volume2/docker/finance/dsk-uploader && find . -type f | head -100
Copy code to clipboard
OUT
./.gitignore
./README.md
./USAGE.md
./app.py
./app_flask.py
./dskuploader.py
./requirements.txt
./.env
./.env.example
./Dockerfile
./docker-compose.yml
./.dockerignore
./.git/description
./.git/packed-refs
./.git/HEAD
./.git/FETCH_HEAD
./.git/index
./.git/COMMIT_EDITMSG
./.git/ORIG_HEAD
./notion_connector/__init__.py
./notion_connector/client.py
./templates/base.html
./templates/index.html
./templates/result.html
./notion_connector/resources/__init__.py
./notion_connector/resources/block.py
./notion_connector/resources/block_property.py
./notion_connector/resources/database.py
./notion_connector/resources/database_property.py
./notion_connector/resources/filter_builder.py
./notion_connector/resources/page.py
./notion_connector/resources/page_property.py
./notion_connector/resources/search.py
./.git/info/exclude
./.git/hooks/post-update.sample
./.git/hooks/pre-applypatch.sample
./.git/hooks/pre-commit.sample
./.git/hooks/applypatch-msg.sample
./.git/hooks/pre-rebase.sample
./.git/hooks/pre-merge-commit.sample
./.git/hooks/update.sample
./.git/hooks/pre-push.sample
./.git/hooks/push-to-checkout.sample
./.git/hooks/prepare-commit-msg.sample
./.git/hooks/commit-msg.sample
./.git/hooks/pre-receive.sample
./.git/hooks/fsmonitor-watchman.sample
./.git/logs/HEAD
./notion_connector/exceptions/__init__.py
./notion_connector/exceptions/exceptions.py
./.git/config
./.git/refs/heads/main
./.git/refs/remotes/origin/HEAD
./.git/refs/remotes/origin/main
./.git/objects/7c/3f071fef98751a68b7d93779f76cf5d5aa8ebf
./.git/objects/ed/8e93af8cc77c7a85f87a9f37573c51b839e571
./.git/objects/7b/2d7b18213f9516ec4544f309772ee4808146bb
./.git/objects/65/386fd3b4ac62094500e21c23845d05b9d18a4f
./.git/objects/ee/3d5f92e57deec809abda371386e371f32de9bb
./.git/logs/refs/heads/main
./.git/objects/pack/pack-ed5aca57f7f3b56e67172d9fb90e685087770006.pack
./.git/objects/pack/pack-ed5aca57f7f3b56e67172d9fb90e685087770006.idx
./.git/objects/85/b5483672f68c327c39ea8c29e94ae8b22b7bbf
./.git/objects/f3/98248da8f4911d463d9a33155fcf58a65092cc
./.git/objects/0b/918bed65202bedaa9fa092e539d607be2eea65
./.git/objects/8e/a1cbf78eae8a86c5990d0582db1847c0226b56
./.git/objects/11/b908125d2f0feebf7aca6d24e127f334bce611
./.git/objects/56/a2766ae5422b18e5b1a418fd231ad12fef08e6
./.git/logs/refs/remotes/origin/HEAD
./.git/logs/refs/remotes/origin/main
Bash
IN
find /volume2/docker/finance/auth -type f -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.tsx" -o -name "*.json" -o -name "*.yaml" -o -name "*.yml" -o -name "*.env*" -o -name "Dockerfile*" | head -100
Copy code to clipboard
OUT
/volume2/docker/finance/auth/.env
/volume2/docker/finance/auth/.env.example
/volume2/docker/finance/auth/docker-compose.yml
/volume2/docker/finance/auth/auth/.env
/volume2/docker/finance/auth/auth/.env.example
/volume2/docker/finance/auth/auth/docker-compose.yml
Read
dsk-uploader
dsk-uploader
Read
docker-compose.yml
docker-compose.yml
Read
package.json
package.json
Read
package.json
package.json
Read
.env.example
.env.example
Bash
IN
ls -la /volume2/docker/finance/auth/ && echo "---" && find /volume2/docker/finance/auth -type d | sort
Copy code to clipboard
OUT
total 20
drwxrwxrwx 1 Adm1n admin 108 May 8 21:08 .
drwxrwxrwx 1 Adm1n admin 62 May 8 21:10 ..
drwxrwxrwx 1 Adm1n admin 128 May 8 21:08 auth
drwxrwxrwx 1 Adm1n admin 0 May 8 21:06 certs
drwxrwxrwx 1 Adm1n admin 0 May 8 21:06 db
-rwxrwxrwx 1 Adm1n admin 3328 May 8 21:07 docker-compose.yml
-rwxrwxrwx 1 Adm1n admin 949 May 8 21:06 .env
-rwxrwxrwx 1 Adm1n admin 2258 May 8 21:06 .env.example
-rwxrwxrwx 1 Adm1n admin 5501 May 8 21:07 README.md
---
/volume2/docker/finance/auth
/volume2/docker/finance/auth/auth
/volume2/docker/finance/auth/auth/certs
/volume2/docker/finance/auth/auth/db
/volume2/docker/finance/auth/auth/db/base
/volume2/docker/finance/auth/auth/db/base/1
/volume2/docker/finance/auth/auth/db/base/16384
/volume2/docker/finance/auth/auth/db/base/4
/volume2/docker/finance/auth/auth/db/base/5
/volume2/docker/finance/auth/auth/db/global
/volume2/docker/finance/auth/auth/db/pg_commit_ts
/volume2/docker/finance/auth/auth/db/pg_dynshmem
/volume2/docker/finance/auth/auth/db/pg_logical
/volume2/docker/finance/auth/auth/db/pg_logical/mappings
/volume2/docker/finance/auth/auth/db/pg_logical/snapshots
/volume2/docker/finance/auth/auth/db/pg_multixact
/volume2/docker/finance/auth/auth/db/pg_multixact/members
/volume2/docker/finance/auth/auth/db/pg_multixact/offsets
/volume2/docker/finance/auth/auth/db/pg_notify
/volume2/docker/finance/auth/auth/db/pg_replslot
/volume2/docker/finance/auth/auth/db/pg_serial
/volume2/docker/finance/auth/auth/db/pg_snapshots
/volume2/docker/finance/auth/auth/db/pg_stat
/volume2/docker/finance/auth/auth/db/pg_stat_tmp
/volume2/docker/finance/auth/auth/db/pg_subtrans
/volume2/docker/finance/auth/auth/db/pg_tblspc
/volume2/docker/finance/auth/auth/db/pg_twophase
/volume2/docker/finance/auth/auth/db/pg_wal
/volume2/docker/finance/auth/auth/db/pg_wal/archive_status
/volume2/docker/finance/auth/auth/db/pg_xact
/volume2/docker/finance/auth/auth/media
/volume2/docker/finance/auth/auth/templates
/volume2/docker/finance/auth/certs
/volume2/docker/finance/auth/db
Read
README.md
README.md
Read
requirements.txt
requirements.txt
Read
index.js
index.js
Read
payments.js
payments.js
Read
auth.js
auth.js
Read
README.md
README.md
Read
.env
.env
Read
.env.example
.env.example
Read
docker-compose.yml
docker-compose.yml
Read
parser.js
parser.js
Bash
IN
find /volume2/docker/finance/auth/auth -type f | grep -v "^/volume2/docker/finance/auth/auth/db" | grep -v "^/volume2/docker/finance/auth/auth/certs" | grep -v "^/volume2/docker/finance/auth/auth/media" | sort
Copy code to clipboard
OUT
/volume2/docker/finance/auth/auth/docker-compose.yml
/volume2/docker/finance/auth/auth/.env
/volume2/docker/finance/auth/auth/.env.example
/volume2/docker/finance/auth/auth/README.md
Read
migration.sql
migration.sql
Read
migration.sql
migration.sql
Read
README.md
README.md
Read
.env
.env
Read
.env.example
.env.example
Read
docker-compose.yml
docker-compose.yml
Read
App.jsx
App.jsx
Read
main.jsx
main.jsx
Read
auth.js
auth.js
Bash
IN
find /volume2/docker/finance -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.tsx" 2>/dev/null | head -50
Copy code to clipboard
OUT
/volume2/docker/finance/dsk-uploader/app.py
/volume2/docker/finance/dsk-uploader/app_flask.py
/volume2/docker/finance/dsk-uploader/dskuploader.py
/volume2/docker/finance/payments-logger/frontend/postcss.config.js
/volume2/docker/finance/payments-logger/frontend/tailwind.config.js
/volume2/docker/finance/payments-logger/frontend/vite.config.js
/volume2/docker/finance/dsk-uploader/notion_connector/__init__.py
/volume2/docker/finance/dsk-uploader/notion_connector/client.py
/volume2/docker/finance/payments-logger/backend/src/auth.js
/volume2/docker/finance/payments-logger/backend/src/index.js
/volume2/docker/finance/payments-logger/backend/src/parser.js
/volume2/docker/finance/payments-logger/frontend/src/auth.js
/volume2/docker/finance/dsk-uploader/notion_connector/resources/__init__.py
/volume2/docker/finance/dsk-uploader/notion_connector/resources/block.py
/volume2/docker/finance/dsk-uploader/notion_connector/resources/block_property.py
/volume2/docker/finance/dsk-uploader/notion_connector/resources/database.py
/volume2/docker/finance/dsk-uploader/notion_connector/resources/database_property.py
/volume2/docker/finance/dsk-uploader/notion_connector/resources/filter_builder.py
/volume2/docker/finance/dsk-uploader/notion_connector/resources/page.py
/volume2/docker/finance/dsk-uploader/notion_connector/resources/page_property.py
/volume2/docker/finance/dsk-uploader/notion_connector/resources/search.py
/volume2/docker/finance/payments-logger/backend/src/routes/payments.js
/volume2/docker/finance/dsk-uploader/notion_connector/exceptions/__init__.py
/volume2/docker/finance/dsk-uploader/notion_connector/exceptions/exceptions.py
Read
AuthProvider.jsx
AuthProvider.jsx
Read
PaymentTable.jsx
PaymentTable.jsx
Read
FilterBar.jsx
FilterBar.jsx
Read
auth.js
auth.js
Read
auth.js
auth.js
Read
index.js
index.js
Read
Dockerfile
Dockerfile
Read
Dockerfile
Dockerfile
Read
migration.sql
migration.sql
Bash
IN
find /volume2/docker/finance/payments-logger -name "docker-compose.yml" -o -name ".env*" -o -name "package.json" | head -20
Copy code to clipboard
OUT
/volume2/docker/finance/payments-logger/.env
/volume2/docker/finance/payments-logger/.env.example
/volume2/docker/finance/payments-logger/docker-compose.yml
/volume2/docker/finance/payments-logger/backend/package.json
/volume2/docker/finance/payments-logger/frontend/package.json
/volume2/docker/finance/payments-logger/auth/.env
/volume2/docker/finance/payments-logger/auth/.env.example
Bash
IN
find /volume2/docker/finance/payments-logger -name "schema.prisma" -type f
Copy code to clipboard
OUT
/volume2/docker/finance/payments-logger/backend/prisma/schema.prisma
Read
docker-compose.yml
docker-compose.yml
Read
.env
.env
Read
.env.example
.env.example
Read
schema.prisma
schema.prisma
Bash
IN
ls -la /volume2/docker/finance/payments-logger/auth/ && echo "---" && find /volume2/docker/finance/payments-logger -name "Dockerfile*" | head -10
Copy code to clipboard
OUT
total 16
drwxrwxrwx 1 Adm1n admin 64 May 8 21:07 .
drwxrwxrwx 1 Adm1n admin 170 May 8 21:07 ..
drwxrwxrwx 1 Adm1n admin 0 May 8 21:07 certs
drwxrwxrwx 1 Adm1n admin 0 May 8 21:07 db
-rwxrwxrwx 1 Adm1n admin 949 May 8 21:07 .env
-rwxrwxrwx 1 Adm1n admin 2258 May 8 21:07 .env.example
-rwxrwxrwx 1 Adm1n admin 5501 May 8 21:07 README.md
---
/volume2/docker/finance/payments-logger/backend/Dockerfile
/volume2/docker/finance/payments-logger/frontend/Dockerfile
Bash
IN
cd /volume2/docker/finance/payments-logger && tree -L 3 -I 'node_modules|.next|dist|build' --charset ascii 2>/dev/null || find . -not -path '*/node_modules/*' -not -path '*/.git/*' -not -path '*/dist/*' -type f | head -60
Copy code to clipboard
OUT
.
|-- API.md
|-- auth
| |-- certs
| |-- db
| `-- README.md
|-- backend
| |-- Dockerfile
| |-- package.json
| |-- prisma
| | |-- migrations
| | `-- schema.prisma
| `-- src
| |-- auth.js
| |-- index.js
| |-- parser.js
| `-- routes
|-- docker-compose.yml
|-- frontend
| |-- Dockerfile
| |-- index.html
| |-- package.json
| |-- postcss.config.js
| |-- src
| | |-- App.jsx
| | |-- auth.js
| | |-- components
| | |-- index.css
| | `-- main.jsx
| |-- tailwind.config.js
| `-- vite.config.js
`-- README.md
12 directories, 20 files
Read
.env
.env
Read
.env.example
.env.example
Read
Dockerfile
Dockerfile
Read
Dockerfile
Dockerfile
Bash
IN
head -100 /volume2/docker/finance/payments-logger/backend/package.json && echo "---FRONTEND---" && head -100 /volume2/docker/finance/payments-logger/frontend/package.json
Copy code to clipboard
OUT
{
"name": "payments-logger-backend",
"version": "1.0.0",
"description": "Payment SMS logger backend",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js",
"prisma:generate": "prisma generate",
"prisma:migrate": "prisma migrate deploy",
"prisma:migrate:dev": "prisma migrate dev"
},
"dependencies": {
"@prisma/client": "^5.22.0",
"bcryptjs": "^2.4.3",
"cors": "^2.8.5",
"express": "^4.21.1",
"express-rate-limit": "^7.4.0",
"jose": "^5.9.6",
"morgan": "^1.10.0"
},
"devDependencies": {
"nodemon": "^3.1.7",
"prisma": "^5.22.0"
}
}
---FRONTEND---
{
"name": "payments-logger-frontend",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"lucide-react": "^0.460.0",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/react": "^18.3.12",
"@vitejs/plugin-react": "^4.3.4",
"autoprefixer": "^10.4.20",
"postcss": "^8.4.49",
"tailwindcss": "^3.4.15",
"vite": "^6.0.1"
}
}
Read
payments.js
payments.js
Bash
IN
find /volume2/docker/finance -name "*.md" -type f | xargs grep -l "auth\|Authentik\|OAuth\|OIDC" 2>/dev/null | head -5
Copy code to clipboard
OUT
/volume2/docker/finance/payments-logger/API.md
/volume2/docker/finance/auth/README.md
/volume2/docker/finance/auth/auth/README.md
/volume2/docker/finance/payments-logger/auth/README.md
Read
API.md
API.md
Bash
IN
head -50 /volume2/docker/finance/payments-logger/frontend/src/main.jsx
Copy code to clipboard
OUT
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { AuthProvider } from './components/AuthProvider';
import './index.css';
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<AuthProvider>
<App />
</AuthProvider>
</React.StrictMode>
);
Bash
IN
find /volume2/docker/finance/payments-logger/frontend/src -name "*.jsx" -o -name "*.js" | head -20
Copy code to clipboard
OUT
/volume2/docker/finance/payments-logger/frontend/src/App.jsx
/volume2/docker/finance/payments-logger/frontend/src/auth.js
/volume2/docker/finance/payments-logger/frontend/src/main.jsx
/volume2/docker/finance/payments-logger/frontend/src/components/AuthProvider.jsx
/volume2/docker/finance/payments-logger/frontend/src/components/FilterBar.jsx
/volume2/docker/finance/payments-logger/frontend/src/components/PaymentCard.jsx
/volume2/docker/finance/payments-logger/frontend/src/components/PaymentList.jsx
/volume2/docker/finance/payments-logger/frontend/src/components/PaymentTable.jsx
Read
AuthProvider.jsx
AuthProvider.jsx
Read
AuthProvider.jsx
AuthProvider.jsx
Bash
IN
head -50 /volume2/docker/finance/payments-logger/frontend/src/App.jsx
Copy code to clipboard
OUT
import React, { useState, useEffect, useCallback } from 'react';
import { CreditCard, RefreshCw, LogOut } from 'lucide-react';
import FilterBar from './components/FilterBar';
import PaymentTable from './components/PaymentTable';
import { useAuth } from './components/AuthProvider';
const API_BASE = '/api/payments';
export default function App() {
const { logout, getToken } = useAuth();
const [payments, setPayments] = useState([]);
const [total, setTotal] = useState(0);
const [page, setPage] = useState(1);
const [filters, setFilters] = useState({});
const [sortBy, setSortBy] = useState('createdAt');
const [sortDir, setSortDir] = useState('desc');
const [filterOptions, setFilterOptions] = useState({ types: [], recipients: [], tags: [] });
const [loading, setLoading] = useState(false);
const authFetch = useCallback(async (url, options = {}) => {
const token = await getToken();
const headers = { ...(options.headers || {}) };
if (token) headers['Authorization'] = `Bearer ${token}`;
return fetch(url, { ...options, headers });
}, [getToken]);
const fetchPayments = useCallback(async () => {
setLoading(true);
try {
const params = new URLSearchParams();
params.set('page', page);
params.set('limit', 50);
params.set('sortBy', sortBy);
params.set('sortDir', sortDir);
Object.entries(filters).forEach(([key, val]) => {
if (val) params.set(key, val);
});
const res = await authFetch(`${API_BASE}?${params}`);
const data = await res.json();
setPayments(data.payments || []);
setTotal(data.total || 0);
} catch (err) {
console.error('Failed to fetch payments:', err);
} finally {
setLoading(false);
}
}, [page, filters, sortBy, sortDir, authFetch]);
const fetchFilterOptions = useCallback(async () => {
try {
Read
docker-compose.yml
docker-compose.yml
Read
Dockerfile
Dockerfile
Read
.env.example
.env.example
Read
app.py
app.py
Read
app_flask.py
app_flask.py
Read
dskuploader.py
dskuploader.py
Read
client.py
client.py
Read
database.py
database.py
Read
index.html
index.html
Read
base.html
base.html
Read
result.html
result.html
Read
page_property.py
page_property.py
Read
USAGE.md
USAGE.md
Bash
IN
find /volume2/docker/finance/dsk-uploader -type f \( -name "*.py" -o -name "*.json" \) | grep -E "(exceptions|page\.py)" | head -10
Copy code to clipboard
OUT
/volume2/docker/finance/dsk-uploader/notion_connector/exceptions/__init__.py
/volume2/docker/finance/dsk-uploader/notion_connector/exceptions/exceptions.py
/volume2/docker/finance/dsk-uploader/notion_connector/resources/page.py
Read
page.py
page.py
Read
exceptions.py
exceptions.py
Bash
IN
tree -L 3 /volume2/docker/finance/dsk-uploader 2>/dev/null | head -80 || find /volume2/docker/finance/dsk-uploader -type d -not -path '.*/.git/*' | sort
Copy code to clipboard
OUT
/volume2/docker/finance/dsk-uploader
├── app_flask.py
├── app.py
├── docker-compose.yml
├── Dockerfile
├── dskuploader.py
├── notion_connector
│ ├── client.py
│ ├── exceptions
│ │ ├── exceptions.py
│ │ └── __init__.py
│ ├── __init__.py
│ └── resources
│ ├── block_property.py
│ ├── block.py
│ ├── database_property.py
│ ├── database.py
│ ├── filter_builder.py
│ ├── __init__.py
│ ├── page_property.py
│ ├── page.py
│ └── search.py
├── README.md
├── requirements.txt
├── templates
│ ├── base.html
│ ├── index.html
│ └── result.html
└── USAGE.md
5 directories, 24 files
Read
README.md
README.md
Read
API.md
API.md
Thinking
Thinking
Now I have a complete picture of all three. Let me design the plan.
Agent:
Design combined app architecture
IN
Design a detailed implementation plan for a new combined web app that merges two existing applications. Here is full context:
---
## App 1: payments-logger (Node.js)
- **Purpose**: Ingest Bulgarian bank SMS → parse → store in PostgreSQL → review/tag/notify in React UI
- **Stack**: Node.js 20 + Express + Prisma 5 + PostgreSQL 16 + React 18 + Vite + Tailwind CSS
- **Auth**: Custom JWT (bcryptjs + jose), tokens in localStorage
- **Ingest**: POST /api/payments/ingest (public) — SMS text OR structured JSON (Apple Wallet)
- **Schema** (PostgreSQL via Prisma):
- `payments` table: id, raw_message, date, type (POS/ATM/INTERNET/ECOM/P2P/WALLET), card, recipient, amount, balance, status (UNPROCESSED/SENT/SKIPPED), notifyPhone, notifiedAt, created_at, updated_at
- `tags` table: id, name, color — M2M with payments via `_PaymentToTag`
- `users` table: id, username, hashed_password (this will be REMOVED)
- **UI**: Single-page React app — PaymentTable (sortable, filterable, taggable), FilterBar, status actions (send/skip), notification system
- **Parser** (backend/src/parser.js): Regex parser for Bulgarian DSK Bank SMS, extracts date/time (DD/MM/YYYY HH:MM), card mask, transaction type, recipient, amount, balance
## App 2: dsk-uploader (Python/Flask)
- **Purpose**: Upload DSK bank CSV exports → parse/normalize → upload to Notion database
- **Stack**: Python 3.11 + Flask + Pandas + Custom Notion SDK + Bootstrap 5
- **Auth**: None (open)
- **CSV format** (DSK Bank Bulgarian format, columns):
- `Дата` (date, DD.MM.YYYY)
- `Вид на трансакцията` (transaction type, Bulgarian)
- `Основание` (reason/description — contains card number regex: `^\d{6}x{6}\d{4}$`)
- `Дебит BGN` (debit amount, may be empty)
- `Кредит BGN` (credit amount, may be empty)
- `Наредител/Получател` (orderer/recipient name)
- `Номер сметка на наредителя / получателя` (account number)
- **Processing**: merge multiple CSVs, normalize dates, extract card numbers from reason via regex, auto-generate tags (keyword heuristics: ЗАПЛАТА→Salary, NETFLIX→Subscriptions, etc.), filter internal transfers
- **Output**: Notion database pages (this will be REPLACED with local PostgreSQL)
## App 3: auth (Authentik)
- **Mode**: Proxy mode via NPM (forward auth)
- **How it works**: NPM intercepts all requests, calls Authentik outpost's auth endpoint. On success, NPM injects headers into proxied request:
- `X-authentik-username`
- `X-authentik-email`
- `X-authentik-groups`
- **No code integration needed** in the app itself — just trust these headers from NPM
- **Logout**: Redirect user to `/outpost.goauthentik.io/sign_out`
---
## What the New Combined App Must Do
1. **Single PostgreSQL database** for all transactions
2. **SMS Ingest** (public endpoint) — same as payments-logger /ingest, source=INGEST
3. **CSV Upload** (authenticated) — parse DSK CSV files, store transactions with source=UPLOAD into the same DB schema
4. **Unified UI** — show all payments in one table regardless of source
5. **Source indicator** in UI — badge showing "INGEST", "UPLOAD", or "BOTH" (if duplicate detection added)
6. **Source filter** in FilterBar — filter by All/Ingest/Upload
7. **Authentik auth** — remove custom JWT entirely; trust X-authentik-* headers from NPM
8. **All existing payments-logger features**: tagging, send notification, skip, status tracking, filters, sorting, pagination
9. **Remove Notion dependency entirely** — all data stays in local PostgreSQL
---
## Technical Constraints
- Keep Node.js backend (not Python) — extend payments-logger's stack
- CSV parsing: use `csv-parse` npm package (handles encoding, streaming)
- File upload: use `multer` npm middleware
- Auth middleware: read X-authentik-username header, 401 if missing (but /api/payments/ingest stays public)
- Add `source` enum field (INGEST/UPLOAD) to payments schema
- Add `currency` field (EUR for SMS ingest, BGN for CSV uploads) — or just store as-is
- Remove `users` table from schema
---
## Please Design
1. Complete folder structure for the new app (suggest name: "finance-hub" or similar — note this is a placeholder, user will confirm)
2. Prisma schema with new fields (`source`, `currency`)
3. All backend API routes
4. CSV parser design in Node.js (port of the Python logic)
5. Authentik auth middleware
6. Frontend component structure (React) — what's reused from payments-logger, what's new
7. Docker Compose setup
8. Environment variables needed
9. Step-by-step implementation order
10. Verification checklist
Be specific about file paths and code structure. This will be used to write actual implementation code.
Bash
List all files in finance directory
IN
find /volume2/docker/finance -type f | sort | head -100
Copy code to clipboard
OUT
/volume2/docker/finance/auth/auth/db/base/1/112
/volume2/docker/finance/auth/auth/db/base/1/113
/volume2/docker/finance/auth/auth/db/base/1/1247
/volume2/docker/finance/auth/auth/db/base/1/1247_fsm
/volume2/docker/finance/auth/auth/db/base/1/1247_vm
/volume2/docker/finance/auth/auth/db/base/1/1249
/volume2/docker/finance/auth/auth/db/base/1/1249_fsm
/volume2/docker/finance/auth/auth/db/base/1/1249_vm
/volume2/docker/finance/auth/auth/db/base/1/1255
/volume2/docker/finance/auth/auth/db/base/1/1255_fsm
/volume2/docker/finance/auth/auth/db/base/1/1255_vm
/volume2/docker/finance/auth/auth/db/base/1/1259
/volume2/docker/finance/auth/auth/db/base/1/1259_fsm
/volume2/docker/finance/auth/auth/db/base/1/1259_vm
/volume2/docker/finance/auth/auth/db/base/1/13457
/volume2/docker/finance/auth/auth/db/base/1/13457_fsm
/volume2/docker/finance/auth/auth/db/base/1/13457_vm
/volume2/docker/finance/auth/auth/db/base/1/13460
/volume2/docker/finance/auth/auth/db/base/1/13461
/volume2/docker/finance/auth/auth/db/base/1/13462
/volume2/docker/finance/auth/auth/db/base/1/13462_fsm
/volume2/docker/finance/auth/auth/db/base/1/13462_vm
/volume2/docker/finance/auth/auth/db/base/1/13465
/volume2/docker/finance/auth/auth/db/base/1/13466
/volume2/docker/finance/auth/auth/db/base/1/13467
/volume2/docker/finance/auth/auth/db/base/1/13467_fsm
/volume2/docker/finance/auth/auth/db/base/1/13467_vm
/volume2/docker/finance/auth/auth/db/base/1/13470
/volume2/docker/finance/auth/auth/db/base/1/13471
/volume2/docker/finance/auth/auth/db/base/1/13472
/volume2/docker/finance/auth/auth/db/base/1/13472_fsm
/volume2/docker/finance/auth/auth/db/base/1/13472_vm
/volume2/docker/finance/auth/auth/db/base/1/13475
/volume2/docker/finance/auth/auth/db/base/1/13476
/volume2/docker/finance/auth/auth/db/base/1/1417
/volume2/docker/finance/auth/auth/db/base/1/1418
/volume2/docker/finance/auth/auth/db/base/1/174
/volume2/docker/finance/auth/auth/db/base/1/175
/volume2/docker/finance/auth/auth/db/base/1/2187
/volume2/docker/finance/auth/auth/db/base/1/2224
/volume2/docker/finance/auth/auth/db/base/1/2228
/volume2/docker/finance/auth/auth/db/base/1/2328
/volume2/docker/finance/auth/auth/db/base/1/2336
/volume2/docker/finance/auth/auth/db/base/1/2337
/volume2/docker/finance/auth/auth/db/base/1/2579
/volume2/docker/finance/auth/auth/db/base/1/2600
/volume2/docker/finance/auth/auth/db/base/1/2600_fsm
/volume2/docker/finance/auth/auth/db/base/1/2600_vm
/volume2/docker/finance/auth/auth/db/base/1/2601
/volume2/docker/finance/auth/auth/db/base/1/2601_fsm
/volume2/docker/finance/auth/auth/db/base/1/2601_vm
/volume2/docker/finance/auth/auth/db/base/1/2602
/volume2/docker/finance/auth/auth/db/base/1/2602_fsm
/volume2/docker/finance/auth/auth/db/base/1/2602_vm
/volume2/docker/finance/auth/auth/db/base/1/2603
/volume2/docker/finance/auth/auth/db/base/1/2603_fsm
/volume2/docker/finance/auth/auth/db/base/1/2603_vm
/volume2/docker/finance/auth/auth/db/base/1/2604
/volume2/docker/finance/auth/auth/db/base/1/2605
/volume2/docker/finance/auth/auth/db/base/1/2605_fsm
/volume2/docker/finance/auth/auth/db/base/1/2605_vm
/volume2/docker/finance/auth/auth/db/base/1/2606
/volume2/docker/finance/auth/auth/db/base/1/2606_fsm
/volume2/docker/finance/auth/auth/db/base/1/2606_vm
/volume2/docker/finance/auth/auth/db/base/1/2607
/volume2/docker/finance/auth/auth/db/base/1/2607_fsm
/volume2/docker/finance/auth/auth/db/base/1/2607_vm
/volume2/docker/finance/auth/auth/db/base/1/2608
/volume2/docker/finance/auth/auth/db/base/1/2608_fsm
/volume2/docker/finance/auth/auth/db/base/1/2608_vm
/volume2/docker/finance/auth/auth/db/base/1/2609
/volume2/docker/finance/auth/auth/db/base/1/2609_fsm
/volume2/docker/finance/auth/auth/db/base/1/2609_vm
/volume2/docker/finance/auth/auth/db/base/1/2610
/volume2/docker/finance/auth/auth/db/base/1/2610_fsm
/volume2/docker/finance/auth/auth/db/base/1/2610_vm
/volume2/docker/finance/auth/auth/db/base/1/2611
/volume2/docker/finance/auth/auth/db/base/1/2612
/volume2/docker/finance/auth/auth/db/base/1/2612_fsm
/volume2/docker/finance/auth/auth/db/base/1/2612_vm
/volume2/docker/finance/auth/auth/db/base/1/2613
/volume2/docker/finance/auth/auth/db/base/1/2615
/volume2/docker/finance/auth/auth/db/base/1/2615_fsm
/volume2/docker/finance/auth/auth/db/base/1/2615_vm
/volume2/docker/finance/auth/auth/db/base/1/2616
/volume2/docker/finance/auth/auth/db/base/1/2616_fsm
/volume2/docker/finance/auth/auth/db/base/1/2616_vm
/volume2/docker/finance/auth/auth/db/base/1/2617
/volume2/docker/finance/auth/auth/db/base/1/2617_fsm
/volume2/docker/finance/auth/auth/db/base/1/2617_vm
/volume2/docker/finance/auth/auth/db/base/1/2618
/volume2/docker/finance/auth/auth/db/base/1/2618_fsm
/volume2/docker/finance/auth/auth/db/base/1/2618_vm
/volume2/docker/finance/auth/auth/db/base/1/2619
/volume2/docker/finance/auth/auth/db/base/1/2619_fsm
/volume2/docker/finance/auth/auth/db/base/1/2619_vm
/volume2/docker/finance/auth/auth/db/base/1/2620
/volume2/docker/finance/auth/auth/db/base/1/2650
/volume2/docker/finance/auth/auth/db/base/1/2651
/volume2/docker/finance/auth/auth/db/base/1/2652
Bash
List docker directory contents
IN
ls -la /volume2/docker/
Copy code to clipboard
OUT
total 40
drwxrwxrwx 1 root root 1160 May 8 21:05 .
drwxr-xr-x 1 root root 246 Apr 6 19:54 ..
drwxrwxrwx 1 Adm1n admin 20 Jul 28 2025 adguard
drwxrwxrwx 1 Adm1n admin 66 Apr 5 13:14 ai-stack
drwxrwxrwx 1 Adm1n admin 12 Aug 1 2025 app-db
drwxrwxr-x 1 appflowy users 138 Dec 14 18:21 appflowy
drwxrwxrwx 1 Adm1n admin 72 May 6 14:55 audiobookshelf
drwxrwxrwx 1 Adm1n admin 128 Mar 30 19:52 auth
drwxrwxrwx 1 Adm1n admin 102 May 8 21:02 beszel
drwxrwxrwx 1 Adm1n admin 38 Jun 16 2025 bitwarden
drwxrwxrwx 1 Adm1n admin 36 Aug 25 2025 dawarich
drwxrwxrwx 1 Adm1n admin 322 Aug 15 2025 dsk-uploader
-rwxrwxrwx 1 Adm1n admin 10244 Oct 29 2025 .DS_Store
drwxrwxrwx 1 Adm1n admin 62 May 8 21:10 finance
drwxrwxrwx 1 Adm1n admin 92 Aug 19 2025 flask-app
drwxrwxrwx 1 Adm1n admin 308 Oct 7 2025 garmin-connector
drwxrwxrwx 1 Adm1n admin 12 Jul 18 2025 gitea
drwxrwxrwx 1 Adm1n admin 0 Feb 16 19:30 health
drwxrwxrwx 1 Adm1n admin 220 Feb 16 21:09 health-tracker
drwxrwxrwx 1 Adm1n admin 0 Oct 31 2025 homarr
drwxrwxrwx 1 Adm1n admin 146 Mar 7 20:46 hst
drwxrwxrwx 1 Adm1n admin 66 Aug 31 2025 immich
drwxrwx--- 1 Adm1n Media 30 Jun 15 2025 jellyfinht
drwxrwxrwx 1 Adm1n admin 20 Aug 31 2025 kavita
drwxrwxrwx 1 Adm1n admin 0 Oct 12 2025 libreoffice
drwxrwxrwx 1 Adm1n admin 12 Dec 13 21:12 linkwarden
drwxrwxrwx 1 Adm1n admin 274 Apr 9 19:39 location-logger
drwxrwxrwx 1 dnsmasq systemd-journal 432 Aug 27 2025 mariadb
drwxrwxrwx 1 Adm1n admin 122 Apr 26 19:03 meeting-detector
drwxrwxrwx 1 Adm1n admin 0 Aug 15 2025 mindfulmama
drwxrwxrwx 1 Adm1n admin 22 Jul 16 2025 n8n
drwxrwxrwx 1 Adm1n admin 176 Feb 20 17:33 notifier-app
drwxrwxrwx 1 Adm1n admin 52 Jun 15 2025 npm
drwxrwxrwx 1 Adm1n admin 306 Mar 29 17:34 oauth
drwxrwxrwx 1 Adm1n admin 92 Jun 15 2025 obsidian
drwxr-xr-x 1 root root 60 Mar 7 20:56 ollama
drwxr-xr-x 1 911 911 128 Jul 28 2025 openttd
drwxrwxrwx 1 Adm1n admin 234 Mar 7 16:30 openvpn-client
drwxr-xr-x 1 root root 58 May 2 23:15 open-webui
drwxrwxrwx 1 Adm1n admin 134 Dec 31 13:13 orchestrator
drwxrwxrwx 1 Adm1n admin 406 Mar 25 20:39 outfit-app
drwxrwxrwx 1 Adm1n admin 90 Aug 28 2025 owntracks-stack
drwxrwxrwx 1 Adm1n admin 156 Mar 10 20:51 paperlessngx
drwxrwxrwx 1 Adm1n admin 162 May 8 20:36 payments-logger
drwxrwxrwx 1 Adm1n admin 0 Sep 28 2025 personal-log
drwxrwxrwx 1 Adm1n admin 616 Mar 7 20:46 personal-log-system
drwxrwxrwx 1 Adm1n admin 26 Feb 19 19:41 player
drwxrwxrwx 1 Adm1n admin 202 Feb 23 21:35 portainer
drwxrwxrwx 1 dnsmasq admin 484 Dec 4 19:31 portnotedb
drwxrwxrwx 1 Adm1n admin 140 Apr 4 15:49 reminders-app
drwxrwxrwx 1 Adm1n admin 60 Oct 29 2025 romm
drwxrwxrwx 1 Adm1n admin 108 Feb 23 20:15 second-brain
drwxrwxrwx 1 Adm1n admin 10 Dec 30 17:16 static
drwxrwxrwx 1 Adm1n admin 28 Jun 19 2025 stirling
drwxrwxrwx 1 Adm1n admin 86 Oct 25 2025 syncthing
drwxrwxrwx 1 root root 56 Jun 5 2025 tailscale
drwxrwxrwx 1 Adm1n admin 186 Sep 23 2025 temp-logger
drwxrwxrwx 1 Adm1n admin 122 Jul 19 2025 test-app
drwxrwxrwx 1 Adm1n admin 52 Jun 14 2025 tmp
drwxrwxrwx 1 Adm1n admin 36 Jul 13 2025 torrent-stack
drwxrwxrwx 1 Adm1n admin 48 Dec 19 10:58 tree
drwxrwxrwx 1 Adm1n admin 0 Oct 31 2025 trilium
drwxrwxrwx 1 Adm1n admin 34 Dec 3 21:18 tubearchivist
drwxrwxrwx 1 Adm1n admin 22 Jul 25 2025 twenty
drwxrwxrwx 1 Adm1n admin 0 Nov 2 2025 uptimekuma
drwxrwxrwx 1 Adm1n admin 30 Dec 7 17:30 ytptube
Bash
List all files in payments-logger directory
IN
find /volume2/docker/payments-logger -type f | sort
Copy code to clipboard
OUT
/volume2/docker/payments-logger/API.md
/volume2/docker/payments-logger/backend/Dockerfile
/volume2/docker/payments-logger/backend/.dockerignore
/volume2/docker/payments-logger/backend/package.json
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_init/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260210_simplify/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260222_add_card/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/20260508_add_users/migration.sql
/volume2/docker/payments-logger/backend/prisma/migrations/migration_lock.toml
/volume2/docker/payments-logger/backend/prisma/schema.prisma
/volume2/docker/payments-logger/backend/src/auth.js
/volume2/docker/payments-logger/backend/src/index.js
/volume2/docker/payments-logger/backend/src/parser.js
/volume2/docker/payments-logger/backend/src/routes/payments.js
/volume2/docker/payments-logger/.claude/settings.local.json
/volume2/docker/payments-logger/docker-compose.yml
/volume2/docker/payments-logger/.env
/volume2/docker/payments-logger/.env.example
/volume2/docker/payments-logger/frontend/Dockerfile
/volume2/docker/payments-logger/frontend/.dockerignore
/volume2/docker/payments-logger/frontend/index.html
/volume2/docker/payments-logger/frontend/package.json
/volume2/docker/payments-logger/frontend/postcss.config.js
/volume2/docker/payments-logger/frontend/src/App.jsx
/volume2/docker/payments-logger/frontend/src/auth.js
/volume2/docker/payments-logger/frontend/src/components/AuthProvider.jsx
/volume2/docker/payments-logger/frontend/src/components/FilterBar.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentCard.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentList.jsx
/volume2/docker/payments-logger/frontend/src/components/PaymentTable.jsx
/volume2/docker/payments-logger/frontend/src/index.css
/volume2/docker/payments-logger/frontend/src/main.jsx
/volume2/docker/payments-logger/frontend/tailwind.config.js
/volume2/docker/payments-logger/frontend/vite.config.js
/volume2/docker/payments-logger/.gitignore
/volume2/docker/payments-logger/README.md
Bash
List all files in dsk-uploader directory
IN
find /volume2/docker/dsk-uploader -type f | sort
Copy code to clipboard
OUT
/volume2/docker/dsk-uploader/app_flask.py
/volume2/docker/dsk-uploader/app.py
/volume2/docker/dsk-uploader/docker-compose.yml
/volume2/docker/dsk-uploader/Dockerfile
/volume2/docker/dsk-uploader/.dockerignore
/volume2/docker/dsk-uploader/dskuploader.py
/volume2/docker/dsk-uploader/.env
/volume2/docker/dsk-uploader/.env.example
/volume2/docker/dsk-uploader/.git/COMMIT_EDITMSG
/volume2/docker/dsk-uploader/.git/config
/volume2/docker/dsk-uploader/.git/description
/volume2/docker/dsk-uploader/.git/FETCH_HEAD
/volume2/docker/dsk-uploader/.git/HEAD
/volume2/docker/dsk-uploader/.git/hooks/applypatch-msg.sample
/volume2/docker/dsk-uploader/.git/hooks/commit-msg.sample
/volume2/docker/dsk-uploader/.git/hooks/fsmonitor-watchman.sample
/volume2/docker/dsk-uploader/.git/hooks/post-update.sample
/volume2/docker/dsk-uploader/.git/hooks/pre-applypatch.sample
/volume2/docker/dsk-uploader/.git/hooks/pre-commit.sample
/volume2/docker/dsk-uploader/.git/hooks/pre-merge-commit.sample
/volume2/docker/dsk-uploader/.git/hooks/prepare-commit-msg.sample
/volume2/docker/dsk-uploader/.git/hooks/pre-push.sample
/volume2/docker/dsk-uploader/.git/hooks/pre-rebase.sample
/volume2/docker/dsk-uploader/.git/hooks/pre-receive.sample
/volume2/docker/dsk-uploader/.git/hooks/push-to-checkout.sample
/volume2/docker/dsk-uploader/.git/hooks/update.sample
/volume2/docker/dsk-uploader/.gitignore
/volume2/docker/dsk-uploader/.git/index
/volume2/docker/dsk-uploader/.git/info/exclude
/volume2/docker/dsk-uploader/.git/logs/HEAD
/volume2/docker/dsk-uploader/.git/logs/refs/heads/main
/volume2/docker/dsk-uploader/.git/logs/refs/remotes/origin/HEAD
/volume2/docker/dsk-uploader/.git/logs/refs/remotes/origin/main
/volume2/docker/dsk-uploader/.git/objects/0b/918bed65202bedaa9fa092e539d607be2eea65
/volume2/docker/dsk-uploader/.git/objects/11/b908125d2f0feebf7aca6d24e127f334bce611
/volume2/docker/dsk-uploader/.git/objects/56/a2766ae5422b18e5b1a418fd231ad12fef08e6
/volume2/docker/dsk-uploader/.git/objects/65/386fd3b4ac62094500e21c23845d05b9d18a4f
/volume2/docker/dsk-uploader/.git/objects/7b/2d7b18213f9516ec4544f309772ee4808146bb
/volume2/docker/dsk-uploader/.git/objects/7c/3f071fef98751a68b7d93779f76cf5d5aa8ebf
/volume2/docker/dsk-uploader/.git/objects/85/b5483672f68c327c39ea8c29e94ae8b22b7bbf
/volume2/docker/dsk-uploader/.git/objects/8e/a1cbf78eae8a86c5990d0582db1847c0226b56
/volume2/docker/dsk-uploader/.git/objects/ed/8e93af8cc77c7a85f87a9f37573c51b839e571
/volume2/docker/dsk-uploader/.git/objects/ee/3d5f92e57deec809abda371386e371f32de9bb
/volume2/docker/dsk-uploader/.git/objects/f3/98248da8f4911d463d9a33155fcf58a65092cc
/volume2/docker/dsk-uploader/.git/objects/pack/pack-ed5aca57f7f3b56e67172d9fb90e685087770006.idx
/volume2/docker/dsk-uploader/.git/objects/pack/pack-ed5aca57f7f3b56e67172d9fb90e685087770006.pack
/volume2/docker/dsk-uploader/.git/ORIG_HEAD
/volume2/docker/dsk-uploader/.git/packed-refs
/volume2/docker/dsk-uploader/.git/refs/heads/main
/volume2/docker/dsk-uploader/.git/refs/remotes/origin/HEAD
/volume2/docker/dsk-uploader/.git/refs/remotes/origin/main
/volume2/docker/dsk-uploader/notion_connector/client.py
/volume2/docker/dsk-uploader/notion_connector/exceptions/exceptions.py
/volume2/docker/dsk-uploader/notion_connector/exceptions/__init__.py
/volume2/docker/dsk-uploader/notion_connector/__init__.py
/volume2/docker/dsk-uploader/notion_connector/resources/block_property.py
/volume2/docker/dsk-uploader/notion_connector/resources/block.py
/volume2/docker/dsk-uploader/notion_connector/resources/database_property.py
/volume2/docker/dsk-uploader/notion_connector/resources/database.py
/volume2/docker/dsk-uploader/notion_connector/resources/filter_builder.py
/volume2/docker/dsk-uploader/notion_connector/resources/__init__.py
/volume2/docker/dsk-uploader/notion_connector/resources/page_property.py
/volume2/docker/dsk-uploader/notion_connector/resources/page.py
/volume2/docker/dsk-uploader/notion_connector/resources/search.py
/volume2/docker/dsk-uploader/README.md
/volume2/docker/dsk-uploader/requirements.txt
/volume2/docker/dsk-uploader/templates/base.html
/volume2/docker/dsk-uploader/templates/index.html
/volume2/docker/dsk-uploader/templates/result.html
/volume2/docker/dsk-uploader/USAGE.md
Read
schema.prisma
schema.prisma
Read
parser.js
parser.js
Read
index.js
index.js
Read
auth.js
auth.js
Read
payments.js
payments.js
Read
package.json
package.json
Read
docker-compose.yml
docker-compose.yml
Read
.env.example
.env.example
Read
App.jsx
App.jsx
Read
FilterBar.jsx
FilterBar.jsx
Read
PaymentTable.jsx
PaymentTable.jsx
Read
AuthProvider.jsx
AuthProvider.jsx
Read
auth.js
auth.js
Read
app.py
app.py
Read
dskuploader.py
dskuploader.py
Read
app_flask.py
app_flask.py
Read
package.json
package.json
Read
vite.config.js
vite.config.js
Read
Dockerfile
Dockerfile
Read
Dockerfile
Dockerfile
Read
migration.sql
migration.sql
Read
migration.sql
migration.sql
Read
migration.sql
migration.sql
Read
migration.sql
migration.sql
Read
API.md
API.md
Read
docker-compose.yml
docker-compose.yml
Read
PaymentCard.jsx
PaymentCard.jsx
Read
PaymentList.jsx
PaymentList.jsx
Read
tailwind.config.js
tailwind.config.js
Read
main.jsx
main.jsx...
|
11153
|
NULL
|
NULL
|
NULL
|
|
11989
|
534
|
20
|
2026-05-09T08:15:17.293352+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-09/1778 /Users/lukas/.screenpipe/data/data/2026-05-09/1778314517293_m2.jpg...
|
Firefox
|
File Upload
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Favorites
jiminny
Recents
Applications
Documents
D Favorites
jiminny
Recents
Applications
Documents
Downloads
lukas
iCloud
iCloud Drive
Sync folder
Locations
DXP4800PLUS-B5F
Eject
Network
Tags
CRM
Orange
Red
Yellow
Green
Blue
Purple
All Tags…
Name
Size
Kind
Date Added
report(2).csv
3 KB
CSV Document
Today at 11:09
report(1).csv
1 KB
CSV Document
Today at 10:04
favicon.ico
5 KB
Windows icon image
24 Apr 2026 at 16:53
27022026_0000000026574472_SWIFT_OB72702260049200.pdf
92 KB
PDF Document
23 Apr 2026 at 13:08
03042026_0000000026574472_SWIFT_OB70304260021608.pdf
92 KB
PDF Document
23 Apr 2026 at 13:08
mazanoke-images-YWJ6
--
Folder
23 Apr 2026 at 13:02
mazanoke-images-YWJ6.zip
7,2 MB
ZIP archive
23 Apr 2026 at 13:02
OrionInstaller.dmg
2,2 MB
Disk Image
8 Apr 2026 at 20:35
ПО-22221726037035-004-001_ORGES.pdf
192 KB
PDF Document
26 Mar 2026 at 11:24
%D0%9F%D0%9E-22221726037035-004-001_archive.zip
148 KB
ZIP archive
26 Mar 2026 at 11:24
ПО-22221726037035-004-001_archive (1).zip
148 KB
ZIP archive
26 Mar 2026 at 11:24
ПО-22221726037035-004-001_archive.zip
148 KB
ZIP archive
26 Mar 2026 at 11:23
first_aid_notes_complete.docx
3 KB
Word 2007 (.docx) Document
18 Mar 2026 at 15:29
license.bettertouchtool
928 bytes
bttlicense
18 Mar 2026 at 11:55
KeychronAssist-1.0.2 (1).dmg
10,1 MB
Disk Image
17 Mar 2026 at 20:27
KeychronAssist-1.0.2.dmg
10,1 MB
Disk Image
17 Mar 2026 at 20:26
Zoom.pkg
56,4 MB
Installer flat package
13 Mar 2026 at 19:43
macOS_Storage_Cleanup.md
6 KB...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Favorites","depth":6,"bounds":{"left":0.37167552,"top":0.1859537,"width":0.04920213,"height":0.015163607},"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"jiminny","depth":6,"bounds":{"left":0.37965426,"top":0.20590582,"width":0.03656915,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Recents","depth":6,"bounds":{"left":0.37965426,"top":0.22825219,"width":0.03656915,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Applications","depth":6,"bounds":{"left":0.37965426,"top":0.25059855,"width":0.03656915,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Documents","depth":6,"bounds":{"left":0.37965426,"top":0.27294493,"width":0.03656915,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Downloads","depth":6,"bounds":{"left":0.37965426,"top":0.2952913,"width":0.03656915,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"lukas","depth":6,"bounds":{"left":0.37965426,"top":0.31763768,"width":0.03656915,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"iCloud","depth":6,"bounds":{"left":0.37167552,"top":0.34557062,"width":0.04920213,"height":0.015163607},"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"iCloud Drive","depth":6,"bounds":{"left":0.37965426,"top":0.36552274,"width":0.03656915,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Sync folder","depth":6,"bounds":{"left":0.37965426,"top":0.38786912,"width":0.03656915,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Locations","depth":6,"bounds":{"left":0.37167552,"top":0.41580206,"width":0.04920213,"height":0.015163607},"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"DXP4800PLUS-B5F","depth":6,"bounds":{"left":0.37965426,"top":0.43575418,"width":0.03025266,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Eject","depth":6,"bounds":{"left":0.4105718,"top":0.43735036,"width":0.0043218085,"height":0.009577015},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXStaticText","text":"Network","depth":6,"bounds":{"left":0.37965426,"top":0.45810056,"width":0.03656915,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Tags","depth":6,"bounds":{"left":0.37167552,"top":0.48603353,"width":0.04920213,"height":0.015163607},"on_screen":true,"automation_id":"xSidebarHeader","role_description":"text"},{"role":"AXStaticText","text":"CRM","depth":6,"bounds":{"left":0.37965426,"top":0.5059856,"width":0.03656915,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Orange","depth":6,"bounds":{"left":0.37965426,"top":0.528332,"width":0.03656915,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Red","depth":6,"bounds":{"left":0.37965426,"top":0.5506784,"width":0.03656915,"height":0.012769354},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Yellow","depth":6,"bounds":{"left":0.37965426,"top":0.57302475,"width":0.03656915,"height":0.012769354},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Green","depth":6,"bounds":{"left":0.37965426,"top":0.5953711,"width":0.03656915,"height":0.012769354},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Blue","depth":6,"bounds":{"left":0.37965426,"top":0.6177175,"width":0.03656915,"height":0.012769354},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Purple","depth":6,"bounds":{"left":0.37965426,"top":0.6400638,"width":0.03656915,"height":0.012769354},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"All Tags…","depth":6,"bounds":{"left":0.37965426,"top":0.6624102,"width":0.03656915,"height":0.012769354},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"Name","depth":7,"bounds":{"left":0.4368351,"top":0.23064645,"width":0.011635638,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Size","depth":7,"bounds":{"left":0.50099736,"top":0.23064645,"width":0.008976064,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Kind","depth":7,"bounds":{"left":0.53324467,"top":0.23064645,"width":0.00930851,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Date Added","depth":7,"bounds":{"left":0.57147604,"top":0.23064645,"width":0.022606382,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"report(2).csv","depth":7,"bounds":{"left":0.4368351,"top":0.25379092,"width":0.028922873,"height":0.012769354},"on_screen":true,"value":"report(2).csv","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3 KB","depth":7,"bounds":{"left":0.51894945,"top":0.25379092,"width":0.010970744,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"CSV Document","depth":7,"bounds":{"left":0.53324467,"top":0.25379092,"width":0.031914894,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Today at 11:09","depth":7,"bounds":{"left":0.57147604,"top":0.25379092,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"report(1).csv","depth":7,"bounds":{"left":0.4368351,"top":0.2697526,"width":0.028590426,"height":0.012769354},"on_screen":true,"value":"report(1).csv","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"1 KB","depth":7,"bounds":{"left":0.51894945,"top":0.2697526,"width":0.010970744,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"CSV Document","depth":7,"bounds":{"left":0.53324467,"top":0.2697526,"width":0.031914894,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Today at 10:04","depth":7,"bounds":{"left":0.57147604,"top":0.2697526,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"favicon.ico","depth":7,"bounds":{"left":0.4368351,"top":0.2857143,"width":0.024601065,"height":0.012769354},"on_screen":true,"value":"favicon.ico","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5 KB","depth":7,"bounds":{"left":0.51894945,"top":0.2857143,"width":0.010970744,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Windows icon image","depth":7,"bounds":{"left":0.53324467,"top":0.2857143,"width":0.034906916,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"24 Apr 2026 at 16:53","depth":7,"bounds":{"left":0.57147604,"top":0.2857143,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"27022026_0000000026574472_SWIFT_OB72702260049200.pdf","depth":7,"bounds":{"left":0.4368351,"top":0.30167598,"width":0.060837764,"height":0.012769354},"on_screen":true,"value":"27022026_0000000026574472_SWIFT_OB72702260049200.pdf","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"92 KB","depth":7,"bounds":{"left":0.5162899,"top":0.30167598,"width":0.013630319,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"PDF Document","depth":7,"bounds":{"left":0.53324467,"top":0.30167598,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"23 Apr 2026 at 13:08","depth":7,"bounds":{"left":0.57147604,"top":0.30167598,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"03042026_0000000026574472_SWIFT_OB70304260021608.pdf","depth":7,"bounds":{"left":0.4368351,"top":0.31763768,"width":0.060837764,"height":0.012769354},"on_screen":true,"value":"03042026_0000000026574472_SWIFT_OB70304260021608.pdf","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"92 KB","depth":7,"bounds":{"left":0.5162899,"top":0.31763768,"width":0.013630319,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"PDF Document","depth":7,"bounds":{"left":0.53324467,"top":0.31763768,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"23 Apr 2026 at 13:08","depth":7,"bounds":{"left":0.57147604,"top":0.31763768,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"mazanoke-images-YWJ6","depth":7,"bounds":{"left":0.4368351,"top":0.33359936,"width":0.05319149,"height":0.012769354},"on_screen":true,"value":"mazanoke-images-YWJ6","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"--","depth":7,"bounds":{"left":0.52460104,"top":0.33359936,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Folder","depth":7,"bounds":{"left":0.53324467,"top":0.33359936,"width":0.014295213,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"23 Apr 2026 at 13:02","depth":7,"bounds":{"left":0.57147604,"top":0.33359936,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"mazanoke-images-YWJ6.zip","depth":7,"bounds":{"left":0.4368351,"top":0.34956107,"width":0.06017287,"height":0.012769354},"on_screen":true,"value":"mazanoke-images-YWJ6.zip","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"7,2 MB","depth":7,"bounds":{"left":0.5142952,"top":0.34956107,"width":0.015957447,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ZIP archive","depth":7,"bounds":{"left":0.53324467,"top":0.34956107,"width":0.025265958,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"23 Apr 2026 at 13:02","depth":7,"bounds":{"left":0.57147604,"top":0.34956107,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"OrionInstaller.dmg","depth":7,"bounds":{"left":0.4368351,"top":0.36552274,"width":0.03956117,"height":0.012769354},"on_screen":true,"value":"OrionInstaller.dmg","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"2,2 MB","depth":7,"bounds":{"left":0.5142952,"top":0.36552274,"width":0.015957447,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Disk Image","depth":7,"bounds":{"left":0.53324467,"top":0.36552274,"width":0.023603724,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"8 Apr 2026 at 20:35","depth":7,"bounds":{"left":0.57147604,"top":0.36552274,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"ПО-22221726037035-004-001_ORGES.pdf","depth":7,"bounds":{"left":0.4368351,"top":0.38148445,"width":0.060837764,"height":0.012769354},"on_screen":true,"value":"ПО-22221726037035-004-001_ORGES.pdf","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"192 KB","depth":7,"bounds":{"left":0.51363033,"top":0.38148445,"width":0.016289894,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"PDF Document","depth":7,"bounds":{"left":0.53324467,"top":0.38148445,"width":0.032912236,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"26 Mar 2026 at 11:24","depth":7,"bounds":{"left":0.57147604,"top":0.38148445,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"%D0%9F%D0%9E-22221726037035-004-001_archive.zip","depth":7,"bounds":{"left":0.4368351,"top":0.39744613,"width":0.060837764,"height":0.012769354},"on_screen":true,"value":"%D0%9F%D0%9E-22221726037035-004-001_archive.zip","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"148 KB","depth":7,"bounds":{"left":0.51363033,"top":0.39744613,"width":0.016289894,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ZIP archive","depth":7,"bounds":{"left":0.53324467,"top":0.39744613,"width":0.025265958,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"26 Mar 2026 at 11:24","depth":7,"bounds":{"left":0.57147604,"top":0.39744613,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"ПО-22221726037035-004-001_archive (1).zip","depth":7,"bounds":{"left":0.4368351,"top":0.41340783,"width":0.060837764,"height":0.012769354},"on_screen":true,"value":"ПО-22221726037035-004-001_archive (1).zip","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"148 KB","depth":7,"bounds":{"left":0.51363033,"top":0.41340783,"width":0.016289894,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ZIP archive","depth":7,"bounds":{"left":0.53324467,"top":0.41340783,"width":0.025265958,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"26 Mar 2026 at 11:24","depth":7,"bounds":{"left":0.57147604,"top":0.41340783,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"ПО-22221726037035-004-001_archive.zip","depth":7,"bounds":{"left":0.4368351,"top":0.4293695,"width":0.060837764,"height":0.012769354},"on_screen":true,"value":"ПО-22221726037035-004-001_archive.zip","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"148 KB","depth":7,"bounds":{"left":0.51363033,"top":0.4293695,"width":0.016289894,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ZIP archive","depth":7,"bounds":{"left":0.53324467,"top":0.4293695,"width":0.025265958,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"26 Mar 2026 at 11:23","depth":7,"bounds":{"left":0.57147604,"top":0.4293695,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"first_aid_notes_complete.docx","depth":7,"bounds":{"left":0.4368351,"top":0.44533122,"width":0.060837764,"height":0.012769354},"on_screen":true,"value":"first_aid_notes_complete.docx","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3 KB","depth":7,"bounds":{"left":0.51894945,"top":0.44533122,"width":0.010970744,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Word 2007 (.docx) Document","depth":7,"bounds":{"left":0.53324467,"top":0.44533122,"width":0.034906916,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"18 Mar 2026 at 15:29","depth":7,"bounds":{"left":0.57147604,"top":0.44533122,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"license.bettertouchtool","depth":7,"bounds":{"left":0.4368351,"top":0.4612929,"width":0.049534574,"height":0.012769354},"on_screen":true,"value":"license.bettertouchtool","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"928 bytes","depth":7,"bounds":{"left":0.50831115,"top":0.4612929,"width":0.021941489,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"bttlicense","depth":7,"bounds":{"left":0.53324467,"top":0.4612929,"width":0.021276595,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"18 Mar 2026 at 11:55","depth":7,"bounds":{"left":0.57147604,"top":0.4612929,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"KeychronAssist-1.0.2 (1).dmg","depth":7,"bounds":{"left":0.4368351,"top":0.4772546,"width":0.060837764,"height":0.012769354},"on_screen":true,"value":"KeychronAssist-1.0.2 (1).dmg","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10,1 MB","depth":7,"bounds":{"left":0.51163566,"top":0.4772546,"width":0.01861702,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Disk Image","depth":7,"bounds":{"left":0.53324467,"top":0.4772546,"width":0.023603724,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"17 Mar 2026 at 20:27","depth":7,"bounds":{"left":0.57147604,"top":0.4772546,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"KeychronAssist-1.0.2.dmg","depth":7,"bounds":{"left":0.4368351,"top":0.49321628,"width":0.054853722,"height":0.012769354},"on_screen":true,"value":"KeychronAssist-1.0.2.dmg","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"10,1 MB","depth":7,"bounds":{"left":0.51163566,"top":0.49321628,"width":0.01861702,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Disk Image","depth":7,"bounds":{"left":0.53324467,"top":0.49321628,"width":0.023603724,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"17 Mar 2026 at 20:26","depth":7,"bounds":{"left":0.57147604,"top":0.49321628,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"Zoom.pkg","depth":7,"bounds":{"left":0.4368351,"top":0.509178,"width":0.022938829,"height":0.012769354},"on_screen":true,"value":"Zoom.pkg","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"56,4 MB","depth":7,"bounds":{"left":0.51163566,"top":0.509178,"width":0.01861702,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Installer flat package","depth":7,"bounds":{"left":0.53324467,"top":0.509178,"width":0.034906916,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"13 Mar 2026 at 19:43","depth":7,"bounds":{"left":0.57147604,"top":0.509178,"width":0.056848403,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXTextField","text":"macOS_Storage_Cleanup.md","depth":7,"bounds":{"left":0.4368351,"top":0.5251397,"width":0.060837764,"height":0.012769354},"on_screen":true,"value":"macOS_Storage_Cleanup.md","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"6 KB","depth":7,"bounds":{"left":0.51894945,"top":0.5251397,"width":0.010970744,"height":0.012769354},"on_screen":true,"role_description":"text"}]...
|
-7743967201670688176
|
7652340403126598259
|
click
|
accessibility
|
NULL
|
Favorites
jiminny
Recents
Applications
Documents
D Favorites
jiminny
Recents
Applications
Documents
Downloads
lukas
iCloud
iCloud Drive
Sync folder
Locations
DXP4800PLUS-B5F
Eject
Network
Tags
CRM
Orange
Red
Yellow
Green
Blue
Purple
All Tags…
Name
Size
Kind
Date Added
report(2).csv
3 KB
CSV Document
Today at 11:09
report(1).csv
1 KB
CSV Document
Today at 10:04
favicon.ico
5 KB
Windows icon image
24 Apr 2026 at 16:53
27022026_0000000026574472_SWIFT_OB72702260049200.pdf
92 KB
PDF Document
23 Apr 2026 at 13:08
03042026_0000000026574472_SWIFT_OB70304260021608.pdf
92 KB
PDF Document
23 Apr 2026 at 13:08
mazanoke-images-YWJ6
--
Folder
23 Apr 2026 at 13:02
mazanoke-images-YWJ6.zip
7,2 MB
ZIP archive
23 Apr 2026 at 13:02
OrionInstaller.dmg
2,2 MB
Disk Image
8 Apr 2026 at 20:35
ПО-22221726037035-004-001_ORGES.pdf
192 KB
PDF Document
26 Mar 2026 at 11:24
%D0%9F%D0%9E-22221726037035-004-001_archive.zip
148 KB
ZIP archive
26 Mar 2026 at 11:24
ПО-22221726037035-004-001_archive (1).zip
148 KB
ZIP archive
26 Mar 2026 at 11:24
ПО-22221726037035-004-001_archive.zip
148 KB
ZIP archive
26 Mar 2026 at 11:23
first_aid_notes_complete.docx
3 KB
Word 2007 (.docx) Document
18 Mar 2026 at 15:29
license.bettertouchtool
928 bytes
bttlicense
18 Mar 2026 at 11:55
KeychronAssist-1.0.2 (1).dmg
10,1 MB
Disk Image
17 Mar 2026 at 20:27
KeychronAssist-1.0.2.dmg
10,1 MB
Disk Image
17 Mar 2026 at 20:26
Zoom.pkg
56,4 MB
Installer flat package
13 Mar 2026 at 19:43
macOS_Storage_Cleanup.md
6 KB...
|
11987
|
NULL
|
NULL
|
NULL
|
|
9390
|
424
|
38
|
2026-05-08T12:45:28.307519+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778244328307_m2.jpg...
|
Firefox
|
Jy 20820 es reindex stream model hydration by Vasi Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app — Work...
|
True
|
github.com/jiminny/app/pull/12059/changes#diff-f77 github.com/jiminny/app/pull/12059/changes#diff-f77c5793308caa3e764a033422493121a1329dd953a89f3dde4a9386622f22f9...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Unnamed Group
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS] -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Collapse
Listen
Show more options
Show thinking
Gemini said
Gemini said
Overview
Overview
This diff refactors the
LoadDocumentsAction
class to optimize memory usage and data processing. It transitions the database query execution from batch chunking to lazy loading using cursors, introduces explicit memory management techniques, and updates the class structure to use dependency injection.
Architectural & Structural Changes
Architectural & Structural Changes
Dependency Injection:
Injected
EntityQueryBuilder
via the constructor instead of calling it statically.
Removed Traits & Constants:
Removed the
SkipActivityTrait
entirely (and its associated skip logic), as well as the
RDS_CHUNK_SIZE
constant.
Namespace Imports:
Added the
Throwable
import and removed
Illuminate\Support\Collection
.
Data Processing Refactor
Data Processing Refactor
Cursor Implementation:
Replaced
chunkByIdDesc
with
cursor()
, iterating through records sequentially rather than loading batches of 250 into memory.
Simplified Deletion Checks:
Replaced Laravel collection filtering (
whereNotNull('deleted_at')
) with a direct
$entityModel->isDeleted()
check on each model during iteration.
Removed Skip Logic:
Removed the
shouldSkipActivity
check, meaning all non-deleted models are now directly processed for updates.
Exception Handling:
Updated the catch block to use the imported
Throwable
interface rather than the fully qualified
\Throwable
.
Memory Optimization
Memory Optimization
Explicit Garbage Collection:
Added specific cleanup steps inside the iteration loop. Dropping loaded relationships (
$entityModel->setRelations([])
) and unsetting the model (
unset($entityModel)
) explicitly signals the PHP Garbage Collector to free and recycle heap memory, preventing excessive OS memory allocation during large stream hydration.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said You are seasoned code reviewer and your task is to make detailed code review of summarized page. First understand the code changes, then evaluate it and try to find potential issues and bottlenecks.
You said
You are seasoned code reviewer and your task is to make detailed code
review of summarized page. First understand the code changes, then
evaluate it and try to find potential issues and bottlenecks.
Expand
Show more options
Addressing Memory Issues
Gemini said
Gemini said
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Stop response
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (33)
Pull requests
(
33
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (2)
Security and quality
(
2
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
Jy 20820 es reindex stream model hydration #12059 Edit title
Jy 20820 es reindex stream model hydration
#
12059
Edit title
Preview
Preview
Awaiting approval
Awaiting approval
Code
Code
Open
Vasil-Jiminny
Vasil-Jiminny
wants to merge 35 commits into
master
master
from
JY-20820-es-reindex-stream-model-hydration
JY-20820-es-reindex-stream-model-hydration
Copy head branch name to clipboard
Lines changed: 363 additions & 140 deletions
Conversation (8)
Conversation
(
8
)
Commits (35)
Commits
(
35
)
Checks (3)
Checks
(
3
)
Files changed (12)
Files changed
(
12
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
Open
Jy 20820 es reindex stream model hydration
Jy 20820 es reindex stream model hydration
#
12059
All commits
All commits
Vasil-Jiminny
Vasil-Jiminny
wants to merge 35 commits into
master
master
from
JY-20820-es-reindex-stream-model-hydration
JY-20820-es-reindex-stream-model-hydration
Copy head branch name to clipboard
5 of 12 files viewed
Awaiting approval
Awaiting approval
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
0
)
Filter files…
Filter options
File tree
File tree
app
Component
ElasticSearch/Contract
Searchable.php
Searchable.php
ES
Processor
Actions
LoadDocumentsAction.php
Traits
SkipActivityTrait.php
EntityQueryBuilder.php
EntityQueryBuilder.php...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.2237367,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.23703457,"top":0.06304868,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Unnamed Group","depth":4,"bounds":{"left":0.2265625,"top":0.08978452,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"bounds":{"left":0.2265625,"top":0.11332801,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"bounds":{"left":0.23969415,"top":0.1245012,"width":0.4644282,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"bounds":{"left":0.2265625,"top":0.14604948,"width":0.07679521,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"bounds":{"left":0.23969415,"top":0.15722266,"width":0.4644282,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"bounds":{"left":0.2237367,"top":0.17877094,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"bounds":{"left":0.23703457,"top":0.18994413,"width":0.10721409,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.21149242,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.22266561,"width":0.17037898,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Feed — jiminny — Sentry","depth":4,"bounds":{"left":0.2237367,"top":0.2442139,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Feed — jiminny — Sentry","depth":5,"bounds":{"left":0.23703457,"top":0.25538707,"width":0.042719416,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20818 move ask jiminny reports to its own datadog metric by LakyLak · Pull Request #12056 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.27693537,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20818 move ask jiminny reports to its own datadog metric by LakyLak · Pull Request #12056 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.28810853,"width":0.18899602,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Ask Jiminny Report Generated","depth":4,"bounds":{"left":0.2237367,"top":0.30965683,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Ask Jiminny Report Generated","depth":5,"bounds":{"left":0.23703457,"top":0.32083002,"width":0.07164229,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.3423783,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.35355148,"width":0.19331782,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Problem loading page","depth":4,"bounds":{"left":0.2237367,"top":0.37509975,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Problem loading page","depth":5,"bounds":{"left":0.23703457,"top":0.38627294,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Search the CRM - HubSpot docs","depth":4,"bounds":{"left":0.2237367,"top":0.40782124,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search the CRM - HubSpot docs","depth":5,"bounds":{"left":0.23703457,"top":0.41899443,"width":0.05651596,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.2237367,"top":0.4405427,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.23703457,"top":0.4517159,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.2237367,"top":0.47326416,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.23703457,"top":0.48443735,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.2237367,"top":0.5059856,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.23703457,"top":0.5171588,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI Features | Datadog","depth":4,"bounds":{"left":0.2237367,"top":0.5387071,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI Features | Datadog","depth":5,"bounds":{"left":0.23703457,"top":0.54988027,"width":0.037400264,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20493 smart instant nudge pre filtering by nikolaybiaivanov · Pull Request #12053 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.5714286,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20493 smart instant nudge pre filtering by nikolaybiaivanov · Pull Request #12053 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.5826017,"width":0.17037898,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.60415006,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.61532325,"width":0.039228722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":4,"bounds":{"left":0.2237367,"top":0.6368715,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":5,"bounds":{"left":0.23703457,"top":0.6480447,"width":0.16888298,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.29105717,"top":0.6440543,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.2265625,"top":0.6711891,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.2265625,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.23753324,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.2486702,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.25980717,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.27094415,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.4084109,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.42037898,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.41771942,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.3073471,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.38979387,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.40309176,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.30302528,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.30302528,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\\Component\\ES\\Processor\\Actions;5namespace Jiminny\\Component\\ES\\Processor\\Actions;667use Elastica\\Document;7use Elastica\\Document;8-use Illuminate\\Support\\Collection;9use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;8use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;10use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;9use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;11use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;10use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;12use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;11use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;13-use Jiminny\\Component\\ES\\Processor\\Traits\\SkipActivityTrait;14use Jiminny\\Exceptions\\SyncActivityException;12use Jiminny\\Exceptions\\SyncActivityException;15use Jiminny\\Models\\Model;13use Jiminny\\Models\\Model;16use Sentry\\Laravel\\Facade as Sentry;14use Sentry\\Laravel\\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\\Component\\ES\\Processor\\Actions;5namespace Jiminny\\Component\\ES\\Processor\\Actions;667use Elastica\\Document;7use Elastica\\Document;8-use Illuminate\\Support\\Collection;9use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;8use Jiminny\\Component\\ElasticSearch\\Contract\\Searchable;10use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;9use Jiminny\\Component\\ES\\Processor\\DTOs\\DocumentLoad;11use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;10use Jiminny\\Component\\ES\\Processor\\DTOs\\SimpleCollection;12use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;11use Jiminny\\Component\\ES\\Processor\\EntityQueryBuilder;13-use Jiminny\\Component\\ES\\Processor\\Traits\\SkipActivityTrait;14use Jiminny\\Exceptions\\SyncActivityException;12use Jiminny\\Exceptions\\SyncActivityException;15use Jiminny\\Models\\Model;13use Jiminny\\Models\\Model;16use Sentry\\Laravel\\Facade as Sentry;14use Sentry\\Laravel\\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Overview","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Overview","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"This diff refactors the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"LoadDocumentsAction","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"class to optimize memory usage and data processing. It transitions the database query execution from batch chunking to lazy loading using cursors, introduces explicit memory management techniques, and updates the class structure to use dependency injection.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Architectural & Structural Changes","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Architectural & Structural Changes","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Dependency Injection:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Injected","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EntityQueryBuilder","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"via the constructor instead of calling it statically.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Traits & Constants:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SkipActivityTrait","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entirely (and its associated skip logic), as well as the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"RDS_CHUNK_SIZE","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"constant.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Namespace Imports:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"import and removed","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Illuminate\\Support\\Collection","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Data Processing Refactor","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Data Processing Refactor","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Cursor Implementation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"chunkByIdDesc","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cursor()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", iterating through records sequentially rather than loading batches of 250 into memory.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Simplified Deletion Checks:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Replaced Laravel collection filtering (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"whereNotNull('deleted_at')","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") with a direct","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel->isDeleted()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"check on each model during iteration.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed Skip Logic:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Removed the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"shouldSkipActivity","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"check, meaning all non-deleted models are now directly processed for updates.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Exception Handling:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated the catch block to use the imported","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"interface rather than the fully qualified","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\\Throwable","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Memory Optimization","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Memory Optimization","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Explicit Garbage Collection:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Added specific cleanup steps inside the iteration loop. Dropping loaded relationships (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$entityModel->setRelations([])","depth":27,"bounds":{"left":0.32978722,"top":0.0,"width":0.08377659,"height":0.014764565},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and unsetting the model (","depth":26,"bounds":{"left":0.3259641,"top":0.0,"width":0.10239362,"height":0.057861134},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"unset($entityModel)","depth":27,"bounds":{"left":0.32978722,"top":0.0035913808,"width":0.05319149,"height":0.014764565},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") explicitly signals the PHP Garbage Collector to free and recycle heap memory, preventing excessive OS memory allocation during large stream hydration.","depth":26,"bounds":{"left":0.3259641,"top":0.0023942539,"width":0.10239362,"height":0.09936153},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"bounds":{"left":0.31000665,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"bounds":{"left":0.32064494,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"bounds":{"left":0.33128324,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"bounds":{"left":0.34192154,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"bounds":{"left":0.35255983,"top":0.12290503,"width":0.010638298,"height":0.025538707},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"bounds":{"left":0.3259641,"top":0.18355946,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"bounds":{"left":0.34059176,"top":0.18355946,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said You are seasoned code reviewer and your task is to make detailed code review of summarized page. First understand the code changes, then evaluate it and try to find potential issues and bottlenecks.","depth":21,"bounds":{"left":0.36053857,"top":0.19313647,"width":0.051861703,"height":0.09577015},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"bounds":{"left":0.30302528,"top":0.19393456,"width":0.019946808,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You are seasoned code reviewer and your task is to make detailed code","depth":23,"bounds":{"left":0.36053857,"top":0.19473264,"width":0.047872342,"height":0.073822826},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"review of summarized page. First understand the code changes, then","depth":23,"bounds":{"left":0.36053857,"top":0.27134877,"width":0.04886968,"height":0.073822826},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"evaluate it and try to find potential issues and bottlenecks.","depth":23,"bounds":{"left":0.36053857,"top":0.2905028,"width":0.049700797,"height":0.054668795},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"bounds":{"left":0.41240028,"top":0.19313647,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"bounds":{"left":0.41771942,"top":0.31524342,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Addressing Memory Issues","depth":25,"bounds":{"left":0.32662898,"top":0.32322428,"width":0.058843084,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"bounds":{"left":0.32430187,"top":0.36472467,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"bounds":{"left":0.32430187,"top":0.36671987,"width":0.04105718,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextArea","text":"Enter a prompt for Gemini\nencrypted","depth":20,"bounds":{"left":0.31665558,"top":0.8216281,"width":0.10638298,"height":0.01915403},"on_screen":true,"value":"Enter a prompt for Gemini\nencrypted","help_text":"","role_description":"text entry area","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enter a prompt for Gemini","depth":21,"bounds":{"left":0.32330453,"top":0.82202715,"width":0.069980055,"height":0.018355945},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"encrypted","depth":21,"bounds":{"left":0.31565824,"top":0.8216281,"width":0.0066489363,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open upload file menu","depth":20,"bounds":{"left":0.31266624,"top":0.8575419,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tools","depth":18,"bounds":{"left":0.32862368,"top":0.8575419,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open mode picker","depth":20,"bounds":{"left":0.3856383,"top":0.85514766,"width":0.026097074,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pro","depth":23,"bounds":{"left":0.39095744,"top":0.8639266,"width":0.007480053,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Stop response","depth":19,"bounds":{"left":0.41306517,"top":0.85434955,"width":0.013962766,"height":0.033519555},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.","depth":17,"bounds":{"left":0.30884308,"top":0.90901834,"width":0.11951463,"height":0.025139665},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Your privacy & Gemini Opens in a new window","depth":17,"bounds":{"left":0.39079124,"top":0.92178774,"width":0.040059842,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your privacy & Gemini","depth":18,"bounds":{"left":0.39079124,"top":0.92178774,"width":0.040059842,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Opens in a new window","depth":19,"bounds":{"left":0.30302528,"top":0.92098963,"width":0.043218084,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Summarize page","depth":7,"bounds":{"left":0.30867687,"top":0.95730245,"width":0.053523935,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summarize page","depth":9,"bounds":{"left":0.31432846,"top":0.96249,"width":0.042220745,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Skip to content","depth":7,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":8,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":11,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":10,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":10,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"All issues(g then i)","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All pull requests","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All repositories","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":10,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":10,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (33)","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"33","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality (2)","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":13,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":11,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":11,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":12,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":11,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":10,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Jy 20820 es reindex stream model hydration #12059 Edit title","depth":13,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jy 20820 es reindex stream model hydration","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12059","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Preview","depth":13,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Preview","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Awaiting approval","depth":13,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Awaiting approval","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"on_screen":false,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Code","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vasil-Jiminny","depth":15,"on_screen":false,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vasil-Jiminny","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 35 commits into","depth":15,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"on_screen":false,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20820-es-reindex-stream-model-hydration","depth":16,"on_screen":false,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20820-es-reindex-stream-model-hydration","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 363 additions & 140 deletions","depth":14,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (8)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Conversation","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Commits (35)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Commits","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"35","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Checks (3)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Files changed (12)","depth":16,"on_screen":false,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Files changed","depth":17,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull Request Toolbar","depth":14,"bounds":{"left":0.44980052,"top":0.075019956,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull Request Toolbar","depth":15,"bounds":{"left":0.44980052,"top":0.077813245,"width":0.030086435,"height":0.08060654},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse file tree","depth":14,"bounds":{"left":0.44980052,"top":0.06424581,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Open","depth":14,"bounds":{"left":0.47240692,"top":0.06863528,"width":0.011968086,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jy 20820 es reindex stream model hydration","depth":14,"bounds":{"left":0.49102393,"top":0.057462092,"width":0.100398935,"height":0.016759777},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20820 es reindex stream model hydration","depth":16,"bounds":{"left":0.49102393,"top":0.05905826,"width":0.100398935,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"bounds":{"left":0.5940825,"top":0.05905826,"width":0.0028257978,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12059","depth":15,"bounds":{"left":0.5969083,"top":0.05905826,"width":0.013630319,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"All commits","depth":14,"bounds":{"left":0.48836437,"top":0.07102953,"width":0.03374335,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All commits","depth":16,"bounds":{"left":0.49135637,"top":0.07621708,"width":0.02244016,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vasil-Jiminny","depth":15,"bounds":{"left":0.52642953,"top":0.075019956,"width":0.02642952,"height":0.014365523},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vasil-Jiminny","depth":16,"bounds":{"left":0.52642953,"top":0.07621708,"width":0.02642952,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 35 commits into","depth":15,"bounds":{"left":0.55418885,"top":0.07621708,"width":0.06050532,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"bounds":{"left":0.61602396,"top":0.07342378,"width":0.018284574,"height":0.017557861},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"bounds":{"left":0.6180186,"top":0.07661612,"width":0.014295213,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"bounds":{"left":0.6356383,"top":0.07621708,"width":0.00880984,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20820-es-reindex-stream-model-hydration","depth":16,"bounds":{"left":0.64577794,"top":0.07342378,"width":0.10472074,"height":0.017557861},"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20820-es-reindex-stream-model-hydration","depth":17,"bounds":{"left":0.6477726,"top":0.07661612,"width":0.10073138,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"bounds":{"left":0.75182843,"top":0.07102953,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5 of 12 files viewed","depth":15,"bounds":{"left":0.813996,"top":0.07661612,"width":0.014960106,"height":0.08060654},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Awaiting approval","depth":14,"bounds":{"left":0.85355717,"top":0.06424581,"width":0.04654255,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Awaiting approval","depth":16,"bounds":{"left":0.86319816,"top":0.06943336,"width":0.033909574,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Submit review","depth":14,"bounds":{"left":0.9027593,"top":0.06424581,"width":0.03856383,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Submit","depth":16,"bounds":{"left":0.90575135,"top":0.06943336,"width":0.014793883,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"review","depth":16,"bounds":{"left":0.9205452,"top":0.06943336,"width":0.012466756,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Open diff view settings","depth":14,"bounds":{"left":0.9439827,"top":0.06424581,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open overview panel","depth":14,"bounds":{"left":0.9616024,"top":0.06424581,"width":0.00930851,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open comments panel","depth":14,"bounds":{"left":0.9722407,"top":0.06424581,"width":0.017287234,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"(","depth":16,"bounds":{"left":0.98055184,"top":0.06943336,"width":0.0026595744,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"bounds":{"left":0.98321146,"top":0.06943336,"width":0.0026595744,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":16,"bounds":{"left":0.985871,"top":0.06943336,"width":0.0014960107,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Filter files…","depth":16,"bounds":{"left":0.46110374,"top":0.11332801,"width":0.06815159,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Filter options","depth":16,"bounds":{"left":0.53224736,"top":0.112529926,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"File tree","depth":15,"bounds":{"left":0.45013297,"top":0.15083799,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"File tree","depth":16,"bounds":{"left":0.45013297,"top":0.15363128,"width":0.014295213,"height":0.0518755},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":19,"bounds":{"left":0.4660904,"top":0.15682362,"width":0.008144947,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Component","depth":21,"bounds":{"left":0.46875,"top":0.18276137,"width":0.025099734,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ElasticSearch/Contract","depth":23,"bounds":{"left":0.4714096,"top":0.20830008,"width":0.049035903,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Searchable.php","depth":25,"bounds":{"left":0.47406915,"top":0.23383878,"width":0.03357713,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Searchable.php","depth":26,"bounds":{"left":0.47406915,"top":0.23383878,"width":0.03357713,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ES","depth":23,"bounds":{"left":0.4714096,"top":0.25937748,"width":0.0056515955,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Processor","depth":25,"bounds":{"left":0.47406915,"top":0.28531525,"width":0.021609042,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Actions","depth":27,"bounds":{"left":0.47672874,"top":0.31085396,"width":0.016123671,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"LoadDocumentsAction.php","depth":29,"bounds":{"left":0.4793883,"top":0.3367917,"width":0.05817819,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Traits","depth":27,"bounds":{"left":0.47672874,"top":0.3623304,"width":0.011968086,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SkipActivityTrait.php","depth":29,"bounds":{"left":0.4793883,"top":0.38786912,"width":0.044049203,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"EntityQueryBuilder.php","depth":27,"bounds":{"left":0.47672874,"top":0.41340783,"width":0.049700797,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"EntityQueryBuilder.php","depth":28,"bounds":{"left":0.47672874,"top":0.41340783,"width":0.049700797,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-7742840372806037810
|
-1205540817411868283
|
click
|
accessibility
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Unnamed Group
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS] -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20820 es reindex stream model hydration by Vasi</tabTitle>” with “<selection>@@ -5,69 +5,64 @@5namespace Jiminny\Component\ES\Processor\Actions;5namespace Jiminny\Component\ES\Processor\Actions;667use Elastica\Document;7use Elastica\Document;8-use Illuminate\Support\Collection;9use Jiminny\Component\ElasticSearch\Contract\Searchable;8use Jiminny\Component\ElasticSearch\Contract\Searchable;10use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;9use Jiminny\Component\ES\Processor\DTOs\DocumentLoad;11use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;10use Jiminny\Component\ES\Processor\DTOs\SimpleCollection;12use Jiminny\Component\ES\Processor\EntityQueryBuilder;11use Jiminny\Component\ES\Processor\EntityQueryBuilder;13-use Jiminny\Component\ES\Processor\Traits\SkipActivityTrait;14use Jiminny\Exceptions\SyncActivityException;12use Jiminny\Exceptions\SyncActivityException;15use Jiminny\Models\Model;13use Jiminny\Models\Model;16use Sentry\Laravel\Facade as Sentry;14use Sentry\Laravel\Facade as Sentry;15+use Throwable;171618class LoadDocumentsAction17class LoadDocumentsAction19{18{20-use SkipActivityTrait;19+public function __construct(21-20+private readonly EntityQueryBuilder $queryBuilder22-private const int RDS_CHUNK_SIZE = 250;21+ ) {22+ }232324-/**25- * @codeCoverageIgnore26- */27public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad24public function loadDocuments(string $updateTarget, array $entityIdsList): DocumentLoad28 {25 {29$documentsToUpdate = new SimpleCollection();26$documentsToUpdate = new SimpleCollection();30$documentsToDelete = new SimpleCollection();27$documentsToDelete = new SimpleCollection();312832-// do get mariadb data29+$query = $this->queryBuilder->getEntityQuery($updateTarget, $entityIdsList);33-$query = EntityQueryBuilder::getEntityQuery($updateTarget, $entityIdsList);343035-$query->chunkByIdDesc(31+/** @var Model&Searchable $entityModel */36-self::RDS_CHUNK_SIZE,32+foreach ($query->cursor() as $entityModel) {37-function (Collection $entityModels) use ($documentsToUpdate, $documentsToDelete) {33+if ($entityModel->isDeleted()) {38-/** @var Model&Searchable $entityForDeletion */34+/**39-foreach ($entityModels->whereNotNull('deleted_at') as $entityForDeletion) {35+ * Cleanup (from ElasticSearch) scheduled entities that were recently deleted.40-$documentsToDelete->add($entityForDeletion->getId());36+ * After a deletion, no more updates on a record are expected, so the operation is considered final,41- }37+ * unless the record is restored.42-38+ */43-/** @var Model&Searchable $entityModel */39+$documentsToDelete->add($entityModel->getId());44-foreach ($entityModels->whereNull('deleted_at') as $entityModel) {40+ } else {45-if (self::shouldSkipActivity($entityModel)) {41+try {46-/**42+$documentsToUpdate->add(47- * If the activity type is in the skip list, we should not push it for indexing.43+new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())48- * If an ES record already exists, we should remove it to free up storage and processing power44+ );49- */45+ } catch (Throwable $error) {50-$documentsToDelete->add($entityModel->getId());46+ Sentry::captureException(51-47+new SyncActivityException(52-continue;48+'ES entity async RDS build data failed',53- }49+$error->getCode(),54-50+$error55-try {51+ )56-$documentsToUpdate->add(52+ );57-new Document((string) $entityModel->getId(), $entityModel->getIndexableAttributes())58- );59- } catch (\Throwable $error) {60- Sentry::captureException(61-new SyncActivityException(62-'ES entity async RDS build data failed',63-$error->getCode(),64-$error65- )66- );67- }68 }53 }69 }54 }70- );55+56+/**57+ * Clean up fragmented memory.58+ * Dropping relations and unsetting the entity model after hydration and usage,59+ * allows GC to remove heap memory allocations, and recycle already allocated memory,60+ * instead of allocating more memory from OS.61+ * Unset operations signal GC to collect destroyed object memory62+ */63+$entityModel->setRelations([]);64+ unset($entityModel);65+ }716672return new DocumentLoad($documentsToUpdate, $documentsToDelete);67return new DocumentLoad($documentsToUpdate, $documentsToDelete);73 }68 }</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Collapse
Listen
Show more options
Show thinking
Gemini said
Gemini said
Overview
Overview
This diff refactors the
LoadDocumentsAction
class to optimize memory usage and data processing. It transitions the database query execution from batch chunking to lazy loading using cursors, introduces explicit memory management techniques, and updates the class structure to use dependency injection.
Architectural & Structural Changes
Architectural & Structural Changes
Dependency Injection:
Injected
EntityQueryBuilder
via the constructor instead of calling it statically.
Removed Traits & Constants:
Removed the
SkipActivityTrait
entirely (and its associated skip logic), as well as the
RDS_CHUNK_SIZE
constant.
Namespace Imports:
Added the
Throwable
import and removed
Illuminate\Support\Collection
.
Data Processing Refactor
Data Processing Refactor
Cursor Implementation:
Replaced
chunkByIdDesc
with
cursor()
, iterating through records sequentially rather than loading batches of 250 into memory.
Simplified Deletion Checks:
Replaced Laravel collection filtering (
whereNotNull('deleted_at')
) with a direct
$entityModel->isDeleted()
check on each model during iteration.
Removed Skip Logic:
Removed the
shouldSkipActivity
check, meaning all non-deleted models are now directly processed for updates.
Exception Handling:
Updated the catch block to use the imported
Throwable
interface rather than the fully qualified
\Throwable
.
Memory Optimization
Memory Optimization
Explicit Garbage Collection:
Added specific cleanup steps inside the iteration loop. Dropping loaded relationships (
$entityModel->setRelations([])
) and unsetting the model (
unset($entityModel)
) explicitly signals the PHP Garbage Collector to free and recycle heap memory, preventing excessive OS memory allocation during large stream hydration.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
Edit
You said You are seasoned code reviewer and your task is to make detailed code review of summarized page. First understand the code changes, then evaluate it and try to find potential issues and bottlenecks.
You said
You are seasoned code reviewer and your task is to make detailed code
review of summarized page. First understand the code changes, then
evaluate it and try to find potential issues and bottlenecks.
Expand
Show more options
Addressing Memory Issues
Gemini said
Gemini said
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Stop response
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (33)
Pull requests
(
33
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (2)
Security and quality
(
2
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
Jy 20820 es reindex stream model hydration #12059 Edit title
Jy 20820 es reindex stream model hydration
#
12059
Edit title
Preview
Preview
Awaiting approval
Awaiting approval
Code
Code
Open
Vasil-Jiminny
Vasil-Jiminny
wants to merge 35 commits into
master
master
from
JY-20820-es-reindex-stream-model-hydration
JY-20820-es-reindex-stream-model-hydration
Copy head branch name to clipboard
Lines changed: 363 additions & 140 deletions
Conversation (8)
Conversation
(
8
)
Commits (35)
Commits
(
35
)
Checks (3)
Checks
(
3
)
Files changed (12)
Files changed
(
12
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
Open
Jy 20820 es reindex stream model hydration
Jy 20820 es reindex stream model hydration
#
12059
All commits
All commits
Vasil-Jiminny
Vasil-Jiminny
wants to merge 35 commits into
master
master
from
JY-20820-es-reindex-stream-model-hydration
JY-20820-es-reindex-stream-model-hydration
Copy head branch name to clipboard
5 of 12 files viewed
Awaiting approval
Awaiting approval
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
0
)
Filter files…
Filter options
File tree
File tree
app
Component
ElasticSearch/Contract
Searchable.php
Searchable.php
ES
Processor
Actions
LoadDocumentsAction.php
Traits
SkipActivityTrait.php
EntityQueryBuilder.php
EntityQueryBuilder.php...
|
9389
|
NULL
|
NULL
|
NULL
|
|
7204
|
325
|
2
|
2026-05-08T08:33:23.086521+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778229203086_m1.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReport.php
|
True
|
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
<?php
declare(strict_types=1);
namespace Jiminny\Component\Utility\Service;
use Illuminate\Cache\RateLimiter;
use Jiminny\Contracts\Http\RateLimited;
use Jiminny\Contracts\Http\RateLimitInterface;
class ProviderRateLimiter
{
protected RateLimiter $rateLimiter;
public function __construct(RateLimiter $rateLimiter)
{
$this->rateLimiter = $rateLimiter;
}
public function canMakeRequest(RateLimited $provider): bool
{
/** @var RateLimitInterface $rateLimit */
foreach ($provider->getRateLimits() as $rateLimit) {
$key = $rateLimit->getKey();
if ($this->rateLimiter->tooManyAttempts($key, $rateLimit->getQuota())) {
return false;
}
}
return true;
}
public function requestAvailableIn(RateLimited $provider): int
{
return $provider->getRateLimits()->isNotEmpty()
? $provider->getRateLimits()
->map(fn (RateLimitInterface $rateLimit): int => $this->rateLimiter->availableIn($rateLimit->getKey()))
->max()
: 0
;
}
public function incrementRequestCount(RateLimited $provider): void
{
/** @var RateLimitInterface $rateLimit */
foreach ($provider->getRateLimits() as $rateLimit) {
$this->rateLimiter->hit($rateLimit->getKey(), $rateLimit->getWindow());
}
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
4
1
6
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Carbon;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\AskAnything\AskAnythingPrompt;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Traits\RequiresUUID;
/**
* Jiminny\Models\AutomatedReport
*
* @property int $id
* @property string $uuid
* @property int $team_id
* @property string $type
* @property bool $status
* @property string $frequency
* @property Carbon|null $from
* @property Carbon|null $to
* @property int|null $deal_value_min
* @property int|null $deal_value_max
* @property array $call_types
* @property array $media_types
* @property int|null $call_duration_min
* @property int|null $call_duration_max
* @property array|null $groups
* @property array|null $playbook_categories
* @property array|null $deal_at_call_stages
* @property array|null $current_deal_stages
* @property array $recipients
* @property string|null $additional_prompt_input
* @property string|null $custom_name
* @property int|null $activity_search_id
* @property int|null $ask_anything_prompt_id
* @property Carbon|null $expires_at
* @property Carbon|null $created_at
* @property Carbon|null $updated_at
* @property Carbon|null $deleted_at
* @property-read \Jiminny\Models\Team $team
* @property-read \Jiminny\Models\Activity\Search|null $savedSearch
* @property-read \Jiminny\Models\AskAnything\AskAnythingPrompt|null $askAnythingPrompt
*/
class AutomatedReport extends Model
{
use RequiresUUID;
use SoftDeletes;
protected $table = 'automated_reports';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'team_id',
'type',
'status',
'frequency',
'from',
'to',
'deal_value_min',
'deal_value_max',
'call_types',
'media_types',
'call_duration_min',
'call_duration_max',
'groups',
'playbook_categories',
'deal_at_call_stages',
'current_deal_stages',
'recipients',
'jiminny_recipients',
'additional_prompt_input',
'custom_name',
'created_by',
'activity_search_id',
'ask_anything_prompt_id',
'expires_at',
];
protected $hidden = ['uuid'];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'status' => 'boolean',
'from' => 'datetime',
'to' => 'datetime',
'call_types' => 'array',
'media_types' => 'array',
'groups' => 'array',
'playbook_categories' => 'array',
'deal_at_call_stages' => 'array',
'current_deal_stages' => 'array',
'recipients' => 'array',
'jiminny_recipients' => 'array',
'expires_at' => 'date',
'deleted_at' => 'datetime',
];
}
/**
* Get the team that owns the automated report.
*/
public function team()
{
return $this->belongsTo(Team::class);
}
/**
*
* Get the user who created the report.
*/
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
public function savedSearch(): BelongsTo
{
return $this->belongsTo(Search::class, 'activity_search_id');
}
public function askAnythingPrompt(): BelongsTo
{
return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');
}
public function isAskJiminnyReport(): bool
{
return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;
}
public function isExpired(): bool
{
$expiresAt = $this->getExpiresAt();
return $expiresAt !== null && $expiresAt->isPast();
}
public function canExecute(): bool
{
if ($this->isAskJiminnyReport()) {
return $this->getActivitySearchId() !== null
&& $this->getAskAnythingPromptId() !== null;
}
return true;
}
public function getActivitySearchId(): ?int
{
return $this->getAttribute('activity_search_id');
}
public function getAskAnythingPromptId(): ?int
{
return $this->getAttribute('ask_anything_prompt_id');
}
public function getExpiresAt(): ?Carbon
{
return $this->getAttribute('expires_at');
}
public function getSavedSearch(): ?Search
{
return $this->getAttribute('savedSearch');
}
public function getAskAnythingPrompt(): ?AskAnythingPrompt
{
return $this->getAttribute('askAnythingPrompt');
}
/**
* Get the ID of the automated report.
*
* @return int
*/
public function getId(): int
{
return $this->getAttribute('id');
}
/**
* Get the UUID of the automated report.
*
* @return string
*/
public function getUuid(): string
{
return $this->getAttribute('id_string');
}
/**
* Get the team ID of the automated report.
*
* @return int
*/
public function getTeamId(): int
{
return $this->getAttribute('team_id');
}
/**
* Get the type of the automated report.
*
* @return string
*/
public function getType(): string
{
return $this->getAttribute('type');
}
/**
* Get the status of the automated report.
* True means active, false means inactive.
*
* @return bool
*/
public function getStatus(): bool
{
return $this->getAttribute('status');
}
/**
* Get the frequency of the automated report.
*
* @return string
*/
public function getFrequency(): string
{
return $this->getAttribute('frequency');
}
/**
* Get the from date of the automated report.
*
* @return Carbon|null
*/
public function getFrom(): ?Carbon
{
return $this->getAttribute('from');
}
/**
* Get the to date of the automated report.
*
* @return Carbon|null
*/
public function getTo(): ?Carbon
{
return $this->getAttribute('to');
}
/**
* Get the minimum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMin(): ?int
{
return $this->getAttribute('deal_value_min');
}
/**
* Get the maximum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMax(): ?int
{
return $this->getAttribute('deal_value_max');
}
/**
* Get the call types of the automated report.
*
* @return array
*/
public function getCallTypes(): array
{
return $this->getAttribute('call_types') ?? [];
}
public function getMediaTypes(): array
{
return $this->getAttribute('media_types') ?? [];
}
/**
* Get the minimum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMin(): ?int
{
return $this->getAttribute('call_duration_min');
}
/**
* Get the maximum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMax(): ?int
{
return $this->getAttribute('call_duration_max');
}
/**
* Get the groups of the automated report.
*
* @return array
*/
public function getGroups(): array
{
return $this->getAttribute('groups') ?? [];
}
/**
* Get the playbook categories of the automated report.
*
* @return array
*/
public function getPlaybookCategories(): array
{
return $this->getAttribute('playbook_categories') ?? [];
}
/**
* Get the deal at call stages of the automated report.
*
* @return array
*/
public function getDealAtCallStages(): array
{
return $this->getAttribute('deal_at_call_stages') ?? [];
}
/**
* Get the current deal stages of the automated report.
*
* @return array
*/
public function getCurrentDealStages(): array
{
return $this->getAttribute('current_deal_stages') ?? [];
}
/**
* Get the recipients of the automated report.
*
* @return array
*/
public function getRecipients(): array
{
return $this->getAttribute('recipients') ?? [];
}
/**
* Get the Jiminny's recipients of the automated report.
*
* @return array
*/
public function getJiminnyRecipients(): array
{
return $this->getAttribute('jiminny_recipients') ?? [];
}
/**
* Get the additional prompt input of the automated report.
*
* @return string|null
*/
public function getAdditionalPromptInput(): ?string
{
return $this->getAttribute('additional_prompt_input');
}
public function getCustomName(): ?string
{
return $this->getAttribute('custom_name');
}
/**
* Get the created at date of the automated report.
*
* @return Carbon
*/
public function getCreatedAt(): Carbon
{
return $this->getAttribute('created_at');
}
/**
* Get the updated at date of the automated report.
*
* @return Carbon
*/
public function getUpdatedAt(): Carbon
{
return $this->getAttribute('updated_at');
}
/**
* Get the deleted at date of the automated report.
*
* @return Carbon|null
*/
public function getDeletedAt(): ?Carbon
{
return $this->getAttribute('deleted_at');
}
public function getTeam(): Team
{
return $this->getAttribute('team');
}
public function getCreator(): ?User
{
return $this->getAttribute('creator');
}
}
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":"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},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\Utility\\Service;\n\nuse Illuminate\\Cache\\RateLimiter;\nuse Jiminny\\Contracts\\Http\\RateLimited;\nuse Jiminny\\Contracts\\Http\\RateLimitInterface;\n\nclass ProviderRateLimiter\n{\n protected RateLimiter $rateLimiter;\n\n public function __construct(RateLimiter $rateLimiter)\n {\n $this->rateLimiter = $rateLimiter;\n }\n\n public function canMakeRequest(RateLimited $provider): bool\n {\n /** @var RateLimitInterface $rateLimit */\n foreach ($provider->getRateLimits() as $rateLimit) {\n $key = $rateLimit->getKey();\n\n if ($this->rateLimiter->tooManyAttempts($key, $rateLimit->getQuota())) {\n return false;\n }\n }\n\n return true;\n }\n\n public function requestAvailableIn(RateLimited $provider): int\n {\n return $provider->getRateLimits()->isNotEmpty()\n ? $provider->getRateLimits()\n ->map(fn (RateLimitInterface $rateLimit): int => $this->rateLimiter->availableIn($rateLimit->getKey()))\n ->max()\n : 0\n ;\n }\n\n public function incrementRequestCount(RateLimited $provider): void\n {\n /** @var RateLimitInterface $rateLimit */\n foreach ($provider->getRateLimits() as $rateLimit) {\n $this->rateLimiter->hit($rateLimit->getKey(), $rateLimit->getWindow());\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\Utility\\Service;\n\nuse Illuminate\\Cache\\RateLimiter;\nuse Jiminny\\Contracts\\Http\\RateLimited;\nuse Jiminny\\Contracts\\Http\\RateLimitInterface;\n\nclass ProviderRateLimiter\n{\n protected RateLimiter $rateLimiter;\n\n public function __construct(RateLimiter $rateLimiter)\n {\n $this->rateLimiter = $rateLimiter;\n }\n\n public function canMakeRequest(RateLimited $provider): bool\n {\n /** @var RateLimitInterface $rateLimit */\n foreach ($provider->getRateLimits() as $rateLimit) {\n $key = $rateLimit->getKey();\n\n if ($this->rateLimiter->tooManyAttempts($key, $rateLimit->getQuota())) {\n return false;\n }\n }\n\n return true;\n }\n\n public function requestAvailableIn(RateLimited $provider): int\n {\n return $provider->getRateLimits()->isNotEmpty()\n ? $provider->getRateLimits()\n ->map(fn (RateLimitInterface $rateLimit): int => $this->rateLimiter->availableIn($rateLimit->getKey()))\n ->max()\n : 0\n ;\n }\n\n public function incrementRequestCount(RateLimited $provider): void\n {\n /** @var RateLimitInterface $rateLimit */\n foreach ($provider->getRateLimits() as $rateLimit) {\n $this->rateLimiter->hit($rateLimit->getKey(), $rateLimit->getWindow());\n }\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":"4","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"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":"<?php\n\nnamespace Jiminny\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\nuse Illuminate\\Support\\Carbon;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPrompt;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Traits\\RequiresUUID;\n\n/**\n * Jiminny\\Models\\AutomatedReport\n *\n * @property int $id\n * @property string $uuid\n * @property int $team_id\n * @property string $type\n * @property bool $status\n * @property string $frequency\n * @property Carbon|null $from\n * @property Carbon|null $to\n * @property int|null $deal_value_min\n * @property int|null $deal_value_max\n * @property array $call_types\n * @property array $media_types\n * @property int|null $call_duration_min\n * @property int|null $call_duration_max\n * @property array|null $groups\n * @property array|null $playbook_categories\n * @property array|null $deal_at_call_stages\n * @property array|null $current_deal_stages\n * @property array $recipients\n * @property string|null $additional_prompt_input\n * @property string|null $custom_name\n * @property int|null $activity_search_id\n * @property int|null $ask_anything_prompt_id\n * @property Carbon|null $expires_at\n * @property Carbon|null $created_at\n * @property Carbon|null $updated_at\n * @property Carbon|null $deleted_at\n * @property-read \\Jiminny\\Models\\Team $team\n * @property-read \\Jiminny\\Models\\Activity\\Search|null $savedSearch\n * @property-read \\Jiminny\\Models\\AskAnything\\AskAnythingPrompt|null $askAnythingPrompt\n */\nclass AutomatedReport extends Model\n{\n use RequiresUUID;\n use SoftDeletes;\n\n protected $table = 'automated_reports';\n\n /**\n * The attributes that are mass assignable.\n *\n * @var array<int, string>\n */\n protected $fillable = [\n 'team_id',\n 'type',\n 'status',\n 'frequency',\n 'from',\n 'to',\n 'deal_value_min',\n 'deal_value_max',\n 'call_types',\n 'media_types',\n 'call_duration_min',\n 'call_duration_max',\n 'groups',\n 'playbook_categories',\n 'deal_at_call_stages',\n 'current_deal_stages',\n 'recipients',\n 'jiminny_recipients',\n 'additional_prompt_input',\n 'custom_name',\n 'created_by',\n 'activity_search_id',\n 'ask_anything_prompt_id',\n 'expires_at',\n ];\n\n protected $hidden = ['uuid'];\n\n /**\n * Get the attributes that should be cast.\n *\n * @return array<string, string>\n */\n protected function casts(): array\n {\n return [\n 'status' => 'boolean',\n 'from' => 'datetime',\n 'to' => 'datetime',\n 'call_types' => 'array',\n 'media_types' => 'array',\n 'groups' => 'array',\n 'playbook_categories' => 'array',\n 'deal_at_call_stages' => 'array',\n 'current_deal_stages' => 'array',\n 'recipients' => 'array',\n 'jiminny_recipients' => 'array',\n 'expires_at' => 'date',\n 'deleted_at' => 'datetime',\n ];\n }\n\n /**\n * Get the team that owns the automated report.\n */\n public function team()\n {\n return $this->belongsTo(Team::class);\n }\n\n /**\n *\n * Get the user who created the report.\n */\n public function creator(): BelongsTo\n {\n return $this->belongsTo(User::class, 'created_by');\n }\n\n public function savedSearch(): BelongsTo\n {\n return $this->belongsTo(Search::class, 'activity_search_id');\n }\n\n public function askAnythingPrompt(): BelongsTo\n {\n return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');\n }\n\n public function isAskJiminnyReport(): bool\n {\n return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;\n }\n\n public function isExpired(): bool\n {\n $expiresAt = $this->getExpiresAt();\n\n return $expiresAt !== null && $expiresAt->isPast();\n }\n\n public function canExecute(): bool\n {\n if ($this->isAskJiminnyReport()) {\n return $this->getActivitySearchId() !== null\n && $this->getAskAnythingPromptId() !== null;\n }\n\n return true;\n }\n\n public function getActivitySearchId(): ?int\n {\n return $this->getAttribute('activity_search_id');\n }\n\n public function getAskAnythingPromptId(): ?int\n {\n return $this->getAttribute('ask_anything_prompt_id');\n }\n\n public function getExpiresAt(): ?Carbon\n {\n return $this->getAttribute('expires_at');\n }\n\n public function getSavedSearch(): ?Search\n {\n return $this->getAttribute('savedSearch');\n }\n\n public function getAskAnythingPrompt(): ?AskAnythingPrompt\n {\n return $this->getAttribute('askAnythingPrompt');\n }\n\n /**\n * Get the ID of the automated report.\n *\n * @return int\n */\n public function getId(): int\n {\n return $this->getAttribute('id');\n }\n\n /**\n * Get the UUID of the automated report.\n *\n * @return string\n */\n public function getUuid(): string\n {\n return $this->getAttribute('id_string');\n }\n\n /**\n * Get the team ID of the automated report.\n *\n * @return int\n */\n public function getTeamId(): int\n {\n return $this->getAttribute('team_id');\n }\n\n /**\n * Get the type of the automated report.\n *\n * @return string\n */\n public function getType(): string\n {\n return $this->getAttribute('type');\n }\n\n /**\n * Get the status of the automated report.\n * True means active, false means inactive.\n *\n * @return bool\n */\n public function getStatus(): bool\n {\n return $this->getAttribute('status');\n }\n\n /**\n * Get the frequency of the automated report.\n *\n * @return string\n */\n public function getFrequency(): string\n {\n return $this->getAttribute('frequency');\n }\n\n /**\n * Get the from date of the automated report.\n *\n * @return Carbon|null\n */\n public function getFrom(): ?Carbon\n {\n return $this->getAttribute('from');\n }\n\n /**\n * Get the to date of the automated report.\n *\n * @return Carbon|null\n */\n public function getTo(): ?Carbon\n {\n return $this->getAttribute('to');\n }\n\n /**\n * Get the minimum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMin(): ?int\n {\n return $this->getAttribute('deal_value_min');\n }\n\n /**\n * Get the maximum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMax(): ?int\n {\n return $this->getAttribute('deal_value_max');\n }\n\n /**\n * Get the call types of the automated report.\n *\n * @return array\n */\n public function getCallTypes(): array\n {\n return $this->getAttribute('call_types') ?? [];\n }\n\n public function getMediaTypes(): array\n {\n return $this->getAttribute('media_types') ?? [];\n }\n\n /**\n * Get the minimum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMin(): ?int\n {\n return $this->getAttribute('call_duration_min');\n }\n\n /**\n * Get the maximum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMax(): ?int\n {\n return $this->getAttribute('call_duration_max');\n }\n\n /**\n * Get the groups of the automated report.\n *\n * @return array\n */\n public function getGroups(): array\n {\n return $this->getAttribute('groups') ?? [];\n }\n\n /**\n * Get the playbook categories of the automated report.\n *\n * @return array\n */\n public function getPlaybookCategories(): array\n {\n return $this->getAttribute('playbook_categories') ?? [];\n }\n\n /**\n * Get the deal at call stages of the automated report.\n *\n * @return array\n */\n public function getDealAtCallStages(): array\n {\n return $this->getAttribute('deal_at_call_stages') ?? [];\n }\n\n /**\n * Get the current deal stages of the automated report.\n *\n * @return array\n */\n public function getCurrentDealStages(): array\n {\n return $this->getAttribute('current_deal_stages') ?? [];\n }\n\n /**\n * Get the recipients of the automated report.\n *\n * @return array\n */\n public function getRecipients(): array\n {\n return $this->getAttribute('recipients') ?? [];\n }\n\n /**\n * Get the Jiminny's recipients of the automated report.\n *\n * @return array\n */\n public function getJiminnyRecipients(): array\n {\n return $this->getAttribute('jiminny_recipients') ?? [];\n }\n\n /**\n * Get the additional prompt input of the automated report.\n *\n * @return string|null\n */\n public function getAdditionalPromptInput(): ?string\n {\n return $this->getAttribute('additional_prompt_input');\n }\n\n public function getCustomName(): ?string\n {\n return $this->getAttribute('custom_name');\n }\n\n /**\n * Get the created at date of the automated report.\n *\n * @return Carbon\n */\n public function getCreatedAt(): Carbon\n {\n return $this->getAttribute('created_at');\n }\n\n /**\n * Get the updated at date of the automated report.\n *\n * @return Carbon\n */\n public function getUpdatedAt(): Carbon\n {\n return $this->getAttribute('updated_at');\n }\n\n /**\n * Get the deleted at date of the automated report.\n *\n * @return Carbon|null\n */\n public function getDeletedAt(): ?Carbon\n {\n return $this->getAttribute('deleted_at');\n }\n\n public function getTeam(): Team\n {\n return $this->getAttribute('team');\n }\n\n public function getCreator(): ?User\n {\n return $this->getAttribute('creator');\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\nuse Illuminate\\Support\\Carbon;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPrompt;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Traits\\RequiresUUID;\n\n/**\n * Jiminny\\Models\\AutomatedReport\n *\n * @property int $id\n * @property string $uuid\n * @property int $team_id\n * @property string $type\n * @property bool $status\n * @property string $frequency\n * @property Carbon|null $from\n * @property Carbon|null $to\n * @property int|null $deal_value_min\n * @property int|null $deal_value_max\n * @property array $call_types\n * @property array $media_types\n * @property int|null $call_duration_min\n * @property int|null $call_duration_max\n * @property array|null $groups\n * @property array|null $playbook_categories\n * @property array|null $deal_at_call_stages\n * @property array|null $current_deal_stages\n * @property array $recipients\n * @property string|null $additional_prompt_input\n * @property string|null $custom_name\n * @property int|null $activity_search_id\n * @property int|null $ask_anything_prompt_id\n * @property Carbon|null $expires_at\n * @property Carbon|null $created_at\n * @property Carbon|null $updated_at\n * @property Carbon|null $deleted_at\n * @property-read \\Jiminny\\Models\\Team $team\n * @property-read \\Jiminny\\Models\\Activity\\Search|null $savedSearch\n * @property-read \\Jiminny\\Models\\AskAnything\\AskAnythingPrompt|null $askAnythingPrompt\n */\nclass AutomatedReport extends Model\n{\n use RequiresUUID;\n use SoftDeletes;\n\n protected $table = 'automated_reports';\n\n /**\n * The attributes that are mass assignable.\n *\n * @var array<int, string>\n */\n protected $fillable = [\n 'team_id',\n 'type',\n 'status',\n 'frequency',\n 'from',\n 'to',\n 'deal_value_min',\n 'deal_value_max',\n 'call_types',\n 'media_types',\n 'call_duration_min',\n 'call_duration_max',\n 'groups',\n 'playbook_categories',\n 'deal_at_call_stages',\n 'current_deal_stages',\n 'recipients',\n 'jiminny_recipients',\n 'additional_prompt_input',\n 'custom_name',\n 'created_by',\n 'activity_search_id',\n 'ask_anything_prompt_id',\n 'expires_at',\n ];\n\n protected $hidden = ['uuid'];\n\n /**\n * Get the attributes that should be cast.\n *\n * @return array<string, string>\n */\n protected function casts(): array\n {\n return [\n 'status' => 'boolean',\n 'from' => 'datetime',\n 'to' => 'datetime',\n 'call_types' => 'array',\n 'media_types' => 'array',\n 'groups' => 'array',\n 'playbook_categories' => 'array',\n 'deal_at_call_stages' => 'array',\n 'current_deal_stages' => 'array',\n 'recipients' => 'array',\n 'jiminny_recipients' => 'array',\n 'expires_at' => 'date',\n 'deleted_at' => 'datetime',\n ];\n }\n\n /**\n * Get the team that owns the automated report.\n */\n public function team()\n {\n return $this->belongsTo(Team::class);\n }\n\n /**\n *\n * Get the user who created the report.\n */\n public function creator(): BelongsTo\n {\n return $this->belongsTo(User::class, 'created_by');\n }\n\n public function savedSearch(): BelongsTo\n {\n return $this->belongsTo(Search::class, 'activity_search_id');\n }\n\n public function askAnythingPrompt(): BelongsTo\n {\n return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');\n }\n\n public function isAskJiminnyReport(): bool\n {\n return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;\n }\n\n public function isExpired(): bool\n {\n $expiresAt = $this->getExpiresAt();\n\n return $expiresAt !== null && $expiresAt->isPast();\n }\n\n public function canExecute(): bool\n {\n if ($this->isAskJiminnyReport()) {\n return $this->getActivitySearchId() !== null\n && $this->getAskAnythingPromptId() !== null;\n }\n\n return true;\n }\n\n public function getActivitySearchId(): ?int\n {\n return $this->getAttribute('activity_search_id');\n }\n\n public function getAskAnythingPromptId(): ?int\n {\n return $this->getAttribute('ask_anything_prompt_id');\n }\n\n public function getExpiresAt(): ?Carbon\n {\n return $this->getAttribute('expires_at');\n }\n\n public function getSavedSearch(): ?Search\n {\n return $this->getAttribute('savedSearch');\n }\n\n public function getAskAnythingPrompt(): ?AskAnythingPrompt\n {\n return $this->getAttribute('askAnythingPrompt');\n }\n\n /**\n * Get the ID of the automated report.\n *\n * @return int\n */\n public function getId(): int\n {\n return $this->getAttribute('id');\n }\n\n /**\n * Get the UUID of the automated report.\n *\n * @return string\n */\n public function getUuid(): string\n {\n return $this->getAttribute('id_string');\n }\n\n /**\n * Get the team ID of the automated report.\n *\n * @return int\n */\n public function getTeamId(): int\n {\n return $this->getAttribute('team_id');\n }\n\n /**\n * Get the type of the automated report.\n *\n * @return string\n */\n public function getType(): string\n {\n return $this->getAttribute('type');\n }\n\n /**\n * Get the status of the automated report.\n * True means active, false means inactive.\n *\n * @return bool\n */\n public function getStatus(): bool\n {\n return $this->getAttribute('status');\n }\n\n /**\n * Get the frequency of the automated report.\n *\n * @return string\n */\n public function getFrequency(): string\n {\n return $this->getAttribute('frequency');\n }\n\n /**\n * Get the from date of the automated report.\n *\n * @return Carbon|null\n */\n public function getFrom(): ?Carbon\n {\n return $this->getAttribute('from');\n }\n\n /**\n * Get the to date of the automated report.\n *\n * @return Carbon|null\n */\n public function getTo(): ?Carbon\n {\n return $this->getAttribute('to');\n }\n\n /**\n * Get the minimum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMin(): ?int\n {\n return $this->getAttribute('deal_value_min');\n }\n\n /**\n * Get the maximum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMax(): ?int\n {\n return $this->getAttribute('deal_value_max');\n }\n\n /**\n * Get the call types of the automated report.\n *\n * @return array\n */\n public function getCallTypes(): array\n {\n return $this->getAttribute('call_types') ?? [];\n }\n\n public function getMediaTypes(): array\n {\n return $this->getAttribute('media_types') ?? [];\n }\n\n /**\n * Get the minimum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMin(): ?int\n {\n return $this->getAttribute('call_duration_min');\n }\n\n /**\n * Get the maximum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMax(): ?int\n {\n return $this->getAttribute('call_duration_max');\n }\n\n /**\n * Get the groups of the automated report.\n *\n * @return array\n */\n public function getGroups(): array\n {\n return $this->getAttribute('groups') ?? [];\n }\n\n /**\n * Get the playbook categories of the automated report.\n *\n * @return array\n */\n public function getPlaybookCategories(): array\n {\n return $this->getAttribute('playbook_categories') ?? [];\n }\n\n /**\n * Get the deal at call stages of the automated report.\n *\n * @return array\n */\n public function getDealAtCallStages(): array\n {\n return $this->getAttribute('deal_at_call_stages') ?? [];\n }\n\n /**\n * Get the current deal stages of the automated report.\n *\n * @return array\n */\n public function getCurrentDealStages(): array\n {\n return $this->getAttribute('current_deal_stages') ?? [];\n }\n\n /**\n * Get the recipients of the automated report.\n *\n * @return array\n */\n public function getRecipients(): array\n {\n return $this->getAttribute('recipients') ?? [];\n }\n\n /**\n * Get the Jiminny's recipients of the automated report.\n *\n * @return array\n */\n public function getJiminnyRecipients(): array\n {\n return $this->getAttribute('jiminny_recipients') ?? [];\n }\n\n /**\n * Get the additional prompt input of the automated report.\n *\n * @return string|null\n */\n public function getAdditionalPromptInput(): ?string\n {\n return $this->getAttribute('additional_prompt_input');\n }\n\n public function getCustomName(): ?string\n {\n return $this->getAttribute('custom_name');\n }\n\n /**\n * Get the created at date of the automated report.\n *\n * @return Carbon\n */\n public function getCreatedAt(): Carbon\n {\n return $this->getAttribute('created_at');\n }\n\n /**\n * Get the updated at date of the automated report.\n *\n * @return Carbon\n */\n public function getUpdatedAt(): Carbon\n {\n return $this->getAttribute('updated_at');\n }\n\n /**\n * Get the deleted at date of the automated report.\n *\n * @return Carbon|null\n */\n public function getDeletedAt(): ?Carbon\n {\n return $this->getAttribute('deleted_at');\n }\n\n public function getTeam(): Team\n {\n return $this->getAttribute('team');\n }\n\n public function getCreator(): ?User\n {\n return $this->getAttribute('creator');\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"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}]...
|
-7741672321923979945
|
-741568003184046556
|
click
|
accessibility
|
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
<?php
declare(strict_types=1);
namespace Jiminny\Component\Utility\Service;
use Illuminate\Cache\RateLimiter;
use Jiminny\Contracts\Http\RateLimited;
use Jiminny\Contracts\Http\RateLimitInterface;
class ProviderRateLimiter
{
protected RateLimiter $rateLimiter;
public function __construct(RateLimiter $rateLimiter)
{
$this->rateLimiter = $rateLimiter;
}
public function canMakeRequest(RateLimited $provider): bool
{
/** @var RateLimitInterface $rateLimit */
foreach ($provider->getRateLimits() as $rateLimit) {
$key = $rateLimit->getKey();
if ($this->rateLimiter->tooManyAttempts($key, $rateLimit->getQuota())) {
return false;
}
}
return true;
}
public function requestAvailableIn(RateLimited $provider): int
{
return $provider->getRateLimits()->isNotEmpty()
? $provider->getRateLimits()
->map(fn (RateLimitInterface $rateLimit): int => $this->rateLimiter->availableIn($rateLimit->getKey()))
->max()
: 0
;
}
public function incrementRequestCount(RateLimited $provider): void
{
/** @var RateLimitInterface $rateLimit */
foreach ($provider->getRateLimits() as $rateLimit) {
$this->rateLimiter->hit($rateLimit->getKey(), $rateLimit->getWindow());
}
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
4
1
6
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Carbon;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\AskAnything\AskAnythingPrompt;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Traits\RequiresUUID;
/**
* Jiminny\Models\AutomatedReport
*
* @property int $id
* @property string $uuid
* @property int $team_id
* @property string $type
* @property bool $status
* @property string $frequency
* @property Carbon|null $from
* @property Carbon|null $to
* @property int|null $deal_value_min
* @property int|null $deal_value_max
* @property array $call_types
* @property array $media_types
* @property int|null $call_duration_min
* @property int|null $call_duration_max
* @property array|null $groups
* @property array|null $playbook_categories
* @property array|null $deal_at_call_stages
* @property array|null $current_deal_stages
* @property array $recipients
* @property string|null $additional_prompt_input
* @property string|null $custom_name
* @property int|null $activity_search_id
* @property int|null $ask_anything_prompt_id
* @property Carbon|null $expires_at
* @property Carbon|null $created_at
* @property Carbon|null $updated_at
* @property Carbon|null $deleted_at
* @property-read \Jiminny\Models\Team $team
* @property-read \Jiminny\Models\Activity\Search|null $savedSearch
* @property-read \Jiminny\Models\AskAnything\AskAnythingPrompt|null $askAnythingPrompt
*/
class AutomatedReport extends Model
{
use RequiresUUID;
use SoftDeletes;
protected $table = 'automated_reports';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'team_id',
'type',
'status',
'frequency',
'from',
'to',
'deal_value_min',
'deal_value_max',
'call_types',
'media_types',
'call_duration_min',
'call_duration_max',
'groups',
'playbook_categories',
'deal_at_call_stages',
'current_deal_stages',
'recipients',
'jiminny_recipients',
'additional_prompt_input',
'custom_name',
'created_by',
'activity_search_id',
'ask_anything_prompt_id',
'expires_at',
];
protected $hidden = ['uuid'];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'status' => 'boolean',
'from' => 'datetime',
'to' => 'datetime',
'call_types' => 'array',
'media_types' => 'array',
'groups' => 'array',
'playbook_categories' => 'array',
'deal_at_call_stages' => 'array',
'current_deal_stages' => 'array',
'recipients' => 'array',
'jiminny_recipients' => 'array',
'expires_at' => 'date',
'deleted_at' => 'datetime',
];
}
/**
* Get the team that owns the automated report.
*/
public function team()
{
return $this->belongsTo(Team::class);
}
/**
*
* Get the user who created the report.
*/
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
public function savedSearch(): BelongsTo
{
return $this->belongsTo(Search::class, 'activity_search_id');
}
public function askAnythingPrompt(): BelongsTo
{
return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');
}
public function isAskJiminnyReport(): bool
{
return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;
}
public function isExpired(): bool
{
$expiresAt = $this->getExpiresAt();
return $expiresAt !== null && $expiresAt->isPast();
}
public function canExecute(): bool
{
if ($this->isAskJiminnyReport()) {
return $this->getActivitySearchId() !== null
&& $this->getAskAnythingPromptId() !== null;
}
return true;
}
public function getActivitySearchId(): ?int
{
return $this->getAttribute('activity_search_id');
}
public function getAskAnythingPromptId(): ?int
{
return $this->getAttribute('ask_anything_prompt_id');
}
public function getExpiresAt(): ?Carbon
{
return $this->getAttribute('expires_at');
}
public function getSavedSearch(): ?Search
{
return $this->getAttribute('savedSearch');
}
public function getAskAnythingPrompt(): ?AskAnythingPrompt
{
return $this->getAttribute('askAnythingPrompt');
}
/**
* Get the ID of the automated report.
*
* @return int
*/
public function getId(): int
{
return $this->getAttribute('id');
}
/**
* Get the UUID of the automated report.
*
* @return string
*/
public function getUuid(): string
{
return $this->getAttribute('id_string');
}
/**
* Get the team ID of the automated report.
*
* @return int
*/
public function getTeamId(): int
{
return $this->getAttribute('team_id');
}
/**
* Get the type of the automated report.
*
* @return string
*/
public function getType(): string
{
return $this->getAttribute('type');
}
/**
* Get the status of the automated report.
* True means active, false means inactive.
*
* @return bool
*/
public function getStatus(): bool
{
return $this->getAttribute('status');
}
/**
* Get the frequency of the automated report.
*
* @return string
*/
public function getFrequency(): string
{
return $this->getAttribute('frequency');
}
/**
* Get the from date of the automated report.
*
* @return Carbon|null
*/
public function getFrom(): ?Carbon
{
return $this->getAttribute('from');
}
/**
* Get the to date of the automated report.
*
* @return Carbon|null
*/
public function getTo(): ?Carbon
{
return $this->getAttribute('to');
}
/**
* Get the minimum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMin(): ?int
{
return $this->getAttribute('deal_value_min');
}
/**
* Get the maximum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMax(): ?int
{
return $this->getAttribute('deal_value_max');
}
/**
* Get the call types of the automated report.
*
* @return array
*/
public function getCallTypes(): array
{
return $this->getAttribute('call_types') ?? [];
}
public function getMediaTypes(): array
{
return $this->getAttribute('media_types') ?? [];
}
/**
* Get the minimum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMin(): ?int
{
return $this->getAttribute('call_duration_min');
}
/**
* Get the maximum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMax(): ?int
{
return $this->getAttribute('call_duration_max');
}
/**
* Get the groups of the automated report.
*
* @return array
*/
public function getGroups(): array
{
return $this->getAttribute('groups') ?? [];
}
/**
* Get the playbook categories of the automated report.
*
* @return array
*/
public function getPlaybookCategories(): array
{
return $this->getAttribute('playbook_categories') ?? [];
}
/**
* Get the deal at call stages of the automated report.
*
* @return array
*/
public function getDealAtCallStages(): array
{
return $this->getAttribute('deal_at_call_stages') ?? [];
}
/**
* Get the current deal stages of the automated report.
*
* @return array
*/
public function getCurrentDealStages(): array
{
return $this->getAttribute('current_deal_stages') ?? [];
}
/**
* Get the recipients of the automated report.
*
* @return array
*/
public function getRecipients(): array
{
return $this->getAttribute('recipients') ?? [];
}
/**
* Get the Jiminny's recipients of the automated report.
*
* @return array
*/
public function getJiminnyRecipients(): array
{
return $this->getAttribute('jiminny_recipients') ?? [];
}
/**
* Get the additional prompt input of the automated report.
*
* @return string|null
*/
public function getAdditionalPromptInput(): ?string
{
return $this->getAttribute('additional_prompt_input');
}
public function getCustomName(): ?string
{
return $this->getAttribute('custom_name');
}
/**
* Get the created at date of the automated report.
*
* @return Carbon
*/
public function getCreatedAt(): Carbon
{
return $this->getAttribute('created_at');
}
/**
* Get the updated at date of the automated report.
*
* @return Carbon
*/
public function getUpdatedAt(): Carbon
{
return $this->getAttribute('updated_at');
}
/**
* Get the deleted at date of the automated report.
*
* @return Carbon|null
*/
public function getDeletedAt(): ?Carbon
{
return $this->getAttribute('deleted_at');
}
public function getTeam(): Team
{
return $this->getAttribute('team');
}
public function getCreator(): ?User
{
return $this->getAttribute('creator');
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
7203
|
NULL
|
NULL
|
NULL
|
|
7205
|
326
|
2
|
2026-05-08T08:33:23.173925+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778229203173_m2.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReport.php
|
True
|
NULL
|
monitor_2
|
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
<?php
declare(strict_types=1);
namespace Jiminny\Component\Utility\Service;
use Illuminate\Cache\RateLimiter;
use Jiminny\Contracts\Http\RateLimited;
use Jiminny\Contracts\Http\RateLimitInterface;
class ProviderRateLimiter
{
protected RateLimiter $rateLimiter;
public function __construct(RateLimiter $rateLimiter)
{
$this->rateLimiter = $rateLimiter;
}
public function canMakeRequest(RateLimited $provider): bool
{
/** @var RateLimitInterface $rateLimit */
foreach ($provider->getRateLimits() as $rateLimit) {
$key = $rateLimit->getKey();
if ($this->rateLimiter->tooManyAttempts($key, $rateLimit->getQuota())) {
return false;
}
}
return true;
}
public function requestAvailableIn(RateLimited $provider): int
{
return $provider->getRateLimits()->isNotEmpty()
? $provider->getRateLimits()
->map(fn (RateLimitInterface $rateLimit): int => $this->rateLimiter->availableIn($rateLimit->getKey()))
->max()
: 0
;
}
public function incrementRequestCount(RateLimited $provider): void
{
/** @var RateLimitInterface $rateLimit */
foreach ($provider->getRateLimits() as $rateLimit) {
$this->rateLimiter->hit($rateLimit->getKey(), $rateLimit->getWindow());
}
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
4
1
6
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Carbon;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\AskAnything\AskAnythingPrompt;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Traits\RequiresUUID;
/**
* Jiminny\Models\AutomatedReport
*
* @property int $id
* @property string $uuid
* @property int $team_id
* @property string $type
* @property bool $status
* @property string $frequency
* @property Carbon|null $from
* @property Carbon|null $to
* @property int|null $deal_value_min
* @property int|null $deal_value_max
* @property array $call_types
* @property array $media_types
* @property int|null $call_duration_min
* @property int|null $call_duration_max
* @property array|null $groups
* @property array|null $playbook_categories
* @property array|null $deal_at_call_stages
* @property array|null $current_deal_stages
* @property array $recipients
* @property string|null $additional_prompt_input
* @property string|null $custom_name
* @property int|null $activity_search_id
* @property int|null $ask_anything_prompt_id
* @property Carbon|null $expires_at
* @property Carbon|null $created_at
* @property Carbon|null $updated_at
* @property Carbon|null $deleted_at
* @property-read \Jiminny\Models\Team $team
* @property-read \Jiminny\Models\Activity\Search|null $savedSearch
* @property-read \Jiminny\Models\AskAnything\AskAnythingPrompt|null $askAnythingPrompt
*/
class AutomatedReport extends Model
{
use RequiresUUID;
use SoftDeletes;
protected $table = 'automated_reports';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'team_id',
'type',
'status',
'frequency',
'from',
'to',
'deal_value_min',
'deal_value_max',
'call_types',
'media_types',
'call_duration_min',
'call_duration_max',
'groups',
'playbook_categories',
'deal_at_call_stages',
'current_deal_stages',
'recipients',
'jiminny_recipients',
'additional_prompt_input',
'custom_name',
'created_by',
'activity_search_id',
'ask_anything_prompt_id',
'expires_at',
];
protected $hidden = ['uuid'];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'status' => 'boolean',
'from' => 'datetime',
'to' => 'datetime',
'call_types' => 'array',
'media_types' => 'array',
'groups' => 'array',
'playbook_categories' => 'array',
'deal_at_call_stages' => 'array',
'current_deal_stages' => 'array',
'recipients' => 'array',
'jiminny_recipients' => 'array',
'expires_at' => 'date',
'deleted_at' => 'datetime',
];
}
/**
* Get the team that owns the automated report.
*/
public function team()
{
return $this->belongsTo(Team::class);
}
/**
*
* Get the user who created the report.
*/
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
public function savedSearch(): BelongsTo
{
return $this->belongsTo(Search::class, 'activity_search_id');
}
public function askAnythingPrompt(): BelongsTo
{
return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');
}
public function isAskJiminnyReport(): bool
{
return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;
}
public function isExpired(): bool
{
$expiresAt = $this->getExpiresAt();
return $expiresAt !== null && $expiresAt->isPast();
}
public function canExecute(): bool
{
if ($this->isAskJiminnyReport()) {
return $this->getActivitySearchId() !== null
&& $this->getAskAnythingPromptId() !== null;
}
return true;
}
public function getActivitySearchId(): ?int
{
return $this->getAttribute('activity_search_id');
}
public function getAskAnythingPromptId(): ?int
{
return $this->getAttribute('ask_anything_prompt_id');
}
public function getExpiresAt(): ?Carbon
{
return $this->getAttribute('expires_at');
}
public function getSavedSearch(): ?Search
{
return $this->getAttribute('savedSearch');
}
public function getAskAnythingPrompt(): ?AskAnythingPrompt
{
return $this->getAttribute('askAnythingPrompt');
}
/**
* Get the ID of the automated report.
*
* @return int
*/
public function getId(): int
{
return $this->getAttribute('id');
}
/**
* Get the UUID of the automated report.
*
* @return string
*/
public function getUuid(): string
{
return $this->getAttribute('id_string');
}
/**
* Get the team ID of the automated report.
*
* @return int
*/
public function getTeamId(): int
{
return $this->getAttribute('team_id');
}
/**
* Get the type of the automated report.
*
* @return string
*/
public function getType(): string
{
return $this->getAttribute('type');
}
/**
* Get the status of the automated report.
* True means active, false means inactive.
*
* @return bool
*/
public function getStatus(): bool
{
return $this->getAttribute('status');
}
/**
* Get the frequency of the automated report.
*
* @return string
*/
public function getFrequency(): string
{
return $this->getAttribute('frequency');
}
/**
* Get the from date of the automated report.
*
* @return Carbon|null
*/
public function getFrom(): ?Carbon
{
return $this->getAttribute('from');
}
/**
* Get the to date of the automated report.
*
* @return Carbon|null
*/
public function getTo(): ?Carbon
{
return $this->getAttribute('to');
}
/**
* Get the minimum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMin(): ?int
{
return $this->getAttribute('deal_value_min');
}
/**
* Get the maximum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMax(): ?int
{
return $this->getAttribute('deal_value_max');
}
/**
* Get the call types of the automated report.
*
* @return array
*/
public function getCallTypes(): array
{
return $this->getAttribute('call_types') ?? [];
}
public function getMediaTypes(): array
{
return $this->getAttribute('media_types') ?? [];
}
/**
* Get the minimum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMin(): ?int
{
return $this->getAttribute('call_duration_min');
}
/**
* Get the maximum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMax(): ?int
{
return $this->getAttribute('call_duration_max');
}
/**
* Get the groups of the automated report.
*
* @return array
*/
public function getGroups(): array
{
return $this->getAttribute('groups') ?? [];
}
/**
* Get the playbook categories of the automated report.
*
* @return array
*/
public function getPlaybookCategories(): array
{
return $this->getAttribute('playbook_categories') ?? [];
}
/**
* Get the deal at call stages of the automated report.
*
* @return array
*/
public function getDealAtCallStages(): array
{
return $this->getAttribute('deal_at_call_stages') ?? [];
}
/**
* Get the current deal stages of the automated report.
*
* @return array
*/
public function getCurrentDealStages(): array
{
return $this->getAttribute('current_deal_stages') ?? [];
}
/**
* Get the recipients of the automated report.
*
* @return array
*/
public function getRecipients(): array
{
return $this->getAttribute('recipients') ?? [];
}
/**
* Get the Jiminny's recipients of the automated report.
*
* @return array
*/
public function getJiminnyRecipients(): array
{
return $this->getAttribute('jiminny_recipients') ?? [];
}
/**
* Get the additional prompt input of the automated report.
*
* @return string|null
*/
public function getAdditionalPromptInput(): ?string
{
return $this->getAttribute('additional_prompt_input');
}
public function getCustomName(): ?string
{
return $this->getAttribute('custom_name');
}
/**
* Get the created at date of the automated report.
*
* @return Carbon
*/
public function getCreatedAt(): Carbon
{
return $this->getAttribute('created_at');
}
/**
* Get the updated at date of the automated report.
*
* @return Carbon
*/
public function getUpdatedAt(): Carbon
{
return $this->getAttribute('updated_at');
}
/**
* Get the deleted at date of the automated report.
*
* @return Carbon|null
*/
public function getDeletedAt(): ?Carbon
{
return $this->getAttribute('deleted_at');
}
public function getTeam(): Team
{
return $this->getAttribute('team');
}
public function getCreator(): ?User
{
return $this->getAttribute('creator');
}
}
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":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"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,"bounds":{"left":0.8081782,"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":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"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 'AskJiminnyReportActivityServiceTest'","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 'AskJiminnyReportActivityServiceTest'","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":"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":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\Utility\\Service;\n\nuse Illuminate\\Cache\\RateLimiter;\nuse Jiminny\\Contracts\\Http\\RateLimited;\nuse Jiminny\\Contracts\\Http\\RateLimitInterface;\n\nclass ProviderRateLimiter\n{\n protected RateLimiter $rateLimiter;\n\n public function __construct(RateLimiter $rateLimiter)\n {\n $this->rateLimiter = $rateLimiter;\n }\n\n public function canMakeRequest(RateLimited $provider): bool\n {\n /** @var RateLimitInterface $rateLimit */\n foreach ($provider->getRateLimits() as $rateLimit) {\n $key = $rateLimit->getKey();\n\n if ($this->rateLimiter->tooManyAttempts($key, $rateLimit->getQuota())) {\n return false;\n }\n }\n\n return true;\n }\n\n public function requestAvailableIn(RateLimited $provider): int\n {\n return $provider->getRateLimits()->isNotEmpty()\n ? $provider->getRateLimits()\n ->map(fn (RateLimitInterface $rateLimit): int => $this->rateLimiter->availableIn($rateLimit->getKey()))\n ->max()\n : 0\n ;\n }\n\n public function incrementRequestCount(RateLimited $provider): void\n {\n /** @var RateLimitInterface $rateLimit */\n foreach ($provider->getRateLimits() as $rateLimit) {\n $this->rateLimiter->hit($rateLimit->getKey(), $rateLimit->getWindow());\n }\n }\n}","depth":4,"bounds":{"left":0.4401596,"top":0.06624102,"width":0.31615692,"height":0.91300875},"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\Utility\\Service;\n\nuse Illuminate\\Cache\\RateLimiter;\nuse Jiminny\\Contracts\\Http\\RateLimited;\nuse Jiminny\\Contracts\\Http\\RateLimitInterface;\n\nclass ProviderRateLimiter\n{\n protected RateLimiter $rateLimiter;\n\n public function __construct(RateLimiter $rateLimiter)\n {\n $this->rateLimiter = $rateLimiter;\n }\n\n public function canMakeRequest(RateLimited $provider): bool\n {\n /** @var RateLimitInterface $rateLimit */\n foreach ($provider->getRateLimits() as $rateLimit) {\n $key = $rateLimit->getKey();\n\n if ($this->rateLimiter->tooManyAttempts($key, $rateLimit->getQuota())) {\n return false;\n }\n }\n\n return true;\n }\n\n public function requestAvailableIn(RateLimited $provider): int\n {\n return $provider->getRateLimits()->isNotEmpty()\n ? $provider->getRateLimits()\n ->map(fn (RateLimitInterface $rateLimit): int => $this->rateLimiter->availableIn($rateLimit->getKey()))\n ->max()\n : 0\n ;\n }\n\n public function incrementRequestCount(RateLimited $provider): void\n {\n /** @var RateLimitInterface $rateLimit */\n foreach ($provider->getRateLimits() as $rateLimit) {\n $this->rateLimiter->hit($rateLimit->getKey(), $rateLimit->getWindow());\n }\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":"4","depth":4,"bounds":{"left":0.3776596,"top":0.2490024,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.38763297,"top":0.2490024,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.39694148,"top":0.2490024,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.40658244,"top":0.24740623,"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.41389626,"top":0.24740623,"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\nnamespace Jiminny\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\nuse Illuminate\\Support\\Carbon;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPrompt;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Traits\\RequiresUUID;\n\n/**\n * Jiminny\\Models\\AutomatedReport\n *\n * @property int $id\n * @property string $uuid\n * @property int $team_id\n * @property string $type\n * @property bool $status\n * @property string $frequency\n * @property Carbon|null $from\n * @property Carbon|null $to\n * @property int|null $deal_value_min\n * @property int|null $deal_value_max\n * @property array $call_types\n * @property array $media_types\n * @property int|null $call_duration_min\n * @property int|null $call_duration_max\n * @property array|null $groups\n * @property array|null $playbook_categories\n * @property array|null $deal_at_call_stages\n * @property array|null $current_deal_stages\n * @property array $recipients\n * @property string|null $additional_prompt_input\n * @property string|null $custom_name\n * @property int|null $activity_search_id\n * @property int|null $ask_anything_prompt_id\n * @property Carbon|null $expires_at\n * @property Carbon|null $created_at\n * @property Carbon|null $updated_at\n * @property Carbon|null $deleted_at\n * @property-read \\Jiminny\\Models\\Team $team\n * @property-read \\Jiminny\\Models\\Activity\\Search|null $savedSearch\n * @property-read \\Jiminny\\Models\\AskAnything\\AskAnythingPrompt|null $askAnythingPrompt\n */\nclass AutomatedReport extends Model\n{\n use RequiresUUID;\n use SoftDeletes;\n\n protected $table = 'automated_reports';\n\n /**\n * The attributes that are mass assignable.\n *\n * @var array<int, string>\n */\n protected $fillable = [\n 'team_id',\n 'type',\n 'status',\n 'frequency',\n 'from',\n 'to',\n 'deal_value_min',\n 'deal_value_max',\n 'call_types',\n 'media_types',\n 'call_duration_min',\n 'call_duration_max',\n 'groups',\n 'playbook_categories',\n 'deal_at_call_stages',\n 'current_deal_stages',\n 'recipients',\n 'jiminny_recipients',\n 'additional_prompt_input',\n 'custom_name',\n 'created_by',\n 'activity_search_id',\n 'ask_anything_prompt_id',\n 'expires_at',\n ];\n\n protected $hidden = ['uuid'];\n\n /**\n * Get the attributes that should be cast.\n *\n * @return array<string, string>\n */\n protected function casts(): array\n {\n return [\n 'status' => 'boolean',\n 'from' => 'datetime',\n 'to' => 'datetime',\n 'call_types' => 'array',\n 'media_types' => 'array',\n 'groups' => 'array',\n 'playbook_categories' => 'array',\n 'deal_at_call_stages' => 'array',\n 'current_deal_stages' => 'array',\n 'recipients' => 'array',\n 'jiminny_recipients' => 'array',\n 'expires_at' => 'date',\n 'deleted_at' => 'datetime',\n ];\n }\n\n /**\n * Get the team that owns the automated report.\n */\n public function team()\n {\n return $this->belongsTo(Team::class);\n }\n\n /**\n *\n * Get the user who created the report.\n */\n public function creator(): BelongsTo\n {\n return $this->belongsTo(User::class, 'created_by');\n }\n\n public function savedSearch(): BelongsTo\n {\n return $this->belongsTo(Search::class, 'activity_search_id');\n }\n\n public function askAnythingPrompt(): BelongsTo\n {\n return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');\n }\n\n public function isAskJiminnyReport(): bool\n {\n return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;\n }\n\n public function isExpired(): bool\n {\n $expiresAt = $this->getExpiresAt();\n\n return $expiresAt !== null && $expiresAt->isPast();\n }\n\n public function canExecute(): bool\n {\n if ($this->isAskJiminnyReport()) {\n return $this->getActivitySearchId() !== null\n && $this->getAskAnythingPromptId() !== null;\n }\n\n return true;\n }\n\n public function getActivitySearchId(): ?int\n {\n return $this->getAttribute('activity_search_id');\n }\n\n public function getAskAnythingPromptId(): ?int\n {\n return $this->getAttribute('ask_anything_prompt_id');\n }\n\n public function getExpiresAt(): ?Carbon\n {\n return $this->getAttribute('expires_at');\n }\n\n public function getSavedSearch(): ?Search\n {\n return $this->getAttribute('savedSearch');\n }\n\n public function getAskAnythingPrompt(): ?AskAnythingPrompt\n {\n return $this->getAttribute('askAnythingPrompt');\n }\n\n /**\n * Get the ID of the automated report.\n *\n * @return int\n */\n public function getId(): int\n {\n return $this->getAttribute('id');\n }\n\n /**\n * Get the UUID of the automated report.\n *\n * @return string\n */\n public function getUuid(): string\n {\n return $this->getAttribute('id_string');\n }\n\n /**\n * Get the team ID of the automated report.\n *\n * @return int\n */\n public function getTeamId(): int\n {\n return $this->getAttribute('team_id');\n }\n\n /**\n * Get the type of the automated report.\n *\n * @return string\n */\n public function getType(): string\n {\n return $this->getAttribute('type');\n }\n\n /**\n * Get the status of the automated report.\n * True means active, false means inactive.\n *\n * @return bool\n */\n public function getStatus(): bool\n {\n return $this->getAttribute('status');\n }\n\n /**\n * Get the frequency of the automated report.\n *\n * @return string\n */\n public function getFrequency(): string\n {\n return $this->getAttribute('frequency');\n }\n\n /**\n * Get the from date of the automated report.\n *\n * @return Carbon|null\n */\n public function getFrom(): ?Carbon\n {\n return $this->getAttribute('from');\n }\n\n /**\n * Get the to date of the automated report.\n *\n * @return Carbon|null\n */\n public function getTo(): ?Carbon\n {\n return $this->getAttribute('to');\n }\n\n /**\n * Get the minimum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMin(): ?int\n {\n return $this->getAttribute('deal_value_min');\n }\n\n /**\n * Get the maximum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMax(): ?int\n {\n return $this->getAttribute('deal_value_max');\n }\n\n /**\n * Get the call types of the automated report.\n *\n * @return array\n */\n public function getCallTypes(): array\n {\n return $this->getAttribute('call_types') ?? [];\n }\n\n public function getMediaTypes(): array\n {\n return $this->getAttribute('media_types') ?? [];\n }\n\n /**\n * Get the minimum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMin(): ?int\n {\n return $this->getAttribute('call_duration_min');\n }\n\n /**\n * Get the maximum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMax(): ?int\n {\n return $this->getAttribute('call_duration_max');\n }\n\n /**\n * Get the groups of the automated report.\n *\n * @return array\n */\n public function getGroups(): array\n {\n return $this->getAttribute('groups') ?? [];\n }\n\n /**\n * Get the playbook categories of the automated report.\n *\n * @return array\n */\n public function getPlaybookCategories(): array\n {\n return $this->getAttribute('playbook_categories') ?? [];\n }\n\n /**\n * Get the deal at call stages of the automated report.\n *\n * @return array\n */\n public function getDealAtCallStages(): array\n {\n return $this->getAttribute('deal_at_call_stages') ?? [];\n }\n\n /**\n * Get the current deal stages of the automated report.\n *\n * @return array\n */\n public function getCurrentDealStages(): array\n {\n return $this->getAttribute('current_deal_stages') ?? [];\n }\n\n /**\n * Get the recipients of the automated report.\n *\n * @return array\n */\n public function getRecipients(): array\n {\n return $this->getAttribute('recipients') ?? [];\n }\n\n /**\n * Get the Jiminny's recipients of the automated report.\n *\n * @return array\n */\n public function getJiminnyRecipients(): array\n {\n return $this->getAttribute('jiminny_recipients') ?? [];\n }\n\n /**\n * Get the additional prompt input of the automated report.\n *\n * @return string|null\n */\n public function getAdditionalPromptInput(): ?string\n {\n return $this->getAttribute('additional_prompt_input');\n }\n\n public function getCustomName(): ?string\n {\n return $this->getAttribute('custom_name');\n }\n\n /**\n * Get the created at date of the automated report.\n *\n * @return Carbon\n */\n public function getCreatedAt(): Carbon\n {\n return $this->getAttribute('created_at');\n }\n\n /**\n * Get the updated at date of the automated report.\n *\n * @return Carbon\n */\n public function getUpdatedAt(): Carbon\n {\n return $this->getAttribute('updated_at');\n }\n\n /**\n * Get the deleted at date of the automated report.\n *\n * @return Carbon|null\n */\n public function getDeletedAt(): ?Carbon\n {\n return $this->getAttribute('deleted_at');\n }\n\n public function getTeam(): Team\n {\n return $this->getAttribute('team');\n }\n\n public function getCreator(): ?User\n {\n return $this->getAttribute('creator');\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse Illuminate\\Database\\Eloquent\\Relations\\BelongsTo;\nuse Illuminate\\Database\\Eloquent\\SoftDeletes;\nuse Illuminate\\Support\\Carbon;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPrompt;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Traits\\RequiresUUID;\n\n/**\n * Jiminny\\Models\\AutomatedReport\n *\n * @property int $id\n * @property string $uuid\n * @property int $team_id\n * @property string $type\n * @property bool $status\n * @property string $frequency\n * @property Carbon|null $from\n * @property Carbon|null $to\n * @property int|null $deal_value_min\n * @property int|null $deal_value_max\n * @property array $call_types\n * @property array $media_types\n * @property int|null $call_duration_min\n * @property int|null $call_duration_max\n * @property array|null $groups\n * @property array|null $playbook_categories\n * @property array|null $deal_at_call_stages\n * @property array|null $current_deal_stages\n * @property array $recipients\n * @property string|null $additional_prompt_input\n * @property string|null $custom_name\n * @property int|null $activity_search_id\n * @property int|null $ask_anything_prompt_id\n * @property Carbon|null $expires_at\n * @property Carbon|null $created_at\n * @property Carbon|null $updated_at\n * @property Carbon|null $deleted_at\n * @property-read \\Jiminny\\Models\\Team $team\n * @property-read \\Jiminny\\Models\\Activity\\Search|null $savedSearch\n * @property-read \\Jiminny\\Models\\AskAnything\\AskAnythingPrompt|null $askAnythingPrompt\n */\nclass AutomatedReport extends Model\n{\n use RequiresUUID;\n use SoftDeletes;\n\n protected $table = 'automated_reports';\n\n /**\n * The attributes that are mass assignable.\n *\n * @var array<int, string>\n */\n protected $fillable = [\n 'team_id',\n 'type',\n 'status',\n 'frequency',\n 'from',\n 'to',\n 'deal_value_min',\n 'deal_value_max',\n 'call_types',\n 'media_types',\n 'call_duration_min',\n 'call_duration_max',\n 'groups',\n 'playbook_categories',\n 'deal_at_call_stages',\n 'current_deal_stages',\n 'recipients',\n 'jiminny_recipients',\n 'additional_prompt_input',\n 'custom_name',\n 'created_by',\n 'activity_search_id',\n 'ask_anything_prompt_id',\n 'expires_at',\n ];\n\n protected $hidden = ['uuid'];\n\n /**\n * Get the attributes that should be cast.\n *\n * @return array<string, string>\n */\n protected function casts(): array\n {\n return [\n 'status' => 'boolean',\n 'from' => 'datetime',\n 'to' => 'datetime',\n 'call_types' => 'array',\n 'media_types' => 'array',\n 'groups' => 'array',\n 'playbook_categories' => 'array',\n 'deal_at_call_stages' => 'array',\n 'current_deal_stages' => 'array',\n 'recipients' => 'array',\n 'jiminny_recipients' => 'array',\n 'expires_at' => 'date',\n 'deleted_at' => 'datetime',\n ];\n }\n\n /**\n * Get the team that owns the automated report.\n */\n public function team()\n {\n return $this->belongsTo(Team::class);\n }\n\n /**\n *\n * Get the user who created the report.\n */\n public function creator(): BelongsTo\n {\n return $this->belongsTo(User::class, 'created_by');\n }\n\n public function savedSearch(): BelongsTo\n {\n return $this->belongsTo(Search::class, 'activity_search_id');\n }\n\n public function askAnythingPrompt(): BelongsTo\n {\n return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');\n }\n\n public function isAskJiminnyReport(): bool\n {\n return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;\n }\n\n public function isExpired(): bool\n {\n $expiresAt = $this->getExpiresAt();\n\n return $expiresAt !== null && $expiresAt->isPast();\n }\n\n public function canExecute(): bool\n {\n if ($this->isAskJiminnyReport()) {\n return $this->getActivitySearchId() !== null\n && $this->getAskAnythingPromptId() !== null;\n }\n\n return true;\n }\n\n public function getActivitySearchId(): ?int\n {\n return $this->getAttribute('activity_search_id');\n }\n\n public function getAskAnythingPromptId(): ?int\n {\n return $this->getAttribute('ask_anything_prompt_id');\n }\n\n public function getExpiresAt(): ?Carbon\n {\n return $this->getAttribute('expires_at');\n }\n\n public function getSavedSearch(): ?Search\n {\n return $this->getAttribute('savedSearch');\n }\n\n public function getAskAnythingPrompt(): ?AskAnythingPrompt\n {\n return $this->getAttribute('askAnythingPrompt');\n }\n\n /**\n * Get the ID of the automated report.\n *\n * @return int\n */\n public function getId(): int\n {\n return $this->getAttribute('id');\n }\n\n /**\n * Get the UUID of the automated report.\n *\n * @return string\n */\n public function getUuid(): string\n {\n return $this->getAttribute('id_string');\n }\n\n /**\n * Get the team ID of the automated report.\n *\n * @return int\n */\n public function getTeamId(): int\n {\n return $this->getAttribute('team_id');\n }\n\n /**\n * Get the type of the automated report.\n *\n * @return string\n */\n public function getType(): string\n {\n return $this->getAttribute('type');\n }\n\n /**\n * Get the status of the automated report.\n * True means active, false means inactive.\n *\n * @return bool\n */\n public function getStatus(): bool\n {\n return $this->getAttribute('status');\n }\n\n /**\n * Get the frequency of the automated report.\n *\n * @return string\n */\n public function getFrequency(): string\n {\n return $this->getAttribute('frequency');\n }\n\n /**\n * Get the from date of the automated report.\n *\n * @return Carbon|null\n */\n public function getFrom(): ?Carbon\n {\n return $this->getAttribute('from');\n }\n\n /**\n * Get the to date of the automated report.\n *\n * @return Carbon|null\n */\n public function getTo(): ?Carbon\n {\n return $this->getAttribute('to');\n }\n\n /**\n * Get the minimum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMin(): ?int\n {\n return $this->getAttribute('deal_value_min');\n }\n\n /**\n * Get the maximum deal value of the automated report.\n *\n * @return int|null\n */\n public function getDealValueMax(): ?int\n {\n return $this->getAttribute('deal_value_max');\n }\n\n /**\n * Get the call types of the automated report.\n *\n * @return array\n */\n public function getCallTypes(): array\n {\n return $this->getAttribute('call_types') ?? [];\n }\n\n public function getMediaTypes(): array\n {\n return $this->getAttribute('media_types') ?? [];\n }\n\n /**\n * Get the minimum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMin(): ?int\n {\n return $this->getAttribute('call_duration_min');\n }\n\n /**\n * Get the maximum call duration of the automated report.\n *\n * @return int|null\n */\n public function getCallDurationMax(): ?int\n {\n return $this->getAttribute('call_duration_max');\n }\n\n /**\n * Get the groups of the automated report.\n *\n * @return array\n */\n public function getGroups(): array\n {\n return $this->getAttribute('groups') ?? [];\n }\n\n /**\n * Get the playbook categories of the automated report.\n *\n * @return array\n */\n public function getPlaybookCategories(): array\n {\n return $this->getAttribute('playbook_categories') ?? [];\n }\n\n /**\n * Get the deal at call stages of the automated report.\n *\n * @return array\n */\n public function getDealAtCallStages(): array\n {\n return $this->getAttribute('deal_at_call_stages') ?? [];\n }\n\n /**\n * Get the current deal stages of the automated report.\n *\n * @return array\n */\n public function getCurrentDealStages(): array\n {\n return $this->getAttribute('current_deal_stages') ?? [];\n }\n\n /**\n * Get the recipients of the automated report.\n *\n * @return array\n */\n public function getRecipients(): array\n {\n return $this->getAttribute('recipients') ?? [];\n }\n\n /**\n * Get the Jiminny's recipients of the automated report.\n *\n * @return array\n */\n public function getJiminnyRecipients(): array\n {\n return $this->getAttribute('jiminny_recipients') ?? [];\n }\n\n /**\n * Get the additional prompt input of the automated report.\n *\n * @return string|null\n */\n public function getAdditionalPromptInput(): ?string\n {\n return $this->getAttribute('additional_prompt_input');\n }\n\n public function getCustomName(): ?string\n {\n return $this->getAttribute('custom_name');\n }\n\n /**\n * Get the created at date of the automated report.\n *\n * @return Carbon\n */\n public function getCreatedAt(): Carbon\n {\n return $this->getAttribute('created_at');\n }\n\n /**\n * Get the updated at date of the automated report.\n *\n * @return Carbon\n */\n public function getUpdatedAt(): Carbon\n {\n return $this->getAttribute('updated_at');\n }\n\n /**\n * Get the deleted at date of the automated report.\n *\n * @return Carbon|null\n */\n public function getDeletedAt(): ?Carbon\n {\n return $this->getAttribute('deleted_at');\n }\n\n public function getTeam(): Team\n {\n return $this->getAttribute('team');\n }\n\n public function getCreator(): ?User\n {\n return $this->getAttribute('creator');\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"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}]...
|
-7741672321923979945
|
-741568003184046556
|
click
|
accessibility
|
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
<?php
declare(strict_types=1);
namespace Jiminny\Component\Utility\Service;
use Illuminate\Cache\RateLimiter;
use Jiminny\Contracts\Http\RateLimited;
use Jiminny\Contracts\Http\RateLimitInterface;
class ProviderRateLimiter
{
protected RateLimiter $rateLimiter;
public function __construct(RateLimiter $rateLimiter)
{
$this->rateLimiter = $rateLimiter;
}
public function canMakeRequest(RateLimited $provider): bool
{
/** @var RateLimitInterface $rateLimit */
foreach ($provider->getRateLimits() as $rateLimit) {
$key = $rateLimit->getKey();
if ($this->rateLimiter->tooManyAttempts($key, $rateLimit->getQuota())) {
return false;
}
}
return true;
}
public function requestAvailableIn(RateLimited $provider): int
{
return $provider->getRateLimits()->isNotEmpty()
? $provider->getRateLimits()
->map(fn (RateLimitInterface $rateLimit): int => $this->rateLimiter->availableIn($rateLimit->getKey()))
->max()
: 0
;
}
public function incrementRequestCount(RateLimited $provider): void
{
/** @var RateLimitInterface $rateLimit */
foreach ($provider->getRateLimits() as $rateLimit) {
$this->rateLimiter->hit($rateLimit->getKey(), $rateLimit->getWindow());
}
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
4
1
6
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Carbon;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\AskAnything\AskAnythingPrompt;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Traits\RequiresUUID;
/**
* Jiminny\Models\AutomatedReport
*
* @property int $id
* @property string $uuid
* @property int $team_id
* @property string $type
* @property bool $status
* @property string $frequency
* @property Carbon|null $from
* @property Carbon|null $to
* @property int|null $deal_value_min
* @property int|null $deal_value_max
* @property array $call_types
* @property array $media_types
* @property int|null $call_duration_min
* @property int|null $call_duration_max
* @property array|null $groups
* @property array|null $playbook_categories
* @property array|null $deal_at_call_stages
* @property array|null $current_deal_stages
* @property array $recipients
* @property string|null $additional_prompt_input
* @property string|null $custom_name
* @property int|null $activity_search_id
* @property int|null $ask_anything_prompt_id
* @property Carbon|null $expires_at
* @property Carbon|null $created_at
* @property Carbon|null $updated_at
* @property Carbon|null $deleted_at
* @property-read \Jiminny\Models\Team $team
* @property-read \Jiminny\Models\Activity\Search|null $savedSearch
* @property-read \Jiminny\Models\AskAnything\AskAnythingPrompt|null $askAnythingPrompt
*/
class AutomatedReport extends Model
{
use RequiresUUID;
use SoftDeletes;
protected $table = 'automated_reports';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
'team_id',
'type',
'status',
'frequency',
'from',
'to',
'deal_value_min',
'deal_value_max',
'call_types',
'media_types',
'call_duration_min',
'call_duration_max',
'groups',
'playbook_categories',
'deal_at_call_stages',
'current_deal_stages',
'recipients',
'jiminny_recipients',
'additional_prompt_input',
'custom_name',
'created_by',
'activity_search_id',
'ask_anything_prompt_id',
'expires_at',
];
protected $hidden = ['uuid'];
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'status' => 'boolean',
'from' => 'datetime',
'to' => 'datetime',
'call_types' => 'array',
'media_types' => 'array',
'groups' => 'array',
'playbook_categories' => 'array',
'deal_at_call_stages' => 'array',
'current_deal_stages' => 'array',
'recipients' => 'array',
'jiminny_recipients' => 'array',
'expires_at' => 'date',
'deleted_at' => 'datetime',
];
}
/**
* Get the team that owns the automated report.
*/
public function team()
{
return $this->belongsTo(Team::class);
}
/**
*
* Get the user who created the report.
*/
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
public function savedSearch(): BelongsTo
{
return $this->belongsTo(Search::class, 'activity_search_id');
}
public function askAnythingPrompt(): BelongsTo
{
return $this->belongsTo(AskAnythingPrompt::class, 'ask_anything_prompt_id');
}
public function isAskJiminnyReport(): bool
{
return $this->getType() === AutomatedReportsService::TYPE_ASK_JIMINNY;
}
public function isExpired(): bool
{
$expiresAt = $this->getExpiresAt();
return $expiresAt !== null && $expiresAt->isPast();
}
public function canExecute(): bool
{
if ($this->isAskJiminnyReport()) {
return $this->getActivitySearchId() !== null
&& $this->getAskAnythingPromptId() !== null;
}
return true;
}
public function getActivitySearchId(): ?int
{
return $this->getAttribute('activity_search_id');
}
public function getAskAnythingPromptId(): ?int
{
return $this->getAttribute('ask_anything_prompt_id');
}
public function getExpiresAt(): ?Carbon
{
return $this->getAttribute('expires_at');
}
public function getSavedSearch(): ?Search
{
return $this->getAttribute('savedSearch');
}
public function getAskAnythingPrompt(): ?AskAnythingPrompt
{
return $this->getAttribute('askAnythingPrompt');
}
/**
* Get the ID of the automated report.
*
* @return int
*/
public function getId(): int
{
return $this->getAttribute('id');
}
/**
* Get the UUID of the automated report.
*
* @return string
*/
public function getUuid(): string
{
return $this->getAttribute('id_string');
}
/**
* Get the team ID of the automated report.
*
* @return int
*/
public function getTeamId(): int
{
return $this->getAttribute('team_id');
}
/**
* Get the type of the automated report.
*
* @return string
*/
public function getType(): string
{
return $this->getAttribute('type');
}
/**
* Get the status of the automated report.
* True means active, false means inactive.
*
* @return bool
*/
public function getStatus(): bool
{
return $this->getAttribute('status');
}
/**
* Get the frequency of the automated report.
*
* @return string
*/
public function getFrequency(): string
{
return $this->getAttribute('frequency');
}
/**
* Get the from date of the automated report.
*
* @return Carbon|null
*/
public function getFrom(): ?Carbon
{
return $this->getAttribute('from');
}
/**
* Get the to date of the automated report.
*
* @return Carbon|null
*/
public function getTo(): ?Carbon
{
return $this->getAttribute('to');
}
/**
* Get the minimum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMin(): ?int
{
return $this->getAttribute('deal_value_min');
}
/**
* Get the maximum deal value of the automated report.
*
* @return int|null
*/
public function getDealValueMax(): ?int
{
return $this->getAttribute('deal_value_max');
}
/**
* Get the call types of the automated report.
*
* @return array
*/
public function getCallTypes(): array
{
return $this->getAttribute('call_types') ?? [];
}
public function getMediaTypes(): array
{
return $this->getAttribute('media_types') ?? [];
}
/**
* Get the minimum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMin(): ?int
{
return $this->getAttribute('call_duration_min');
}
/**
* Get the maximum call duration of the automated report.
*
* @return int|null
*/
public function getCallDurationMax(): ?int
{
return $this->getAttribute('call_duration_max');
}
/**
* Get the groups of the automated report.
*
* @return array
*/
public function getGroups(): array
{
return $this->getAttribute('groups') ?? [];
}
/**
* Get the playbook categories of the automated report.
*
* @return array
*/
public function getPlaybookCategories(): array
{
return $this->getAttribute('playbook_categories') ?? [];
}
/**
* Get the deal at call stages of the automated report.
*
* @return array
*/
public function getDealAtCallStages(): array
{
return $this->getAttribute('deal_at_call_stages') ?? [];
}
/**
* Get the current deal stages of the automated report.
*
* @return array
*/
public function getCurrentDealStages(): array
{
return $this->getAttribute('current_deal_stages') ?? [];
}
/**
* Get the recipients of the automated report.
*
* @return array
*/
public function getRecipients(): array
{
return $this->getAttribute('recipients') ?? [];
}
/**
* Get the Jiminny's recipients of the automated report.
*
* @return array
*/
public function getJiminnyRecipients(): array
{
return $this->getAttribute('jiminny_recipients') ?? [];
}
/**
* Get the additional prompt input of the automated report.
*
* @return string|null
*/
public function getAdditionalPromptInput(): ?string
{
return $this->getAttribute('additional_prompt_input');
}
public function getCustomName(): ?string
{
return $this->getAttribute('custom_name');
}
/**
* Get the created at date of the automated report.
*
* @return Carbon
*/
public function getCreatedAt(): Carbon
{
return $this->getAttribute('created_at');
}
/**
* Get the updated at date of the automated report.
*
* @return Carbon
*/
public function getUpdatedAt(): Carbon
{
return $this->getAttribute('updated_at');
}
/**
* Get the deleted at date of the automated report.
*
* @return Carbon|null
*/
public function getDeletedAt(): ?Carbon
{
return $this->getAttribute('deleted_at');
}
public function getTeam(): Team
{
return $this->getAttribute('team');
}
public function getCreator(): ?User
{
return $this->getAttribute('creator');
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
7202
|
NULL
|
NULL
|
NULL
|
|
24533
|
1024
|
1
|
2026-05-12T09:22:25.963102+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778577745963_m1.jpg...
|
Firefox
|
JY-20725 add HS rate limit handling on activities JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app — Work...
|
True
|
github.com/jiminny/app/pull/12066#discussion_r3225 github.com/jiminny/app/pull/12066#discussion_r3225003426...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Unnamed Group
TypeError: League\Flysystem\Filesyst Unnamed Group
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
CloudWatch | us-east-2
CloudWatch | us-east-2
Unnamed Group
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
Data Explorer
Data Explorer
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
Jiminny
Jiminny
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (33)
Pull requests
(
33
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (4)
Security and quality
(
4
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20725 add HS rate limit handling on activities rematching #12066 Edit title
JY-20725 add HS rate limit handling on activities rematching
#
12066
Edit title
Unable to merge
Unable to merge
Code
Code
Open
LakyLak
LakyLak
wants to merge 4 commits into
master
master
from
JY-20725-handle-HS-search-rate-limit
JY-20725-handle-HS-search-rate-limit
Copy head branch name to clipboard
Lines changed: 775 additions & 249 deletions
Conversation (7)
Conversation
(
7
)
Commits (4)
Commits
(
4
)
Checks (6)
Checks
(
6
)
Files changed (12)...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Unnamed Group","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"CloudWatch | us-east-2","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"CloudWatch | us-east-2","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Unnamed Group","depth":4,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXRadioButton","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pull requests · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20773] User Pilot not receiving events on report generated - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20773] User Pilot not receiving events on report generated - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20776] Automated report - sentry - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20776] Automated report - sentry - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Data Explorer","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Data Explorer","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20776] Automated report - sentry - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20776] Automated report - sentry - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Skip to content","depth":6,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":10,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":12,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":9,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":9,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"All issues(g then i)","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All pull requests","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"All repositories","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":9,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":9,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (33)","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"33","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality (4)","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":11,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"JY-20725 add HS rate limit handling on activities rematching #12066 Edit title","depth":13,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12066","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Unable to merge","depth":13,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Unable to merge","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"on_screen":true,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Code","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"LakyLak","depth":15,"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"LakyLak","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 4 commits into","depth":15,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20725-handle-HS-search-rate-limit","depth":16,"on_screen":true,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725-handle-HS-search-rate-limit","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 775 additions & 249 deletions","depth":14,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (7)","depth":16,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Conversation","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Commits (4)","depth":16,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Commits","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Checks (6)","depth":16,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks","depth":17,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"6","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Files changed (12)","depth":16,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":true,"is_selected":false}]...
|
-7741515123034865846
|
-3313006157861588856
|
click
|
accessibility
|
NULL
|
Unnamed Group
TypeError: League\Flysystem\Filesyst Unnamed Group
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
CloudWatch | us-east-2
CloudWatch | us-east-2
Unnamed Group
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
Data Explorer
Data Explorer
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
Jiminny
Jiminny
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
All issues(g then i)
All pull requests
All repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (33)
Pull requests
(
33
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (4)
Security and quality
(
4
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20725 add HS rate limit handling on activities rematching #12066 Edit title
JY-20725 add HS rate limit handling on activities rematching
#
12066
Edit title
Unable to merge
Unable to merge
Code
Code
Open
LakyLak
LakyLak
wants to merge 4 commits into
master
master
from
JY-20725-handle-HS-search-rate-limit
JY-20725-handle-HS-search-rate-limit
Copy head branch name to clipboard
Lines changed: 775 additions & 249 deletions
Conversation (7)
Conversation
(
7
)
Commits (4)
Commits
(
4
)
Checks (6)
Checks
(
6
)
Files changed (12)...
|
24531
|
NULL
|
NULL
|
NULL
|
|
22952
|
979
|
32
|
2026-05-12T07:28:10.244112+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778570890244_m2.jpg...
|
Firefox
|
Data Explorer — Work
|
True
|
ws.planhat.com/jiminny/home/data-explorer/usagemet ws.planhat.com/jiminny/home/data-explorer/usagemetricdef?preview=UsageMetricDef.69f2c6529c9f21b58804f123...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
New Tab
New Tab
Jy 20820 es reindex stream model h New Tab
New Tab
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
LLM pricing overview with the most actual prices - Google Search
LLM pricing overview with the most actual prices - Google Search
Planhat
Planhat
Data Explorer
Data Explorer
Close tab
Login
Login
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Copy prompt
Edit
You said I am on https://app-eu3.planhat.com/ how to get to ws.planhat.com
You said
I am on https://app-eu3.planhat.com/ how to get to ws.planhat.com
Listen
Gemini said
Gemini said
To get to
ws.planhat.com
(which is the address for the "Upgraded Planhat" or "Next Generation" interface) while you are currently on the EU regional server (
app-eu3.planhat.com
), you have two primary options:
1. The Manual URL Change
1. The Manual URL Change
Because Planhat uses specific subdomains for different versions and regions, you can try navigating directly. However, note that
ws.planhat.com
is a global entry point for the upgraded platform.
Try navigating to:
https://ws.planhat.com
https://ws.planhat.com
If your account has been migrated to the upgraded version, it should recognize your session or prompt you to log in.
Note:
If your data is specifically hosted on the
eu3
cluster, the system may automatically redirect you to a regional version of the upgraded UI (e.g.,
ws-eu3.planhat.com
).
2. The In-App "Switch" (If Available)
2. The In-App "Switch" (If Available)
If your tenant is eligible for the upgrade but you are still in the classic "app" view, look for these UI elements:
The Top Gray Bar:
Click on your
Tenant Name/Logo
in the top-left corner. This often opens the "Global Tools" menu.
Upgrade Prompts:
In some instances, Planhat places a "Try the new Planhat" or "Upgraded Planhat" toggle in the Help menu (the
"?" icon
in the top right) or as a banner at the top of the screen.
Why use ws.planhat.com?
Why use ws.planhat.com?
You likely need this URL to access newer "Global Tools" and features that are only available in the upgraded version, such as:
Data Model Manager:
For advanced field and object configuration.
Portal Manager:
To manage customer-facing portals.
Workflows:
The newer engine for automating projects and sequences.
Federated Search:
Located in the middle of the top gray bar in the
ws
version.
Important Troubleshooting:
Permissions:
If you try to access
ws.planhat.com
and get an error or a blank screen, your user
Role
may lack the "Admin Access" or "Upgraded Access" permissions. You will need a current Admin to enable these for you in the
Settings > Users & Roles
section of the current app.
NPS Campaigns:
Note that as of recent updates, some features like NPS configuration might still require you to briefly switch back to the classic
app.planhat.com
view while they are being finalized for the
ws
environment.
Good response
Bad response
Redo
Share & export
Copy
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Fast
Microphone
Send message
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
J J Jiminny
J
Jiminny
Search Jiminny ⌘K
Search Jiminny
⌘
K
L
Lukas
Content Explorer
Content Explorer
Data Explorer
Data Explorer
Calendar
Calendar
Notifications
Notifications
More
More
Sections
Sections
CS Day-to-day
🚀 Getting started Guide
🪬 Just CS Data
👉 Daily Operations
🗓️ Weekly prep
🤑 Renewals and Upsell
🚨 Risk and Churn Analytics
Implementation
Impl Projects
Trial Opps (Under Review)
Stoyan's clients
Metric
Tab icon Dataset
Dataset
report
3 metrics
Add chart
Add chart
Name
Type
Model
Description
Created By
Created date
Updated date
Featured
Group
EndUser
3
ExecReportsLast1Day
ExecReportsLast1Day
Calculated Metrics
EndUser
-
P
Petko
Apr 30, 2026
May 11, 2026
-
ExecReportsRequest
ExecReportsRequest
User Activities
EndUser
-
-
-
-
-
automated-reports-track-interest
automated-reports-track-interest
User Activities
EndUser
-
-
-
-
-
Name
ExecReportsLast1Day
ExecReportsLast1Day
ExecReportsRequest
ExecReportsRequest
automated-reports-track-interest
automated-reports-track-interest
Type
Calculated Metrics
User Activities
User Activities
Model
EndUser
EndUser
EndUser
Description
-
-
-
Created By
P
Petko
-
-
Created date...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.24335106,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.25664893,"top":0.06304868,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":4,"bounds":{"left":0.24335106,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":5,"bounds":{"left":0.25664893,"top":0.09577015,"width":0.16888298,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira","depth":4,"bounds":{"left":0.24335106,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira","depth":5,"bounds":{"left":0.25664893,"top":0.12849163,"width":0.16140293,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.24335106,"top":0.15003991,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.25664893,"top":0.16121309,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.24335106,"top":0.18276137,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.25664893,"top":0.19393456,"width":0.039228722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pull requests · jiminny/app","depth":4,"bounds":{"left":0.24335106,"top":0.21548285,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · jiminny/app","depth":5,"bounds":{"left":0.25664893,"top":0.22665602,"width":0.04537899,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20773] User Pilot not receiving events on report generated - Jira","depth":4,"bounds":{"left":0.24335106,"top":0.2482043,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20773] User Pilot not receiving events on report generated - Jira","depth":5,"bounds":{"left":0.25664893,"top":0.25937748,"width":0.1200133,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"bounds":{"left":0.24335106,"top":0.28092578,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"bounds":{"left":0.25664893,"top":0.29209897,"width":0.19331782,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20776] Automated report - sentry - Jira","depth":4,"bounds":{"left":0.24335106,"top":0.31364724,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20776] Automated report - sentry - Jira","depth":5,"bounds":{"left":0.25664893,"top":0.32482043,"width":0.07646277,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":4,"bounds":{"left":0.24335106,"top":0.3463687,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":5,"bounds":{"left":0.25664893,"top":0.3575419,"width":0.40475398,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":4,"bounds":{"left":0.24335106,"top":0.3790902,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":5,"bounds":{"left":0.25664893,"top":0.39026338,"width":0.40475398,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.24335106,"top":0.41181165,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.25664893,"top":0.42298484,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app","depth":4,"bounds":{"left":0.24335106,"top":0.4445331,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app","depth":5,"bounds":{"left":0.25664893,"top":0.4557063,"width":0.15159574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"LLM pricing overview with the most actual prices - Google Search","depth":4,"bounds":{"left":0.24335106,"top":0.4772546,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"LLM pricing overview with the most actual prices - Google Search","depth":5,"bounds":{"left":0.25664893,"top":0.4884278,"width":0.1143617,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Planhat","depth":4,"bounds":{"left":0.24335106,"top":0.509976,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Planhat","depth":5,"bounds":{"left":0.25664893,"top":0.5211492,"width":0.012965426,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Data Explorer","depth":4,"bounds":{"left":0.24335106,"top":0.54269755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Data Explorer","depth":5,"bounds":{"left":0.25664893,"top":0.55387074,"width":0.0234375,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.31067154,"top":0.54988027,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Login","depth":4,"bounds":{"left":0.24335106,"top":0.575419,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Login","depth":5,"bounds":{"left":0.25664893,"top":0.5865922,"width":0.009474734,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.24617687,"top":0.6097366,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.24617687,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.2571476,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.2682846,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.27942154,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.29055852,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.42802528,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.43999335,"top":0.055067837,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.43733376,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.32696143,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.40940824,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.42270613,"top":0.103751,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.3226396,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.3226396,"top":0.15003991,"width":0.1200133,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said I am on https://app-eu3.planhat.com/ how to get to ws.planhat.com","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I am on https://app-eu3.planhat.com/ how to get to ws.planhat.com","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"bounds":{"left":0.43733376,"top":0.0,"width":0.013297873,"height":0.031923383},"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":20,"bounds":{"left":0.32795876,"top":0.0,"width":0.0003324468,"height":0.0007980846},"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"bounds":{"left":0.32795876,"top":0.0,"width":0.04105718,"height":0.01915403},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To get to","depth":24,"bounds":{"left":0.3309508,"top":0.0,"width":0.022606382,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ws.planhat.com","depth":24,"bounds":{"left":0.35355717,"top":0.0,"width":0.04105718,"height":0.016360734},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(which is the address for the \"Upgraded Planhat\" or \"Next Generation\" interface) while you are currently on the EU regional server (","depth":24,"bounds":{"left":0.3309508,"top":0.0,"width":0.11702128,"height":0.07861133},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app-eu3.planhat.com","depth":24,"bounds":{"left":0.3309508,"top":0.015961692,"width":0.07662899,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), you have two primary options:","depth":24,"bounds":{"left":0.3309508,"top":0.03671189,"width":0.101230055,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. The Manual URL Change","depth":23,"bounds":{"left":0.3309508,"top":0.0981644,"width":0.11702128,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. The Manual URL Change","depth":24,"bounds":{"left":0.3309508,"top":0.09976058,"width":0.068317816,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Because Planhat uses specific subdomains for different versions and regions, you can try navigating directly. However, note that","depth":24,"bounds":{"left":0.3309508,"top":0.12609737,"width":0.11336436,"height":0.057861134},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ws.planhat.com","depth":24,"bounds":{"left":0.3309508,"top":0.18834797,"width":0.04105718,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is a global entry point for the upgraded platform.","depth":24,"bounds":{"left":0.3309508,"top":0.18834797,"width":0.11319814,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Try navigating to:","depth":26,"bounds":{"left":0.34358376,"top":0.2386273,"width":0.04288564,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"https://ws.planhat.com","depth":26,"bounds":{"left":0.38646942,"top":0.2386273,"width":0.05501995,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"https://ws.planhat.com","depth":27,"bounds":{"left":0.38646942,"top":0.2386273,"width":0.05501995,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If your account has been migrated to the upgraded version, it should recognize your session or prompt you to log in.","depth":26,"bounds":{"left":0.34358376,"top":0.26815644,"width":0.104222074,"height":0.057861134},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Note:","depth":26,"bounds":{"left":0.34358376,"top":0.33918595,"width":0.013962766,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If your data is specifically hosted on the","depth":26,"bounds":{"left":0.34358376,"top":0.33918595,"width":0.10322473,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"eu3","depth":27,"bounds":{"left":0.35488698,"top":0.36113328,"width":0.008477394,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cluster, the system may automatically redirect you to a regional version of the upgraded UI (e.g.,","depth":26,"bounds":{"left":0.34358376,"top":0.35993615,"width":0.09541223,"height":0.057861134},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ws-eu3.planhat.com","depth":27,"bounds":{"left":0.34358376,"top":0.40263367,"width":0.089428194,"height":0.035514764},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":26,"bounds":{"left":0.38746676,"top":0.42218676,"width":0.0033244682,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"2. The In-App \"Switch\" (If Available)","depth":23,"bounds":{"left":0.3309508,"top":0.46288908,"width":0.11702128,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2. The In-App \"Switch\" (If Available)","depth":24,"bounds":{"left":0.3309508,"top":0.46448523,"width":0.092586435,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If your tenant is eligible for the upgrade but you are still in the classic \"app\" view, look for these UI elements:","depth":24,"bounds":{"left":0.3309508,"top":0.49082202,"width":0.116023935,"height":0.057861134},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The Top Gray Bar:","depth":26,"bounds":{"left":0.34358376,"top":0.56185156,"width":0.046210106,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Click on your","depth":26,"bounds":{"left":0.38979387,"top":0.56185156,"width":0.033909574,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tenant Name/Logo","depth":26,"bounds":{"left":0.34358376,"top":0.56185156,"width":0.09923537,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"in the top-left corner. This often opens the \"Global Tools\" menu.","depth":26,"bounds":{"left":0.34358376,"top":0.5826017,"width":0.09524601,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Upgrade Prompts:","depth":26,"bounds":{"left":0.34358376,"top":0.6328811,"width":0.047041222,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"In some instances, Planhat places a \"Try the new Planhat\" or \"Upgraded Planhat\" toggle in the Help menu (the","depth":26,"bounds":{"left":0.34358376,"top":0.6328811,"width":0.10106383,"height":0.07861133},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"\"?\" icon","depth":26,"bounds":{"left":0.36968085,"top":0.69513166,"width":0.019780586,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"in the top right) or as a banner at the top of the screen.","depth":26,"bounds":{"left":0.34358376,"top":0.69513166,"width":0.10372341,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Why use ws.planhat.com?","depth":23,"bounds":{"left":0.3309508,"top":0.7565842,"width":0.11702128,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Why use ws.planhat.com?","depth":24,"bounds":{"left":0.3309508,"top":0.7581804,"width":0.06732048,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You likely need this URL to access newer \"Global Tools\" and features that are only available in the upgraded version, such as:","depth":24,"bounds":{"left":0.3309508,"top":0.78451717,"width":0.11702128,"height":0.057861134},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Data Model Manager:","depth":26,"bounds":{"left":0.34358376,"top":0.8555467,"width":0.055352394,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"For advanced field and object configuration.","depth":26,"bounds":{"left":0.34358376,"top":0.8555467,"width":0.10289229,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Portal Manager:","depth":26,"bounds":{"left":0.34358376,"top":0.90582603,"width":0.04138963,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To manage customer-facing portals.","depth":26,"bounds":{"left":0.34358376,"top":0.90582603,"width":0.095578454,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Workflows:","depth":26,"bounds":{"left":0.34358376,"top":0.95610535,"width":0.028756648,"height":0.016360734},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The newer engine for automating projects and sequences.","depth":26,"bounds":{"left":0.34358376,"top":0.95610535,"width":0.08809841,"height":0.037110932},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Federated Search:","depth":26,"bounds":{"left":0.34358376,"top":1.0,"width":0.04737367,"height":-0.0063847303},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Located in the middle of the top gray bar in the","depth":26,"bounds":{"left":0.34358376,"top":1.0,"width":0.10239362,"height":-0.0063847303},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ws","depth":27,"bounds":{"left":0.40724733,"top":1.0,"width":0.0056515955,"height":-0.028331995},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"version.","depth":26,"bounds":{"left":0.41489363,"top":1.0,"width":0.019946808,"height":-0.027134895},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important Troubleshooting:","depth":24,"bounds":{"left":0.3309508,"top":1.0,"width":0.0709774,"height":-0.0606544},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Permissions:","depth":26,"bounds":{"left":0.34358376,"top":1.0,"width":0.03274601,"height":-0.090183616},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If you try to access","depth":26,"bounds":{"left":0.37632978,"top":1.0,"width":0.04870346,"height":-0.090183616},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ws.planhat.com","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and get an error or a blank screen, your user","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Role","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"may lack the \"Admin Access\" or \"Upgraded Access\" permissions. You will need a current Admin to enable these for you in the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Settings > Users & Roles","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"section of the current app.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"NPS Campaigns:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Note that as of recent updates, some features like NPS configuration might still require you to briefly switch back to the classic","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app.planhat.com","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"view while they are being finalized for the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ws","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"environment.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":21,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":21,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Redo","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Share & export","depth":20,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXTextArea","text":"Enter a prompt for Gemini\nencrypted","depth":20,"bounds":{"left":0.33626994,"top":0.8216281,"width":0.10638298,"height":0.01915403},"on_screen":true,"value":"Enter a prompt for Gemini\nencrypted","help_text":"","role_description":"text entry area","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enter a prompt for Gemini","depth":21,"bounds":{"left":0.34291887,"top":0.82202715,"width":0.069980055,"height":0.018355945},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"encrypted","depth":21,"bounds":{"left":0.3352726,"top":0.8216281,"width":0.0066489363,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open upload file menu","depth":20,"bounds":{"left":0.33228058,"top":0.8575419,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tools","depth":18,"bounds":{"left":0.34823802,"top":0.8575419,"width":0.013297873,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open mode picker","depth":20,"bounds":{"left":0.4034242,"top":0.85514766,"width":0.027925532,"height":0.031923383},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Fast","depth":23,"bounds":{"left":0.40874335,"top":0.8639266,"width":0.00930851,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Microphone","depth":19,"bounds":{"left":0.43334442,"top":0.85514766,"width":0.013297873,"height":0.031923383},"on_screen":true,"role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Send message","depth":19,"bounds":{"left":0.4396609,"top":0.85434955,"width":0.013962766,"height":0.033519555},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.","depth":17,"bounds":{"left":0.32845744,"top":0.90901834,"width":0.11951463,"height":0.025139665},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Your privacy & Gemini Opens in a new window","depth":17,"bounds":{"left":0.41040558,"top":0.92178774,"width":0.040059842,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your privacy & Gemini","depth":18,"bounds":{"left":0.41040558,"top":0.92178774,"width":0.040059842,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Opens in a new window","depth":19,"bounds":{"left":0.3226396,"top":0.92098963,"width":0.043218084,"height":0.012370312},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Summarize page","depth":7,"bounds":{"left":0.32829124,"top":0.95730245,"width":0.053523935,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summarize page","depth":9,"bounds":{"left":0.33394283,"top":0.96249,"width":0.042220745,"height":0.015163607},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"J J Jiminny","depth":8,"bounds":{"left":0.46409574,"top":0.058260176,"width":0.03474069,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"J","depth":11,"bounds":{"left":0.46758643,"top":0.07940942,"width":0.0023271276,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny","depth":9,"bounds":{"left":0.47539893,"top":0.06304868,"width":0.016123671,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search Jiminny ⌘K","depth":9,"bounds":{"left":0.6296542,"top":0.058260176,"width":0.21143617,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search Jiminny","depth":11,"bounds":{"left":0.6402925,"top":0.06304868,"width":0.031416222,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"⌘","depth":10,"bounds":{"left":0.82629657,"top":0.06344773,"width":0.0039893617,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"K","depth":10,"bounds":{"left":0.8351064,"top":0.06344773,"width":0.0026595744,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"L","depth":11,"bounds":{"left":0.9730718,"top":0.06304868,"width":0.002493351,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Lukas","depth":10,"bounds":{"left":0.9808843,"top":0.06304868,"width":0.012300532,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Content Explorer","depth":12,"bounds":{"left":0.46426198,"top":0.09377494,"width":0.07114362,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Content Explorer","depth":14,"bounds":{"left":0.47623006,"top":0.09936153,"width":0.03474069,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Data Explorer","depth":12,"bounds":{"left":0.46426198,"top":0.11931365,"width":0.07114362,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Data Explorer","depth":14,"bounds":{"left":0.47623006,"top":0.12490024,"width":0.027925532,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":12,"bounds":{"left":0.46426198,"top":0.14485236,"width":0.07114362,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Calendar","depth":14,"bounds":{"left":0.47623006,"top":0.15043895,"width":0.01861702,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Notifications","depth":12,"bounds":{"left":0.46426198,"top":0.17039107,"width":0.07114362,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Notifications","depth":14,"bounds":{"left":0.47623006,"top":0.17597765,"width":0.026263298,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"More","depth":12,"bounds":{"left":0.46426198,"top":0.19592977,"width":0.07114362,"height":0.023942538},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"More","depth":14,"bounds":{"left":0.47623006,"top":0.20151636,"width":0.010638298,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Sections","depth":13,"bounds":{"left":0.46426198,"top":0.23264167,"width":0.07114362,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sections","depth":15,"bounds":{"left":0.46559176,"top":0.23782921,"width":0.01662234,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CS Day-to-day","depth":16,"bounds":{"left":0.47822472,"top":0.26456505,"width":0.030751329,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"🚀 Getting started Guide","depth":18,"bounds":{"left":0.47822472,"top":0.29010376,"width":0.049700797,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"🪬 Just CS Data","depth":18,"bounds":{"left":0.47822472,"top":0.3140463,"width":0.032081116,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"👉 Daily Operations","depth":18,"bounds":{"left":0.47822472,"top":0.33798882,"width":0.03956117,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"🗓️ Weekly prep","depth":18,"bounds":{"left":0.47822472,"top":0.36193135,"width":0.03125,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"🤑 Renewals and Upsell","depth":18,"bounds":{"left":0.47822472,"top":0.3858739,"width":0.048204787,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"🚨 Risk and Churn Analytics","depth":18,"bounds":{"left":0.47822472,"top":0.40981644,"width":0.05718085,"height":0.01396648},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Implementation","depth":16,"bounds":{"left":0.47822472,"top":0.44972068,"width":0.032579787,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Impl Projects","depth":18,"bounds":{"left":0.47822472,"top":0.47525936,"width":0.026761968,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Trial Opps (Under Review)","depth":18,"bounds":{"left":0.47822472,"top":0.49920192,"width":0.054022606,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Stoyan's clients","depth":18,"bounds":{"left":0.47822472,"top":0.5231444,"width":0.032579787,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Metric","depth":18,"bounds":{"left":0.55502,"top":0.09856345,"width":0.012965426,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Tab icon Dataset","depth":16,"bounds":{"left":0.58361036,"top":0.087789305,"width":0.030585106,"height":0.035115723},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Dataset","depth":18,"bounds":{"left":0.59358376,"top":0.09856345,"width":0.015957447,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"report","depth":19,"bounds":{"left":0.5538564,"top":0.12968874,"width":0.059175532,"height":0.0207502},"on_screen":true,"value":"report","help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3 metrics","depth":19,"bounds":{"left":0.63896275,"top":0.13328013,"width":0.018949468,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add chart","depth":18,"bounds":{"left":0.8580452,"top":0.12889066,"width":0.032579787,"height":0.022346368},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Add chart","depth":20,"bounds":{"left":0.86752,"top":0.13328013,"width":0.020279255,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Name","depth":26,"bounds":{"left":0.5621675,"top":0.16679968,"width":0.012134309,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Type","depth":26,"bounds":{"left":0.6605718,"top":0.16679968,"width":0.010305851,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Model","depth":26,"bounds":{"left":0.7124335,"top":0.16679968,"width":0.012799202,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Description","depth":26,"bounds":{"left":0.76728725,"top":0.16679968,"width":0.023769947,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created By","depth":26,"bounds":{"left":0.8484042,"top":0.16679968,"width":0.022938829,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created date","depth":26,"bounds":{"left":0.88796544,"top":0.16679968,"width":0.026761968,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Updated date","depth":26,"bounds":{"left":0.92586434,"top":0.16679968,"width":0.027925532,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Featured","depth":26,"bounds":{"left":0.9637633,"top":0.16679968,"width":0.018284574,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Group","depth":26,"bounds":{"left":1.0,"top":0.16679968,"width":-0.013630271,"height":0.0131683955},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EndUser","depth":25,"bounds":{"left":0.5661569,"top":0.19752593,"width":0.01761968,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":26,"bounds":{"left":0.58776593,"top":0.19752593,"width":0.0026595744,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ExecReportsLast1Day","depth":26,"bounds":{"left":0.5628325,"top":0.22705507,"width":0.049867023,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ExecReportsLast1Day","depth":28,"bounds":{"left":0.56549203,"top":0.23064645,"width":0.04454787,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Calculated Metrics","depth":28,"bounds":{"left":0.6605718,"top":0.23064645,"width":0.038231384,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EndUser","depth":28,"bounds":{"left":0.7124335,"top":0.23064645,"width":0.017453458,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":27,"bounds":{"left":0.76728725,"top":0.23064645,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"P","depth":28,"bounds":{"left":0.8507314,"top":0.24581006,"width":0.0019946808,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Petko","depth":27,"bounds":{"left":0.85638297,"top":0.23064645,"width":0.011469414,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Apr 30, 2026","depth":26,"bounds":{"left":0.88796544,"top":0.23064645,"width":0.026928192,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"May 11, 2026","depth":26,"bounds":{"left":0.92586434,"top":0.23064645,"width":0.026595745,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":26,"bounds":{"left":1.0,"top":0.23144454,"width":-0.01628995,"height":0.0131683955},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ExecReportsRequest","depth":26,"bounds":{"left":0.5628325,"top":0.25897846,"width":0.048204787,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ExecReportsRequest","depth":28,"bounds":{"left":0.56549203,"top":0.26256984,"width":0.04288564,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"User Activities","depth":28,"bounds":{"left":0.6605718,"top":0.26256984,"width":0.029587766,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EndUser","depth":28,"bounds":{"left":0.7124335,"top":0.26256984,"width":0.017453458,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":27,"bounds":{"left":0.76728725,"top":0.26256984,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":27,"bounds":{"left":0.84973407,"top":0.26256984,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":26,"bounds":{"left":0.88796544,"top":0.26256984,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":26,"bounds":{"left":0.92586434,"top":0.26256984,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":26,"bounds":{"left":1.0,"top":0.26336792,"width":-0.01628995,"height":0.0131683955},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"automated-reports-track-interest","depth":26,"bounds":{"left":0.5628325,"top":0.29090184,"width":0.07413564,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"automated-reports-track-interest","depth":28,"bounds":{"left":0.56549203,"top":0.29449323,"width":0.06881649,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"User Activities","depth":28,"bounds":{"left":0.6605718,"top":0.29449323,"width":0.029587766,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EndUser","depth":28,"bounds":{"left":0.7124335,"top":0.29449323,"width":0.017453458,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":27,"bounds":{"left":0.76728725,"top":0.29449323,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":27,"bounds":{"left":0.84973407,"top":0.29449323,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":26,"bounds":{"left":0.88796544,"top":0.29449323,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":26,"bounds":{"left":0.92586434,"top":0.29449323,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":26,"bounds":{"left":1.0,"top":0.2952913,"width":-0.01628995,"height":0.0131683955},"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Name","depth":25,"bounds":{"left":0.5621675,"top":0.16679968,"width":0.012134309,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ExecReportsLast1Day","depth":25,"bounds":{"left":0.5628325,"top":0.22705507,"width":0.049867023,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ExecReportsLast1Day","depth":27,"bounds":{"left":0.56549203,"top":0.23064645,"width":0.04454787,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ExecReportsRequest","depth":25,"bounds":{"left":0.5628325,"top":0.25897846,"width":0.048204787,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ExecReportsRequest","depth":27,"bounds":{"left":0.56549203,"top":0.26256984,"width":0.04288564,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"automated-reports-track-interest","depth":25,"bounds":{"left":0.5628325,"top":0.29090184,"width":0.07413564,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"automated-reports-track-interest","depth":27,"bounds":{"left":0.56549203,"top":0.29449323,"width":0.06881649,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Type","depth":25,"bounds":{"left":0.6605718,"top":0.16679968,"width":0.010305851,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Calculated Metrics","depth":27,"bounds":{"left":0.6605718,"top":0.23064645,"width":0.038231384,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"User Activities","depth":27,"bounds":{"left":0.6605718,"top":0.26256984,"width":0.029587766,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"User Activities","depth":27,"bounds":{"left":0.6605718,"top":0.29449323,"width":0.029587766,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Model","depth":25,"bounds":{"left":0.7124335,"top":0.16679968,"width":0.012799202,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EndUser","depth":27,"bounds":{"left":0.7124335,"top":0.23064645,"width":0.017453458,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EndUser","depth":27,"bounds":{"left":0.7124335,"top":0.26256984,"width":0.017453458,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"EndUser","depth":27,"bounds":{"left":0.7124335,"top":0.29449323,"width":0.017453458,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Description","depth":25,"bounds":{"left":0.76728725,"top":0.16679968,"width":0.023769947,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":26,"bounds":{"left":0.76728725,"top":0.23064645,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":26,"bounds":{"left":0.76728725,"top":0.26256984,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":26,"bounds":{"left":0.76728725,"top":0.29449323,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created By","depth":25,"bounds":{"left":0.8484042,"top":0.16679968,"width":0.022938829,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"P","depth":27,"bounds":{"left":0.8507314,"top":0.24581006,"width":0.0019946808,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Petko","depth":26,"bounds":{"left":0.85638297,"top":0.23064645,"width":0.011469414,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":26,"bounds":{"left":0.84973407,"top":0.26256984,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":26,"bounds":{"left":0.84973407,"top":0.29449323,"width":0.0019946808,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Created date","depth":25,"bounds":{"left":0.88796544,"top":0.16679968,"width":0.026761968,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-7741180405124538301
|
-2876161737785770298
|
visual_change
|
accessibility
|
NULL
|
New Tab
New Tab
Jy 20820 es reindex stream model h New Tab
New Tab
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
LLM pricing overview with the most actual prices - Google Search
LLM pricing overview with the most actual prices - Google Search
Planhat
Planhat
Data Explorer
Data Explorer
Close tab
Login
Login
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Copy prompt
Edit
You said I am on https://app-eu3.planhat.com/ how to get to ws.planhat.com
You said
I am on https://app-eu3.planhat.com/ how to get to ws.planhat.com
Listen
Gemini said
Gemini said
To get to
ws.planhat.com
(which is the address for the "Upgraded Planhat" or "Next Generation" interface) while you are currently on the EU regional server (
app-eu3.planhat.com
), you have two primary options:
1. The Manual URL Change
1. The Manual URL Change
Because Planhat uses specific subdomains for different versions and regions, you can try navigating directly. However, note that
ws.planhat.com
is a global entry point for the upgraded platform.
Try navigating to:
https://ws.planhat.com
https://ws.planhat.com
If your account has been migrated to the upgraded version, it should recognize your session or prompt you to log in.
Note:
If your data is specifically hosted on the
eu3
cluster, the system may automatically redirect you to a regional version of the upgraded UI (e.g.,
ws-eu3.planhat.com
).
2. The In-App "Switch" (If Available)
2. The In-App "Switch" (If Available)
If your tenant is eligible for the upgrade but you are still in the classic "app" view, look for these UI elements:
The Top Gray Bar:
Click on your
Tenant Name/Logo
in the top-left corner. This often opens the "Global Tools" menu.
Upgrade Prompts:
In some instances, Planhat places a "Try the new Planhat" or "Upgraded Planhat" toggle in the Help menu (the
"?" icon
in the top right) or as a banner at the top of the screen.
Why use ws.planhat.com?
Why use ws.planhat.com?
You likely need this URL to access newer "Global Tools" and features that are only available in the upgraded version, such as:
Data Model Manager:
For advanced field and object configuration.
Portal Manager:
To manage customer-facing portals.
Workflows:
The newer engine for automating projects and sequences.
Federated Search:
Located in the middle of the top gray bar in the
ws
version.
Important Troubleshooting:
Permissions:
If you try to access
ws.planhat.com
and get an error or a blank screen, your user
Role
may lack the "Admin Access" or "Upgraded Access" permissions. You will need a current Admin to enable these for you in the
Settings > Users & Roles
section of the current app.
NPS Campaigns:
Note that as of recent updates, some features like NPS configuration might still require you to briefly switch back to the classic
app.planhat.com
view while they are being finalized for the
ws
environment.
Good response
Bad response
Redo
Share & export
Copy
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Fast
Microphone
Send message
Your Jiminny chats aren’t used to improve our models. Gemini is AI. It can make mistakes, so double check it.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
J J Jiminny
J
Jiminny
Search Jiminny ⌘K
Search Jiminny
⌘
K
L
Lukas
Content Explorer
Content Explorer
Data Explorer
Data Explorer
Calendar
Calendar
Notifications
Notifications
More
More
Sections
Sections
CS Day-to-day
🚀 Getting started Guide
🪬 Just CS Data
👉 Daily Operations
🗓️ Weekly prep
🤑 Renewals and Upsell
🚨 Risk and Churn Analytics
Implementation
Impl Projects
Trial Opps (Under Review)
Stoyan's clients
Metric
Tab icon Dataset
Dataset
report
3 metrics
Add chart
Add chart
Name
Type
Model
Description
Created By
Created date
Updated date
Featured
Group
EndUser
3
ExecReportsLast1Day
ExecReportsLast1Day
Calculated Metrics
EndUser
-
P
Petko
Apr 30, 2026
May 11, 2026
-
ExecReportsRequest
ExecReportsRequest
User Activities
EndUser
-
-
-
-
-
automated-reports-track-interest
automated-reports-track-interest
User Activities
EndUser
-
-
-
-
-
Name
ExecReportsLast1Day
ExecReportsLast1Day
ExecReportsRequest
ExecReportsRequest
automated-reports-track-interest
automated-reports-track-interest
Type
Calculated Metrics
User Activities
User Activities
Model
EndUser
EndUser
EndUser
Description
-
-
-
Created By
P
Petko
-
-
Created date...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
17626
|
775
|
20
|
2026-05-11T10:26:37.981550+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778495197981_m2.jpg...
|
Firefox
|
Screenpipe — Archive — Personal
|
True
|
app.screenpipe.lakylak.xyz
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
New Tab
New Tab
Screenpipe — Archive
Screenpipe — New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Screenpipe [archive.db · 12323.6MB]
Screenpipe
[archive.db · 12323.6MB]
Activity
Search
Audio
Work Report
Timetable
AI Summary
Date
07
/
05
/
2026
Calendar
Monitor
Jump to
--
:
--
Go
APP TIMELINE · CLICK TO PLAY · DRAG SCROLLBAR TO PAN
−
1×
+
Follow
Follow
10:00
10:30
11:00
11:30
12:00
12:30
13:00
13:30
14:00
14:30
15:00
15:30
16:00
16:30
17:00
17:30
18:00
18:30
19:00
19:30
20:00
20:30
21:00
21:30
7 May 14:08 · PhpStorm / faVsco.js – console [STAGING]
⏮ 30s
◀ 10s
⏸ Pause
10s ▶
30s ⏭
14:08
iTerm2
Firefox
CleanShot X
Finder
QuickTime Player
PhpStorm
Music
Control Centre
Claude
Slack
Alfred
Raycast
System Information...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.28823137,"top":0.0518755,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.30152926,"top":0.06304868,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Screenpipe — Archive","depth":4,"bounds":{"left":0.28823137,"top":0.08459697,"width":0.113696806,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Screenpipe — Archive","depth":5,"bounds":{"left":0.30152926,"top":0.09577015,"width":0.037898935,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.38962767,"top":0.09177973,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.29105717,"top":0.118914604,"width":0.108211435,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.29105717,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.3020279,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.3131649,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.32430187,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bitwarden","depth":6,"bounds":{"left":0.33543882,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Screenpipe [archive.db · 12323.6MB]","depth":7,"bounds":{"left":0.4085771,"top":0.061452515,"width":0.06698803,"height":0.017956903},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Screenpipe","depth":8,"bounds":{"left":0.4085771,"top":0.06304868,"width":0.027759308,"height":0.014764565},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[archive.db · 12323.6MB]","depth":9,"bounds":{"left":0.43766624,"top":0.06703911,"width":0.037898935,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Activity","depth":7,"bounds":{"left":0.48021942,"top":0.059856344,"width":0.024767287,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Search","depth":7,"bounds":{"left":0.5056516,"top":0.059856344,"width":0.023769947,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Audio","depth":7,"bounds":{"left":0.53008646,"top":0.059856344,"width":0.020944148,"height":0.0207502},"on_screen":true,"help_text":"No audio data in this database","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Work Report","depth":7,"bounds":{"left":0.55169547,"top":0.059856344,"width":0.03507314,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Timetable","depth":7,"bounds":{"left":0.5874335,"top":0.059856344,"width":0.029753989,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Summary","depth":7,"bounds":{"left":0.6178524,"top":0.059856344,"width":0.034075797,"height":0.0207502},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Date","depth":8,"bounds":{"left":0.93849736,"top":0.0650439,"width":0.008144947,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"07","depth":9,"bounds":{"left":0.9552859,"top":0.06464485,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":8,"bounds":{"left":0.96110374,"top":0.06464485,"width":0.0023271276,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"05","depth":9,"bounds":{"left":0.9644282,"top":0.06464485,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":8,"bounds":{"left":0.970246,"top":0.06464485,"width":0.002493351,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026","depth":9,"bounds":{"left":0.9737367,"top":0.06464485,"width":0.009474734,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Calendar","depth":8,"bounds":{"left":0.98454124,"top":0.0650439,"width":0.0051529254,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Monitor","depth":9,"bounds":{"left":0.4915226,"top":0.10853951,"width":0.013464096,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jump to","depth":9,"bounds":{"left":0.8500665,"top":0.10853951,"width":0.01412899,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"--","depth":10,"bounds":{"left":0.87017953,"top":0.10814046,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":":","depth":9,"bounds":{"left":0.87599736,"top":0.10814046,"width":0.0023271276,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"--","depth":10,"bounds":{"left":0.8793218,"top":0.10814046,"width":0.0048204786,"height":0.011572227},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Go","depth":8,"bounds":{"left":0.898105,"top":0.10454908,"width":0.012300532,"height":0.018754989},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"APP TIMELINE · CLICK TO PLAY · DRAG SCROLLBAR TO PAN","depth":10,"bounds":{"left":0.4965093,"top":0.14964086,"width":0.10571808,"height":0.009976057},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"−","depth":9,"bounds":{"left":0.8528923,"top":0.1452514,"width":0.009807181,"height":0.018754989},"on_screen":true,"help_text":"Zoom out","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1×","depth":10,"bounds":{"left":0.866855,"top":0.14924182,"width":0.004155585,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"+","depth":9,"bounds":{"left":0.8753325,"top":0.1452514,"width":0.009640957,"height":0.018754989},"on_screen":true,"help_text":"Zoom in","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Follow","depth":10,"bounds":{"left":0.88829786,"top":0.14924182,"width":0.004654255,"height":0.011173184},"on_screen":true,"help_text":"","role_description":"checkbox","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Follow","depth":10,"bounds":{"left":0.8942819,"top":0.14924182,"width":0.011136968,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10:00","depth":13,"bounds":{"left":0.50182843,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10:30","depth":13,"bounds":{"left":0.51894945,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11:00","depth":13,"bounds":{"left":0.53640294,"top":0.21947326,"width":0.0076462766,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11:30","depth":13,"bounds":{"left":0.55352396,"top":0.21947326,"width":0.0076462766,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12:00","depth":13,"bounds":{"left":0.57047874,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12:30","depth":13,"bounds":{"left":0.58759975,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"13:00","depth":13,"bounds":{"left":0.60488695,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"13:30","depth":13,"bounds":{"left":0.62200797,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14:00","depth":13,"bounds":{"left":0.639129,"top":0.21947326,"width":0.00831117,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14:30","depth":13,"bounds":{"left":0.65625,"top":0.21947326,"width":0.00831117,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"15:00","depth":13,"bounds":{"left":0.67353725,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"15:30","depth":13,"bounds":{"left":0.6906583,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16:00","depth":13,"bounds":{"left":0.7077792,"top":0.21947326,"width":0.00831117,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16:30","depth":13,"bounds":{"left":0.7250665,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17:00","depth":13,"bounds":{"left":0.74235374,"top":0.21947326,"width":0.007978723,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17:30","depth":13,"bounds":{"left":0.75947475,"top":0.21947326,"width":0.007978723,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18:00","depth":13,"bounds":{"left":0.7765958,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18:30","depth":13,"bounds":{"left":0.7937167,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"19:00","depth":13,"bounds":{"left":0.81083775,"top":0.21947326,"width":0.00831117,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"19:30","depth":13,"bounds":{"left":0.828125,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20:00","depth":13,"bounds":{"left":0.84491354,"top":0.21947326,"width":0.008643617,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20:30","depth":13,"bounds":{"left":0.8622008,"top":0.21947326,"width":0.008643617,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"21:00","depth":13,"bounds":{"left":0.87948805,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"21:30","depth":13,"bounds":{"left":0.89677525,"top":0.21947326,"width":0.008144947,"height":0.008778931},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7 May 14:08 · PhpStorm / faVsco.js – console [STAGING]","depth":10,"bounds":{"left":0.49517953,"top":0.2661612,"width":0.10605053,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"⏮ 30s","depth":9,"bounds":{"left":0.49584442,"top":0.7186752,"width":0.023936171,"height":0.02434158},"on_screen":true,"help_text":"Ctrl+←","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"◀ 10s","depth":9,"bounds":{"left":0.52244014,"top":0.71907425,"width":0.02244016,"height":0.023942538},"on_screen":true,"help_text":"←","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"⏸ Pause","depth":9,"bounds":{"left":0.5475399,"top":0.7186752,"width":0.027925532,"height":0.02434158},"on_screen":true,"help_text":"Space","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"10s ▶","depth":9,"bounds":{"left":0.578125,"top":0.71907425,"width":0.022273935,"height":0.023942538},"on_screen":true,"help_text":"→","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"30s ⏭","depth":9,"bounds":{"left":0.6030585,"top":0.7186752,"width":0.024102394,"height":0.02434158},"on_screen":true,"help_text":"Ctrl+→","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"14:08","depth":10,"bounds":{"left":0.8962766,"top":0.7254589,"width":0.009807181,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"iTerm2","depth":9,"bounds":{"left":0.4965093,"top":0.7609737,"width":0.011801862,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Firefox","depth":9,"bounds":{"left":0.51662236,"top":0.7609737,"width":0.011801862,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"CleanShot X","depth":9,"bounds":{"left":0.53673536,"top":0.7609737,"width":0.021609042,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Finder","depth":9,"bounds":{"left":0.5666556,"top":0.7609737,"width":0.010970744,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"QuickTime Player","depth":9,"bounds":{"left":0.5859375,"top":0.7609737,"width":0.030086435,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"PhpStorm","depth":9,"bounds":{"left":0.6243351,"top":0.7609737,"width":0.017287234,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Music","depth":9,"bounds":{"left":0.6499335,"top":0.7609737,"width":0.010305851,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Control Centre","depth":9,"bounds":{"left":0.66855055,"top":0.7609737,"width":0.025598405,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Claude","depth":9,"bounds":{"left":0.7024601,"top":0.7609737,"width":0.012134309,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Slack","depth":9,"bounds":{"left":0.7229056,"top":0.7609737,"width":0.009474734,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Alfred","depth":9,"bounds":{"left":0.7406915,"top":0.7609737,"width":0.010472074,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Raycast","depth":9,"bounds":{"left":0.75947475,"top":0.7609737,"width":0.013630319,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"System Information","depth":9,"bounds":{"left":0.78141624,"top":0.7609737,"width":0.033909574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-7741015084558649786
|
2828740133251811741
|
visual_change
|
accessibility
|
NULL
|
New Tab
New Tab
Screenpipe — Archive
Screenpipe — New Tab
New Tab
Screenpipe — Archive
Screenpipe — Archive
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Open history (⇧⌘H)
Open bookmarks (⌘B)
Bitwarden
Screenpipe [archive.db · 12323.6MB]
Screenpipe
[archive.db · 12323.6MB]
Activity
Search
Audio
Work Report
Timetable
AI Summary
Date
07
/
05
/
2026
Calendar
Monitor
Jump to
--
:
--
Go
APP TIMELINE · CLICK TO PLAY · DRAG SCROLLBAR TO PAN
−
1×
+
Follow
Follow
10:00
10:30
11:00
11:30
12:00
12:30
13:00
13:30
14:00
14:30
15:00
15:30
16:00
16:30
17:00
17:30
18:00
18:30
19:00
19:30
20:00
20:30
21:00
21:30
7 May 14:08 · PhpStorm / faVsco.js – console [STAGING]
⏮ 30s
◀ 10s
⏸ Pause
10s ▶
30s ⏭
14:08
iTerm2
Firefox
CleanShot X
Finder
QuickTime Player
PhpStorm
Music
Control Centre
Claude
Slack
Alfred
Raycast
System Information...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
20329
|
879
|
6
|
2026-05-11T15:16:47.887737+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778512607887_m2.jpg...
|
Code
|
Client.php (Working Tree) (Client.php) — app — 9 p Client.php (Working Tree) (Client.php) — app — 9 problems in this file • Modified...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G) - 17 pending changes
17
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Testing
Claude Code
SOURCE CONTROL
SOURCE CONTROL
Changes Section
CHANGES
CHANGES
Commit Changes on "JY-20725-handle-HS-search-rate-limit"
Commit
More Actions...
Changes
17
.env.local
M
.env.nikilocal
U
.env.other
U
ids.txt
U
raw_sql_query.sql
U
WEBHOOK_FILTERING_IMPLEMENTATION.md
U
JiminnyDebugCommand.php
app/Console/Commands
M
SimulateWebhooksCommand.php
app/Console/Commands/Crm/Hubspot
U
CreateMockAskJiminnyReportResultCommand.php
app/Console/Commands/Reports
U
RateLimitException.php
app/Exceptions
M
MatchActivityCrmData.php
app/Jobs/Crm
M
Client.php
app/Services/Crm/Hubspot
9, M
logging.php
config
M
favicon.ico
public
U
HandleHubspotRateLimitTest.php
tests/Unit/Jobs/Middleware
M
CanAccessAiReportsTest.php
tests/Unit/Policies
U
ClientTest.php
tests/Unit/Services/Crm/Hubspot
M
Graph Section...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Explorer (⇧⌘E)","depth":19,"bounds":{"left":0.0,"top":0.047885075,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.057462092,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Search (⇧⌘F)","depth":19,"bounds":{"left":0.0,"top":0.08619314,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.09577015,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Source Control (⌃⇧G) - 17 pending changes","depth":19,"bounds":{"left":0.0,"top":0.1245012,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":true},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.13407822,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":22,"bounds":{"left":0.00831117,"top":0.1452514,"width":0.003656915,"height":0.008778931},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.008643617,"top":0.14604948,"width":0.0016622341,"height":0.007980846}},{"char_start":1,"char_count":1,"bounds":{"left":0.009973404,"top":0.14604948,"width":0.0019946808,"height":0.007980846}}],"role_description":"text"},{"role":"AXRadioButton","text":"Run and Debug (⇧⌘D)","depth":19,"bounds":{"left":0.0,"top":0.16280925,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.17238627,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Remote Explorer","depth":19,"bounds":{"left":0.0,"top":0.20111732,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.21069433,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Extensions (⇧⌘X) - 2 require update","depth":19,"bounds":{"left":0.0,"top":0.23942538,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.2490024,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":22,"bounds":{"left":0.009640957,"top":0.2601756,"width":0.0019946808,"height":0.008778931},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Testing","depth":19,"bounds":{"left":0.0,"top":0.27773345,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"bounds":{"left":0.0039893617,"top":0.28731045,"width":0.007978723,"height":0.01915403},"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Claude Code","depth":19,"bounds":{"left":0.0,"top":0.3160415,"width":0.015957447,"height":0.03830806},"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"SOURCE CONTROL","depth":17,"bounds":{"left":0.022606382,"top":0.047885075,"width":0.034242023,"height":0.02793296},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"SOURCE CONTROL","depth":18,"bounds":{"left":0.022606382,"top":0.056664005,"width":0.034242023,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Changes Section","depth":21,"bounds":{"left":0.015957447,"top":0.07581804,"width":0.09940159,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"","depth":23,"bounds":{"left":0.01662234,"top":0.07821229,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"CHANGES","depth":22,"bounds":{"left":0.022606382,"top":0.07581804,"width":0.01861702,"height":0.017557861},"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"CHANGES","depth":23,"bounds":{"left":0.022606382,"top":0.079010375,"width":0.01861702,"height":0.0103751},"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"","depth":28,"bounds":{"left":0.024601065,"top":0.09896249,"width":0.07247341,"height":0.015961692},"on_screen":true,"value":"","role_description":"editor","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":29,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Commit Changes on \"JY-20725-handle-HS-search-rate-limit\"","depth":26,"bounds":{"left":0.022273935,"top":0.1245012,"width":0.08045213,"height":0.0207502},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.052526597,"top":0.12849163,"width":0.0056515955,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Commit","depth":27,"bounds":{"left":0.058843084,"top":0.1292897,"width":0.014960106,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.059175532,"top":0.1292897,"width":0.0029920214,"height":0.011173184}},{"char_start":1,"char_count":5,"bounds":{"left":0.061835106,"top":0.1292897,"width":0.011968086,"height":0.011173184}}],"role_description":"text"},{"role":"AXPopUpButton","text":"More Actions...","depth":26,"bounds":{"left":0.10305851,"top":0.1245012,"width":0.00831117,"height":0.0207502},"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":28,"bounds":{"left":0.1043883,"top":0.12849163,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"bounds":{"left":0.019614361,"top":0.15163608,"width":0.005319149,"height":0.012769354},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Changes","depth":27,"bounds":{"left":0.025930852,"top":0.15163608,"width":0.01761968,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.025930852,"top":0.15243416,"width":0.0029920214,"height":0.011971269}},{"char_start":1,"char_count":6,"bounds":{"left":0.028922873,"top":0.15243416,"width":0.014960106,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"17","depth":27,"bounds":{"left":0.10571808,"top":0.15243416,"width":0.0039893617,"height":0.0103751},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10605053,"top":0.15243416,"width":0.0016622341,"height":0.0103751}},{"char_start":1,"char_count":1,"bounds":{"left":0.10771277,"top":0.15243416,"width":0.0019946808,"height":0.0103751}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"bounds":{"left":0.021276595,"top":0.16759777,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env.local","depth":28,"bounds":{"left":0.028590426,"top":0.16919394,"width":0.01861702,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.16999201,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":9,"bounds":{"left":0.029920213,"top":0.16999201,"width":0.01761968,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"M","depth":28,"bounds":{"left":0.106715426,"top":0.16999201,"width":0.003656915,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"bounds":{"left":0.021276595,"top":0.18515563,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env.nikilocal","depth":28,"bounds":{"left":0.028590426,"top":0.1867518,"width":0.025598405,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.18754987,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":13,"bounds":{"left":0.029920213,"top":0.18754987,"width":0.024268618,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"U","depth":28,"bounds":{"left":0.107380316,"top":0.18754987,"width":0.0029920214,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"bounds":{"left":0.021276595,"top":0.20271349,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env.other","depth":28,"bounds":{"left":0.028590426,"top":0.20430966,"width":0.019946808,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.20510775,"width":0.0013297872,"height":0.011971269}},{"char_start":1,"char_count":9,"bounds":{"left":0.029920213,"top":0.20510775,"width":0.01861702,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"U","depth":28,"bounds":{"left":0.107380316,"top":0.20510775,"width":0.0029920214,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"bounds":{"left":0.021276595,"top":0.22027135,"width":0.0076462766,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ids.txt","depth":28,"bounds":{"left":0.028590426,"top":0.22186752,"width":0.012300532,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.22266561,"width":0.0009973404,"height":0.011971269}},{"char_start":1,"char_count":6,"bounds":{"left":0.029587766,"top":0.22266561,"width":0.011635638,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"U","depth":28,"bounds":{"left":0.107380316,"top":0.22266561,"width":0.0029920214,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"bounds":{"left":0.021276595,"top":0.23782921,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"raw_sql_query.sql","depth":28,"bounds":{"left":0.028590426,"top":0.23942538,"width":0.035904255,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.24022347,"width":0.0016622341,"height":0.011971269}},{"char_start":1,"char_count":16,"bounds":{"left":0.03025266,"top":0.24022347,"width":0.034242023,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"U","depth":28,"bounds":{"left":0.107380316,"top":0.24022347,"width":0.0029920214,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"bounds":{"left":0.021276595,"top":0.25538707,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"WEBHOOK_FILTERING_IMPLEMENTATION.md","depth":28,"bounds":{"left":0.028590426,"top":0.25698325,"width":0.076130316,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.25778133,"width":0.0043218085,"height":0.011971269}},{"char_start":1,"char_count":34,"bounds":{"left":0.032912236,"top":0.25778133,"width":0.08909574,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"U","depth":28,"bounds":{"left":0.107380316,"top":0.25778133,"width":0.0029920214,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"bounds":{"left":0.021276595,"top":0.27294493,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"JiminnyDebugCommand.php","depth":28,"bounds":{"left":0.028590426,"top":0.2745411,"width":0.05817819,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.2753392,"width":0.0023271276,"height":0.011971269}},{"char_start":1,"char_count":22,"bounds":{"left":0.030917553,"top":0.2753392,"width":0.055851065,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"app/Console/Commands","depth":28,"bounds":{"left":0.08843085,"top":0.2745411,"width":0.01462766,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.0887633,"top":0.27613726,"width":0.0023271276,"height":0.011173184}},{"char_start":1,"char_count":19,"bounds":{"left":0.09075798,"top":0.27613726,"width":0.043218084,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"M","depth":28,"bounds":{"left":0.106715426,"top":0.2753392,"width":0.003656915,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"bounds":{"left":0.021276595,"top":0.2905028,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SimulateWebhooksCommand.php","depth":28,"bounds":{"left":0.028590426,"top":0.29209897,"width":0.06781915,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.29289705,"width":0.0026595744,"height":0.011971269}},{"char_start":1,"char_count":26,"bounds":{"left":0.03125,"top":0.29289705,"width":0.065159574,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"app/Console/Commands/Crm/Hubspot","depth":28,"bounds":{"left":0.098071806,"top":0.29209897,"width":0.005984043,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.09840426,"top":0.29369512,"width":0.0023271276,"height":0.011173184}},{"char_start":1,"char_count":31,"bounds":{"left":0.100398935,"top":0.29369512,"width":0.06881649,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"U","depth":28,"bounds":{"left":0.107380316,"top":0.29289705,"width":0.0029920214,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"bounds":{"left":0.021276595,"top":0.30806065,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"CreateMockAskJiminnyReportResultCommand.php","depth":28,"bounds":{"left":0.028590426,"top":0.30965683,"width":0.07646277,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.3104549,"width":0.0029920214,"height":0.011971269}},{"char_start":1,"char_count":42,"bounds":{"left":0.03158245,"top":0.3104549,"width":0.099734046,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"app/Console/Commands/Reports","depth":28,"bounds":{"left":0.10538564,"top":0.3104549,"width":0.0003324468,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.13331117,"top":0.31125298,"width":0.0023271276,"height":0.011173184}},{"char_start":1,"char_count":27,"bounds":{"left":0.13530585,"top":0.31125298,"width":0.05851064,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"U","depth":28,"bounds":{"left":0.107380316,"top":0.3104549,"width":0.0029920214,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"bounds":{"left":0.021276595,"top":0.3256185,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"RateLimitException.php","depth":28,"bounds":{"left":0.028590426,"top":0.3272147,"width":0.047539894,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.32801276,"width":0.0029920214,"height":0.011971269}},{"char_start":1,"char_count":21,"bounds":{"left":0.03158245,"top":0.32801276,"width":0.04488032,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"app/Exceptions","depth":28,"bounds":{"left":0.078125,"top":0.3272147,"width":0.024933511,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.078125,"top":0.32881084,"width":0.0023271276,"height":0.011173184}},{"char_start":1,"char_count":13,"bounds":{"left":0.08045213,"top":0.32881084,"width":0.026263298,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"M","depth":28,"bounds":{"left":0.106715426,"top":0.32801276,"width":0.003656915,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"bounds":{"left":0.021276595,"top":0.34317636,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MatchActivityCrmData.php","depth":28,"bounds":{"left":0.028590426,"top":0.34477255,"width":0.054521278,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.34557062,"width":0.0039893617,"height":0.011971269}},{"char_start":1,"char_count":23,"bounds":{"left":0.032579787,"top":0.34557062,"width":0.050531916,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"app/Jobs/Crm","depth":28,"bounds":{"left":0.084773935,"top":0.34477255,"width":0.020279255,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.084773935,"top":0.3463687,"width":0.0023271276,"height":0.011173184}},{"char_start":1,"char_count":11,"bounds":{"left":0.087101065,"top":0.3463687,"width":0.023603724,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"M","depth":28,"bounds":{"left":0.106715426,"top":0.34557062,"width":0.003656915,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"bounds":{"left":0.021276595,"top":0.36073422,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Client.php","depth":28,"bounds":{"left":0.028590426,"top":0.3623304,"width":0.020611702,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.36312848,"width":0.0029920214,"height":0.011971269}},{"char_start":1,"char_count":9,"bounds":{"left":0.03158245,"top":0.36312848,"width":0.01761968,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"app/Services/Crm/Hubspot","depth":28,"bounds":{"left":0.05119681,"top":0.3623304,"width":0.028590426,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.05119681,"top":0.3639266,"width":0.0023271276,"height":0.011173184}},{"char_start":1,"char_count":23,"bounds":{"left":0.053523935,"top":0.3639266,"width":0.047539894,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"9, M","depth":28,"bounds":{"left":0.10206117,"top":0.36312848,"width":0.00831117,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.10206117,"top":0.36312848,"width":0.0026595744,"height":0.011173184}},{"char_start":1,"char_count":3,"bounds":{"left":0.10472074,"top":0.36312848,"width":0.005984043,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"bounds":{"left":0.021276595,"top":0.3782921,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"logging.php","depth":28,"bounds":{"left":0.028590426,"top":0.37988827,"width":0.023936171,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.38068634,"width":0.0009973404,"height":0.011971269}},{"char_start":1,"char_count":10,"bounds":{"left":0.029587766,"top":0.38068634,"width":0.022938829,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"config","depth":28,"bounds":{"left":0.05418883,"top":0.38068634,"width":0.011968086,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.054521278,"top":0.38148445,"width":0.0023271276,"height":0.011173184}},{"char_start":1,"char_count":5,"bounds":{"left":0.05651596,"top":0.38148445,"width":0.009640957,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"M","depth":28,"bounds":{"left":0.106715426,"top":0.38068634,"width":0.003656915,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"bounds":{"left":0.021276595,"top":0.39584997,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"favicon.ico","depth":28,"bounds":{"left":0.028590426,"top":0.39744613,"width":0.021609042,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.3982442,"width":0.0016622341,"height":0.011971269}},{"char_start":1,"char_count":10,"bounds":{"left":0.03025266,"top":0.3982442,"width":0.020279255,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"public","depth":28,"bounds":{"left":0.05219415,"top":0.3982442,"width":0.011303191,"height":0.011173184},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.05219415,"top":0.3990423,"width":0.0026595744,"height":0.011173184}},{"char_start":1,"char_count":5,"bounds":{"left":0.054521278,"top":0.3990423,"width":0.008976064,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"U","depth":28,"bounds":{"left":0.107380316,"top":0.3982442,"width":0.0029920214,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"bounds":{"left":0.021276595,"top":0.41340783,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HandleHubspotRateLimitTest.php","depth":28,"bounds":{"left":0.028590426,"top":0.415004,"width":0.06781915,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.41580206,"width":0.0033244682,"height":0.011971269}},{"char_start":1,"char_count":29,"bounds":{"left":0.031914894,"top":0.41580206,"width":0.064494684,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"tests/Unit/Jobs/Middleware","depth":28,"bounds":{"left":0.098071806,"top":0.415004,"width":0.004986702,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.098071806,"top":0.41660017,"width":0.0016622341,"height":0.011173184}},{"char_start":1,"char_count":25,"bounds":{"left":0.09940159,"top":0.41660017,"width":0.04886968,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"M","depth":28,"bounds":{"left":0.106715426,"top":0.41580206,"width":0.003656915,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"bounds":{"left":0.021276595,"top":0.4309657,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"CanAccessAiReportsTest.php","depth":28,"bounds":{"left":0.028590426,"top":0.43256184,"width":0.059175532,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.43335995,"width":0.0029920214,"height":0.011971269}},{"char_start":1,"char_count":25,"bounds":{"left":0.03158245,"top":0.43335995,"width":0.05618351,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"tests/Unit/Policies","depth":28,"bounds":{"left":0.089428194,"top":0.43256184,"width":0.013962766,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.08976064,"top":0.43415803,"width":0.0013297872,"height":0.011173184}},{"char_start":1,"char_count":18,"bounds":{"left":0.091090426,"top":0.43415803,"width":0.031914894,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"U","depth":28,"bounds":{"left":0.107380316,"top":0.43335995,"width":0.0029920214,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"bounds":{"left":0.021276595,"top":0.44852355,"width":0.0063164895,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ClientTest.php","depth":28,"bounds":{"left":0.028590426,"top":0.4501197,"width":0.028922873,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.028590426,"top":0.4509178,"width":0.0029920214,"height":0.011971269}},{"char_start":1,"char_count":13,"bounds":{"left":0.03158245,"top":0.4509178,"width":0.026263298,"height":0.011971269}}],"role_description":"text"},{"role":"AXStaticText","text":"tests/Unit/Services/Crm/Hubspot","depth":28,"bounds":{"left":0.059507977,"top":0.4501197,"width":0.043882977,"height":0.011971269},"on_screen":true,"lines":[{"char_start":0,"char_count":1,"bounds":{"left":0.059507977,"top":0.4517159,"width":0.0016622341,"height":0.011173184}},{"char_start":1,"char_count":30,"bounds":{"left":0.060837764,"top":0.4517159,"width":0.059507977,"height":0.011173184}}],"role_description":"text"},{"role":"AXStaticText","text":"M","depth":28,"bounds":{"left":0.106715426,"top":0.4509178,"width":0.003656915,"height":0.011173184},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Graph Section","depth":21,"bounds":{"left":0.015957447,"top":0.60015965,"width":0.09940159,"height":0.017557861},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true}]...
|
-7740823318290404934
|
-389183615073049652
|
click
|
accessibility
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G) - 17 pending changes
17
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Testing
Claude Code
SOURCE CONTROL
SOURCE CONTROL
Changes Section
CHANGES
CHANGES
Commit Changes on "JY-20725-handle-HS-search-rate-limit"
Commit
More Actions...
Changes
17
.env.local
M
.env.nikilocal
U
.env.other
U
ids.txt
U
raw_sql_query.sql
U
WEBHOOK_FILTERING_IMPLEMENTATION.md
U
JiminnyDebugCommand.php
app/Console/Commands
M
SimulateWebhooksCommand.php
app/Console/Commands/Crm/Hubspot
U
CreateMockAskJiminnyReportResultCommand.php
app/Console/Commands/Reports
U
RateLimitException.php
app/Exceptions
M
MatchActivityCrmData.php
app/Jobs/Crm
M
Client.php
app/Services/Crm/Hubspot
9, M
logging.php
config
M
favicon.ico
public
U
HandleHubspotRateLimitTest.php
tests/Unit/Jobs/Middleware
M
CanAccessAiReportsTest.php
tests/Unit/Policies
U
ClientTest.php
tests/Unit/Services/Crm/Hubspot
M
Graph Section...
|
NULL
|
/Users/lukas/jiminny/app/app/Services/Crm/Hubspot/ /Users/lukas/jiminny/app/app/Services/Crm/Hubspot/Client.php...
|
NULL
|
NULL
|
|
20342
|
878
|
11
|
2026-05-11T15:17:58.728085+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-11/1778 /Users/lukas/.screenpipe/data/data/2026-05-11/1778512678728_m1.jpg...
|
Code
|
RateLimitException.php — app — Modified
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G) - 17 pending changes
17
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Testing
Claude Code
SOURCE CONTROL
SOURCE CONTROL
Changes Section
CHANGES
CHANGES
Commit Changes on "JY-20725-handle-HS-search-rate-limit"
Commit
More Actions...
Changes
17
.env.local
M
.env.nikilocal
U
.env.other
U
ids.txt
U
raw_sql_query.sql
U
WEBHOOK_FILTERING_IMPLEMENTATION.md
U
JiminnyDebugCommand.php
app/Console/Commands
M
SimulateWebhooksCommand.php
app/Console/Commands/Crm/Hubspot
U
CreateMockAskJiminnyReportResultCommand.php
app/Console/Commands/Reports
U
RateLimitException.php
app/Exceptions
M
MatchActivityCrmData.php
app/Jobs/Crm
M
Client.php
app/Services/Crm/Hubspot
9, M
logging.php
config
M
favicon.ico
public
U
HandleHubspotRateLimitTest.php
tests/Unit/Jobs/Middleware
M
CanAccessAiReportsTest.php
tests/Unit/Policies
U
ClientTest.php
tests/Unit/Services/Crm/Hubspot
M
Graph Section...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Explorer (⇧⌘E)","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Search (⇧⌘F)","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Source Control (⌃⇧G) - 17 pending changes","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true,"is_expanded":true},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Run and Debug (⇧⌘D)","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Remote Explorer","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Extensions (⇧⌘X) - 2 require update","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Testing","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":22,"on_screen":true,"role_description":"text"},{"role":"AXRadioButton","text":"Claude Code","depth":19,"on_screen":true,"role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"SOURCE CONTROL","depth":17,"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"SOURCE CONTROL","depth":18,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Changes Section","depth":21,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXHeading","text":"CHANGES","depth":22,"on_screen":true,"role_description":"heading"},{"role":"AXStaticText","text":"CHANGES","depth":23,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"","depth":28,"on_screen":true,"value":"","role_description":"editor","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":29,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Commit Changes on \"JY-20725-handle-HS-search-rate-limit\"","depth":26,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Commit","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXPopUpButton","text":"More Actions...","depth":26,"on_screen":true,"role_description":"pop-up button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Changes","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":27,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env.local","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"M","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env.nikilocal","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"U","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":".env.other","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"U","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ids.txt","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"U","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"raw_sql_query.sql","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"U","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"WEBHOOK_FILTERING_IMPLEMENTATION.md","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"U","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"JiminnyDebugCommand.php","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"app/Console/Commands","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"M","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"SimulateWebhooksCommand.php","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"app/Console/Commands/Crm/Hubspot","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"U","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"CreateMockAskJiminnyReportResultCommand.php","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"app/Console/Commands/Reports","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"U","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"RateLimitException.php","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"app/Exceptions","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"M","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"MatchActivityCrmData.php","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"app/Jobs/Crm","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"M","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"Client.php","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"app/Services/Crm/Hubspot","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"9, M","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"logging.php","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"config","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"M","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"favicon.ico","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"public","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"U","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"HandleHubspotRateLimitTest.php","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"tests/Unit/Jobs/Middleware","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"M","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"CanAccessAiReportsTest.php","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"tests/Unit/Policies","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"U","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"ClientTest.php","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"tests/Unit/Services/Crm/Hubspot","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"M","depth":28,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Graph Section","depth":21,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true}]...
|
-7740823318290404934
|
-389183615073049652
|
click
|
accessibility
|
NULL
|
Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧ Explorer (⇧⌘E)
Search (⇧⌘F)
Source Control (⌃⇧G) - 17 pending changes
17
Run and Debug (⇧⌘D)
Remote Explorer
Extensions (⇧⌘X) - 2 require update
2
Testing
Claude Code
SOURCE CONTROL
SOURCE CONTROL
Changes Section
CHANGES
CHANGES
Commit Changes on "JY-20725-handle-HS-search-rate-limit"
Commit
More Actions...
Changes
17
.env.local
M
.env.nikilocal
U
.env.other
U
ids.txt
U
raw_sql_query.sql
U
WEBHOOK_FILTERING_IMPLEMENTATION.md
U
JiminnyDebugCommand.php
app/Console/Commands
M
SimulateWebhooksCommand.php
app/Console/Commands/Crm/Hubspot
U
CreateMockAskJiminnyReportResultCommand.php
app/Console/Commands/Reports
U
RateLimitException.php
app/Exceptions
M
MatchActivityCrmData.php
app/Jobs/Crm
M
Client.php
app/Services/Crm/Hubspot
9, M
logging.php
config
M
favicon.ico
public
U
HandleHubspotRateLimitTest.php
tests/Unit/Jobs/Middleware
M
CanAccessAiReportsTest.php
tests/Unit/Policies
U
ClientTest.php
tests/Unit/Services/Crm/Hubspot
M
Graph Section...
|
NULL
|
/Users/lukas/jiminny/app/app/Exceptions/RateLimitE /Users/lukas/jiminny/app/app/Exceptions/RateLimitException.php...
|
NULL
|
NULL
|
|
3996
|
143
|
1
|
2026-05-07T12:56:26.972882+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-07/1778 /Users/lukas/.screenpipe/data/data/2026-05-07/1778158586972_m1.jpg...
|
iTerm2
|
NULL
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
iTerm2ShellEditViewSessionScriptsProfilesWindowHel iTerm2ShellEditViewSessionScriptsProfilesWindowHelpLukas/Stefka 121 - in 1h 34 m100% <478DEV (docker)*3-zshDOCKERDEV (docker)H82APP (-zsh)worker:worker_00:startedworker-analytics:worker-analytics_00:startedworker-audio:worker-audio_00: startedworker-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: startedroot@docker_lamp_1:/home/jiminny#php artisan jiminny: debugMatchingcontact 0Matchingcontact 1Matchingcontact 2Matchingcontact3Matchingcontact4Matchingcontact5Matching contact 6Matchingcontact 7Matching contact 8Matching contact 9root@docker_lamp_1:/home/jiminny# php artisan jiminny:debugMatching contact 0Matching contact 1Matchingcontact 2Matchingcontact 3Matching contact 4Matching contact 5Matching contact6Matching contact 7Matching contact 8Matching contact 9root@docker_lamp_1:/home/jiminny# php artisan optimize:clear && supervisorctl restart allINFOClearing cached bootstrap files.configcachecompiledeventsroutesviews• 84screenpipe*•$5-zshThu 7 May 15:56:26T81₴6DEV6.01ms DONE16.11ms DONE2.91ms DONE2.27ms DONE3.11ms DONE18.41ms DONE...
|
NULL
|
-7740704058518218087
|
NULL
|
visual_change
|
ocr
|
NULL
|
iTerm2ShellEditViewSessionScriptsProfilesWindowHel iTerm2ShellEditViewSessionScriptsProfilesWindowHelpLukas/Stefka 121 - in 1h 34 m100% <478DEV (docker)*3-zshDOCKERDEV (docker)H82APP (-zsh)worker:worker_00:startedworker-analytics:worker-analytics_00:startedworker-audio:worker-audio_00: startedworker-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: startedroot@docker_lamp_1:/home/jiminny#php artisan jiminny: debugMatchingcontact 0Matchingcontact 1Matchingcontact 2Matchingcontact3Matchingcontact4Matchingcontact5Matching contact 6Matchingcontact 7Matching contact 8Matching contact 9root@docker_lamp_1:/home/jiminny# php artisan jiminny:debugMatching contact 0Matching contact 1Matchingcontact 2Matchingcontact 3Matching contact 4Matching contact 5Matching contact6Matching contact 7Matching contact 8Matching contact 9root@docker_lamp_1:/home/jiminny# php artisan optimize:clear && supervisorctl restart allINFOClearing cached bootstrap files.configcachecompiledeventsroutesviews• 84screenpipe*•$5-zshThu 7 May 15:56:26T81₴6DEV6.01ms DONE16.11ms DONE2.91ms DONE2.27ms DONE3.11ms DONE18.41ms DONE...
|
3995
|
NULL
|
NULL
|
NULL
|
|
23918
|
1003
|
86
|
2026-05-12T08:30:47.295367+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-12/1778 /Users/lukas/.screenpipe/data/data/2026-05-12/1778574647295_m2.jpg...
|
Firefox
|
Jiminny — Work
|
True
|
app.jiminny.com/ai-reports
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
New Tab
New Tab
Jy 20820 es reindex stream model h New Tab
New Tab
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
Data Explorer
Data Explorer
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
Jiminny
Jiminny
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
6
6
AI Reports
AI Reports
Ask Jiminny reports
Ask Jiminny reports
Report name
5-19 Apr, 2026
2026
Mo
Tu
We
Th
Fr
Sa
Su
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
5
Coaching Profiles × Report Type
Coaching Profiles
×
Report Type
Clear all
NAME
FREQUENCY
SHARED
DATE
ACTIONS
Coaching Profiles - 6 - 12 Apr 2026 - Client Success, UK Sales
Weekly
+1
13/04/2026
Coaching Profiles Podcast - 6 - 12 Apr 2026 - Client Success, UK Sales
Weekly
+1
13/04/2026
Coaching Profiles - 30 Mar - 5 Apr 2026 - Client Success, UK Sales
Weekly
+1
06/04/2026
Coaching Profiles Podcast - 30 Mar - 5 Apr 2026 - Client Success, UK Sales
Weekly
+1
06/04/2026
You are currently impersonating Adelina Petrova...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.3643617,"top":0.0518755,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.3776596,"top":0.06304868,"width":0.014960106,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":4,"bounds":{"left":0.3643617,"top":0.08459697,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app","depth":5,"bounds":{"left":0.3776596,"top":0.09577015,"width":0.16888298,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira","depth":4,"bounds":{"left":0.3643617,"top":0.11731844,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira","depth":5,"bounds":{"left":0.3776596,"top":0.12849163,"width":0.16140293,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":4,"bounds":{"left":0.3643617,"top":0.15003991,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app","depth":5,"bounds":{"left":0.3776596,"top":0.16121309,"width":0.18816489,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.3643617,"top":0.18276137,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.3776596,"top":0.19393456,"width":0.039228722,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pull requests · jiminny/app","depth":4,"bounds":{"left":0.3643617,"top":0.21548285,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests · jiminny/app","depth":5,"bounds":{"left":0.3776596,"top":0.22665602,"width":0.04537899,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20773] User Pilot not receiving events on report generated - Jira","depth":4,"bounds":{"left":0.3643617,"top":0.2482043,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20773] User Pilot not receiving events on report generated - Jira","depth":5,"bounds":{"left":0.3776596,"top":0.25937748,"width":0.1200133,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"bounds":{"left":0.3643617,"top":0.28092578,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"bounds":{"left":0.3776596,"top":0.29209897,"width":0.19331782,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20776] Automated report - sentry - Jira","depth":4,"bounds":{"left":0.3643617,"top":0.31364724,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20776] Automated report - sentry - Jira","depth":5,"bounds":{"left":0.3776596,"top":0.32482043,"width":0.07646277,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":4,"bounds":{"left":0.3643617,"top":0.3463687,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"TypeError: League\\Flysystem\\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app","depth":5,"bounds":{"left":0.3776596,"top":0.3575419,"width":0.40475398,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.3643617,"top":0.3790902,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"bounds":{"left":0.3776596,"top":0.39026338,"width":0.10106383,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app","depth":4,"bounds":{"left":0.3643617,"top":0.41181165,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app","depth":5,"bounds":{"left":0.3776596,"top":0.42298484,"width":0.15159574,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Data Explorer","depth":4,"bounds":{"left":0.3643617,"top":0.4445331,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Data Explorer","depth":5,"bounds":{"left":0.3776596,"top":0.4557063,"width":0.0234375,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20776] Automated report - sentry - Jira","depth":4,"bounds":{"left":0.3643617,"top":0.4772546,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20776] Automated report - sentry - Jira","depth":5,"bounds":{"left":0.3776596,"top":0.4884278,"width":0.07646277,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.3643617,"top":0.509976,"width":0.07962101,"height":0.032721467},"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.3776596,"top":0.5211492,"width":0.013131649,"height":0.010774142},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.43168217,"top":0.5171588,"width":0.007978723,"height":0.01915403},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.3671875,"top":0.5442937,"width":0.07413564,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.3671875,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.37815824,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.38929522,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.40043217,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.41156915,"top":0.97007185,"width":0.010638298,"height":0.025538707},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"6","depth":12,"bounds":{"left":0.44664228,"top":0.91380686,"width":0.015957447,"height":0.035115723},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"6","depth":14,"bounds":{"left":0.45611703,"top":0.9173983,"width":0.0023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"AI Reports","depth":13,"bounds":{"left":0.47323802,"top":0.06943336,"width":0.031416222,"height":0.019553073},"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"AI Reports","depth":14,"bounds":{"left":0.47323802,"top":0.06943336,"width":0.031416222,"height":0.019553073},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Ask Jiminny reports","depth":13,"bounds":{"left":0.93267953,"top":0.06464485,"width":0.059341755,"height":0.028731046},"on_screen":true,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Jiminny reports","depth":14,"bounds":{"left":0.94630986,"top":0.07222666,"width":0.04105718,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Report name","depth":17,"bounds":{"left":0.48603722,"top":0.10933759,"width":0.058011968,"height":0.019952115},"on_screen":true,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"5-19 Apr, 2026","depth":20,"bounds":{"left":0.563996,"top":0.114924185,"width":0.029089095,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2026","depth":25,"bounds":{"left":0.54853725,"top":0.15522745,"width":0.00930851,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mo","depth":24,"bounds":{"left":0.5093085,"top":0.1783719,"width":0.005984043,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tu","depth":24,"bounds":{"left":0.5221077,"top":0.1783719,"width":0.0043218085,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"We","depth":24,"bounds":{"left":0.53307843,"top":0.1783719,"width":0.0063164895,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Th","depth":24,"bounds":{"left":0.54587764,"top":0.1783719,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Fr","depth":24,"bounds":{"left":0.5581782,"top":0.1783719,"width":0.0039893617,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Sa","depth":24,"bounds":{"left":0.56998,"top":0.1783719,"width":0.0043218085,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Su","depth":24,"bounds":{"left":0.5817819,"top":0.1783719,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30","depth":24,"bounds":{"left":0.5099734,"top":0.20151636,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"31","depth":24,"bounds":{"left":0.5219415,"top":0.20151636,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":24,"bounds":{"left":0.53507316,"top":0.20151636,"width":0.0023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":24,"bounds":{"left":0.54704124,"top":0.20151636,"width":0.0023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":24,"bounds":{"left":0.5590093,"top":0.20151636,"width":0.0023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4","depth":24,"bounds":{"left":0.5709774,"top":0.20151636,"width":0.0023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":24,"bounds":{"left":0.58294547,"top":0.20151636,"width":0.0023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"6","depth":24,"bounds":{"left":0.51113695,"top":0.22466081,"width":0.0023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"7","depth":24,"bounds":{"left":0.523105,"top":0.22466081,"width":0.0023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"8","depth":24,"bounds":{"left":0.53507316,"top":0.22466081,"width":0.0023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"9","depth":24,"bounds":{"left":0.54704124,"top":0.22466081,"width":0.0023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"10","depth":24,"bounds":{"left":0.5578458,"top":0.22466081,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11","depth":24,"bounds":{"left":0.56981385,"top":0.22466081,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"12","depth":24,"bounds":{"left":0.5817819,"top":0.22466081,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"13","depth":24,"bounds":{"left":0.5099734,"top":0.24780527,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14","depth":24,"bounds":{"left":0.5219415,"top":0.24780527,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"15","depth":24,"bounds":{"left":0.53390956,"top":0.24780527,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16","depth":24,"bounds":{"left":0.54587764,"top":0.24780527,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17","depth":24,"bounds":{"left":0.5578458,"top":0.24780527,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"18","depth":24,"bounds":{"left":0.56981385,"top":0.24780527,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"19","depth":24,"bounds":{"left":0.5817819,"top":0.24780527,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20","depth":24,"bounds":{"left":0.5099734,"top":0.27094972,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"21","depth":24,"bounds":{"left":0.5219415,"top":0.27094972,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22","depth":24,"bounds":{"left":0.53390956,"top":0.27094972,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"23","depth":24,"bounds":{"left":0.54587764,"top":0.27094972,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"24","depth":24,"bounds":{"left":0.5578458,"top":0.27094972,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"25","depth":24,"bounds":{"left":0.56981385,"top":0.27094972,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"26","depth":24,"bounds":{"left":0.5817819,"top":0.27094972,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"27","depth":24,"bounds":{"left":0.5099734,"top":0.29409418,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"28","depth":24,"bounds":{"left":0.5219415,"top":0.29409418,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"29","depth":24,"bounds":{"left":0.53390956,"top":0.29409418,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30","depth":24,"bounds":{"left":0.54587764,"top":0.29409418,"width":0.004654255,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":24,"bounds":{"left":0.5590093,"top":0.29409418,"width":0.0023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":24,"bounds":{"left":0.5709774,"top":0.29409418,"width":0.0023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"3","depth":24,"bounds":{"left":0.58294547,"top":0.29409418,"width":0.0023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4","depth":24,"bounds":{"left":0.51113695,"top":0.31723863,"width":0.0023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":24,"bounds":{"left":0.523105,"top":0.31723863,"width":0.0023271276,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXComboBox","text":"Coaching Profiles × Report Type","depth":16,"bounds":{"left":0.63380986,"top":0.10933759,"width":0.06615692,"height":0.028731046},"on_screen":true,"value":"Coaching Profiles × Report Type","help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Coaching Profiles","depth":20,"bounds":{"left":0.63613695,"top":0.11691939,"width":0.036402926,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"×","depth":21,"bounds":{"left":0.67486703,"top":0.11652035,"width":0.0028257978,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Report Type","depth":18,"on_screen":false,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Clear all","depth":13,"bounds":{"left":0.7062833,"top":0.112529926,"width":0.028424202,"height":0.015961692},"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"NAME","depth":16,"bounds":{"left":0.47290558,"top":0.17398244,"width":0.012965426,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"FREQUENCY","depth":16,"bounds":{"left":0.6978058,"top":0.17398244,"width":0.026263298,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SHARED","depth":16,"bounds":{"left":0.7727726,"top":0.17398244,"width":0.017453458,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"DATE","depth":16,"bounds":{"left":0.84773934,"top":0.17398244,"width":0.011136968,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ACTIONS","depth":16,"bounds":{"left":0.9227061,"top":0.17398244,"width":0.019115692,"height":0.012769354},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Coaching Profiles - 6 - 12 Apr 2026 - Client Success, UK Sales","depth":17,"bounds":{"left":0.48620346,"top":0.22067039,"width":0.12799202,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Weekly","depth":17,"bounds":{"left":0.6978058,"top":0.22067039,"width":0.014960106,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+1","depth":17,"bounds":{"left":0.8005319,"top":0.22146848,"width":0.004488032,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"13/04/2026","depth":17,"bounds":{"left":0.84773934,"top":0.22067039,"width":0.024102394,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Coaching Profiles Podcast - 6 - 12 Apr 2026 - Client Success, UK Sales","depth":17,"bounds":{"left":0.48620346,"top":0.2677574,"width":0.14577793,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Weekly","depth":17,"bounds":{"left":0.6978058,"top":0.2677574,"width":0.014960106,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+1","depth":17,"bounds":{"left":0.8005319,"top":0.26855546,"width":0.004488032,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"13/04/2026","depth":17,"bounds":{"left":0.84773934,"top":0.2677574,"width":0.024102394,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Coaching Profiles - 30 Mar - 5 Apr 2026 - Client Success, UK Sales","depth":17,"bounds":{"left":0.48620346,"top":0.31484437,"width":0.13763298,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Weekly","depth":17,"bounds":{"left":0.6978058,"top":0.31484437,"width":0.014960106,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+1","depth":17,"bounds":{"left":0.8005319,"top":0.31564245,"width":0.004488032,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"06/04/2026","depth":17,"bounds":{"left":0.84773934,"top":0.31484437,"width":0.024102394,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Coaching Profiles Podcast - 30 Mar - 5 Apr 2026 - Client Success, UK Sales","depth":17,"bounds":{"left":0.48620346,"top":0.36193135,"width":0.15558511,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Weekly","depth":17,"bounds":{"left":0.6978058,"top":0.36193135,"width":0.014960106,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+1","depth":17,"bounds":{"left":0.8005319,"top":0.36272946,"width":0.004488032,"height":0.011971269},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"06/04/2026","depth":17,"bounds":{"left":0.84773934,"top":0.36193135,"width":0.024102394,"height":0.0131683955},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You are currently impersonating Adelina Petrova","depth":11,"bounds":{"left":0.66638964,"top":0.053072624,"width":0.10073138,"height":0.013567438},"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-7738990721717645671
|
-2592645515586127861
|
click
|
accessibility
|
NULL
|
New Tab
New Tab
Jy 20820 es reindex stream model h New Tab
New Tab
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
Jy 20820 es reindex stream model hydration by Vasil-Jiminny · Pull Request #12059 · jiminny/app
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
[JY-20725] [HubSpot] Optimise CRM rematching on delete hubspot accounts/contacts - Jira
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
JY-20725 add HS rate limit handling on activities rematching by LakyLak · Pull Request #12066 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Pull requests · jiminny/app
Pull requests · jiminny/app
[JY-20773] User Pilot not receiving events on report generated - Jira
[JY-20773] User Pilot not receiving events on report generated - Jira
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
TypeError: League\Flysystem\Filesystem::has(): Argument #1 ($location) must be of type string, null given, called in /home/jiminny/vendor/laravel/framework/src/Illuminate/Filesystem/FilesystemAdapter.php on line 218 — jiminny — app
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
JY-20625 | JY-20742 | MCP POC by yalokin-jiminny · Pull Request #12036 · jiminny/app
Data Explorer
Data Explorer
[JY-20776] Automated report - sentry - Jira
[JY-20776] Automated report - sentry - Jira
Jiminny
Jiminny
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
6
6
AI Reports
AI Reports
Ask Jiminny reports
Ask Jiminny reports
Report name
5-19 Apr, 2026
2026
Mo
Tu
We
Th
Fr
Sa
Su
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
5
Coaching Profiles × Report Type
Coaching Profiles
×
Report Type
Clear all
NAME
FREQUENCY
SHARED
DATE
ACTIONS
Coaching Profiles - 6 - 12 Apr 2026 - Client Success, UK Sales
Weekly
+1
13/04/2026
Coaching Profiles Podcast - 6 - 12 Apr 2026 - Client Success, UK Sales
Weekly
+1
13/04/2026
Coaching Profiles - 30 Mar - 5 Apr 2026 - Client Success, UK Sales
Weekly
+1
06/04/2026
Coaching Profiles Podcast - 30 Mar - 5 Apr 2026 - Client Success, UK Sales
Weekly
+1
06/04/2026
You are currently impersonating Adelina Petrova...
|
23916
|
NULL
|
NULL
|
NULL
|
|
8219
|
363
|
3
|
2026-05-08T10:10:41.486865+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778235041486_m1.jpg...
|
Firefox
|
JY-20818 move ask jiminny reports to its own datad JY-20818 move ask jiminny reports to its own datadog metric by LakyLak · Pull Request #12056 · jiminny/app — Work...
|
True
|
github.com/jiminny/app/pull/12056
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS] -4,16 +4,17 @@445namespace Jiminny\Component\Nudge\Job;5namespace Jiminny\Component\Nudge\Job;667+use Carbon\Carbon;7use Illuminate\Bus\Queueable;8use Illuminate\Bus\Queueable;8use Illuminate\Contracts\Queue\ShouldQueue;9use Illuminate\Contracts\Queue\ShouldQueue;9-use Illuminate\Database\Eloquent\Builder;10use Illuminate\Foundation\Bus\Dispatchable;10use Illuminate\Foundation\Bus\Dispatchable;11use Illuminate\Queue\InteractsWithQueue;11use Illuminate\Queue\InteractsWithQueue;12use Illuminate\Queue\SerializesModels;12use Illuminate\Queue\SerializesModels;13use Illuminate\Support\Facades\Log;13use Illuminate\Support\Facades\Log;14use Jiminny\Component\Queue\Constants;14use Jiminny\Component\Queue\Constants;15use Jiminny\Models\Activity;15use Jiminny\Models\Activity;16use Jiminny\Models\Activity\Search;16use Jiminny\Models\Activity\Search;17+use Jiminny\Models\Activity\SearchFilter;17use Jiminny\Models\Nudge;18use Jiminny\Models\Nudge;18use Jiminny\Models\Team;19use Jiminny\Models\Team;1920@@ -34,37 +35,201 @@343535public function handle(): void36public function handle(): void36 {37 {37-/** @var Activity $activity */38+$activity = Activity::with(['user.group'])->uuid($this->activityUuid, false)->firstOrFail();38-$activity = Activity::with(['user'])->uuid($this->activityUuid, false)->firstOrFail();39-40-/** @var Team $team */41$team = Team::with(['users'])->findOrFail($activity->user->team_id);39$team = Team::with(['users'])->findOrFail($activity->user->team_id);424043- Log::info(__METHOD__ . " Running for team $team->id.", [44-'activity_id' => $activity->id,45-'activity_uuid' => $this->activityUuid,46-'team_id' => $team->id,47- ]);48-49$usersIds = $team->users->pluck('id')->toArray();41$usersIds = $team->users->pluck('id')->toArray();504251-$searchesWithImmediateNudges = Activity\Search::with(['nudges'])43+$searchesWithImmediateNudges = Activity\Search::with([44+'nudges' => fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY),45+'filters',46+ ])52 ->whereIn('user_id', $usersIds)47 ->whereIn('user_id', $usersIds)53- ->whereHas('nudges', function (Builder $query) {48+ ->whereHas('nudges', fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY))54-$query->where('frequency', Nudge::FREQ_INSTANTLY);49+ ->get();55- })->get();50+51+$totalSearches = $searchesWithImmediateNudges->count();52+$skippedCount = 0;53+54+$searchesWithImmediateNudges->each(function (Search $search) use ($activity, &$skippedCount): void {55+$matchResult = $this->activityMightMatchSearch($activity, $search);565657-$searchesWithImmediateNudges->each(function (Search $search): void {57+if (! $matchResult['matches']) {58-$search->nudges->each(function (Nudge $nudge): void {58+$skippedCount++;59-// Filter only nudges that are set to be sent instantly59+ Log::info('Pre-filter skipped nudge dispatch', [60-if ($nudge->frequency === Nudge::FREQ_INSTANTLY) {60+'activity_uuid' => $activity->getUuid(),61- Log::info("Dispatching ProcessNudgeSearchJob for nudge $nudge->id.");61+'search_id' => $search->getId(),62+'mismatched_filter' => $matchResult['mismatch_reason'],63+'filter_value' => $matchResult['filter_value'],64+ ]);626563- ProcessNudgeSearchJob::dispatch($nudge);66+return;67+ }646865- Log::info("ProcessNudgeSearchJob dispatched for nudge $nudge->id.");69+$search->nudges->each(fn ($nudge) => ProcessNudgeSearchJob::dispatch($nudge));66- }67- });68 });70 });71+72+if ($totalSearches > 0) {73+ Log::info('Nudge pre-filter results', [74+'activity_uuid' => $activity->getUuid(),75+'total_searches' => $totalSearches,76+'skipped' => $skippedCount,77+'dispatched' => $totalSearches - $skippedCount,78+'skip_rate' => round(($skippedCount / $totalSearches) * 100, 2) . '%',79+ ]);80+ }81+ }82+83+private function activityMightMatchSearch(Activity $activity, Search $search): array84+ {85+foreach ($search->filters as $filter) {86+$filterName = $filter->getFilterProperty();87+88+$result = match ($filterName) {89+'group_id' => $this->checkGroupId($activity, $filter),90+'user_id' => $this->checkUserId($activity, $filter),91+'channel_id' => $this->checkChannelId($activity, $filter),92+'provider_id' => $this->checkProviderId($activity, $filter),93+'category_id' => $this->checkCategoryId($activity, $filter),94+'min_duration' => $this->checkMinDuration($activity, $filter),95+'max_duration' => $this->checkMaxDuration($activity, $filter),96+'not_logged' => $this->checkNotLogged($activity, $filter),97+'only_recorded' => $this->checkOnlyRecorded($activity, $filter),98+'languages' => $this->checkLanguages($activity, $filter),99+'stage_id' => $this->checkStageId($activity, $filter),100+'start_date' => $this->checkStartDate($activity, $filter),101+'end_date' => $this->checkEndDate($activity, $filter),102+default => null, // Unknown filter - can't pre-check, assume might match103+ };104+105+if ($result === false) {106+return [107+'matches' => false,108+'mismatch_reason' => $filterName,109+'filter_value' => $filter->getFilterValue(),110+ ];111+ }112+ }113+114+return ['matches' => true];115+ }116+117+private function checkGroupId(Activity $activity, SearchFilter $filter): ?bool118+ {119+$groupUuid = $activity->user->getGroup()?->getUuid();120+if ($groupUuid === null) {121+return null;122+ }123+124+return $filter->getFilterValue() === $groupUuid ? null : false;125+ }126+127+private function checkUserId(Activity $activity, SearchFilter $filter): ?bool128+ {129+return $filter->getFilterValue() === $activity->user->getUuid() ? null : false;130+ }131+132+private function checkChannelId(Activity $activity, SearchFilter $filter): ?bool133+ {134+return $filter->getFilterValue() === $activity->getType() ? null : false;135+ }136+137+private function checkProviderId(Activity $activity, SearchFilter $filter): ?bool138+ {139+return $filter->getFilterValue() === $activity->getProvider() ? null : false;140+ }141+142+private function checkCategoryId(Activity $activity, SearchFilter $filter): ?bool143+ {144+$categoryId = $activity->getCategory()?->getUuid();145+if ($categoryId === null) {146+return null;147+ }148+149+return $filter->getFilterValue() === $categoryId ? null : false;150+ }151+152+private function checkMinDuration(Activity $activity, SearchFilter $filter): ?bool153+ {154+return $activity->getDuration() >= (float) $filter->getFilterValue() ? null : false;155+ }156+157+private function checkMaxDuration(Activity $activity, SearchFilter $filter): ?bool158+ {159+return $activity->getDuration() <= (float) $filter->getFilterValue() ? null : false;160+ }161+162+private function checkNotLogged(Activity $activity, SearchFilter $filter): ?bool163+ {164+if (! $filter->getFilterValue()) {165+return null;166+ }167+168+$isLogged = $activity->getCrmProviderId() !== null;169+$isInternal = $activity->isInternal();170+171+return (! $isLogged || $isInternal) ? null : false;172+ }173+174+private function checkOnlyRecorded(Activity $activity, SearchFilter $filter): ?bool175+ {176+$filterValue = (int) $filter->getFilterValue();177+$hasRecording = $activity->recording_state !== Activity::RECORDING_OFF;178+179+return match ($filterValue) {180+1 => $hasRecording ? null : false, // Only recorded181+2 => ! $hasRecording ? null : false, // Only non-recorded182+default => null,183+ };184+ }185+186+private function checkStageId(Activity $activity, SearchFilter $filter): ?bool187+ {188+$stageId = $activity->getStage()?->getUuid();189+if ($stageId === null) {190+return null; // No stage, let ES handle191+ }192+193+return $filter->getFilterValue() === $stageId ? null : false;194+ }195+196+private function checkStartDate(Activity $activity, SearchFilter $filter): ?bool197+ {198+$startTime = $activity->getActualStartTime();199+if ($startTime === null) {200+return null;201+ }202+203+$filterDate = Carbon::parse($filter->getFilterValue());204+205+return $startTime->gte($filterDate) ? null : false;206+ }207+208+private function checkEndDate(Activity $activity, SearchFilter $filter): ?bool209+ {210+$endTime = $activity->getActualEndTime();211+if ($endTime === null) {212+return null;213+ }214+215+$filterDate = Carbon::parse($filter->getFilterValue())->endOfDay();216+217+return $endTime->lte($filterDate) ? null : false;218+ }219+220+private function checkLanguages(Activity $activity, SearchFilter $filter): ?bool221+ {222+$activityLanguage = $activity->getLanguageCode();223+if ($activityLanguage === null) {224+return null;225+ }226+227+// Filter values are always base language codes (e.g., 'en', 'fr').228+// Extract base code from activity locale (e.g., en_GB -> en) to match ES query behavior.229+// See LanguageFilterDefinition::getQueries() which uses regex: $language . '_[a-z]{2}'230+$activityLangCode = explode('_', $activityLanguage)[0];231+$filterLanguage = $filter->getFilterValue();232+233+return $activityLangCode === $filterLanguage ? null : false;69 }234 }70}235}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20493 smart instant nudge pre filtering by niko</tabTitle>” with “<selection>@@ -4,16 +4,17 @@445namespace Jiminny\Component\Nudge\Job;5namespace Jiminny\Component\Nudge\Job;667+use Carbon\Carbon;7use Illuminate\Bus\Queueable;8use Illuminate\Bus\Queueable;8use Illuminate\Contracts\Queue\ShouldQueue;9use Illuminate\Contracts\Queue\ShouldQueue;9-use Illuminate\Database\Eloquent\Builder;10use Illuminate\Foundation\Bus\Dispatchable;10use Illuminate\Foundation\Bus\Dispatchable;11use Illuminate\Queue\InteractsWithQueue;11use Illuminate\Queue\InteractsWithQueue;12use Illuminate\Queue\SerializesModels;12use Illuminate\Queue\SerializesModels;13use Illuminate\Support\Facades\Log;13use Illuminate\Support\Facades\Log;14use Jiminny\Component\Queue\Constants;14use Jiminny\Component\Queue\Constants;15use Jiminny\Models\Activity;15use Jiminny\Models\Activity;16use Jiminny\Models\Activity\Search;16use Jiminny\Models\Activity\Search;17+use Jiminny\Models\Activity\SearchFilter;17use Jiminny\Models\Nudge;18use Jiminny\Models\Nudge;18use Jiminny\Models\Team;19use Jiminny\Models\Team;1920@@ -34,37 +35,201 @@343535public function handle(): void36public function handle(): void36 {37 {37-/** @var Activity $activity */38+$activity = Activity::with(['user.group'])->uuid($this->activityUuid, false)->firstOrFail();38-$activity = Activity::with(['user'])->uuid($this->activityUuid, false)->firstOrFail();39-40-/** @var Team $team */41$team = Team::with(['users'])->findOrFail($activity->user->team_id);39$team = Team::with(['users'])->findOrFail($activity->user->team_id);424043- Log::info(__METHOD__ . " Running for team $team->id.", [44-'activity_id' => $activity->id,45-'activity_uuid' => $this->activityUuid,46-'team_id' => $team->id,47- ]);48-49$usersIds = $team->users->pluck('id')->toArray();41$usersIds = $team->users->pluck('id')->toArray();504251-$searchesWithImmediateNudges = Activity\Search::with(['nudges'])43+$searchesWithImmediateNudges = Activity\Search::with([44+'nudges' => fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY),45+'filters',46+ ])52 ->whereIn('user_id', $usersIds)47 ->whereIn('user_id', $usersIds)53- ->whereHas('nudges', function (Builder $query) {48+ ->whereHas('nudges', fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY))54-$query->where('frequency', Nudge::FREQ_INSTANTLY);49+ ->get();55- })->get();50+51+$totalSearches = $searchesWithImmediateNudges->count();52+$skippedCount = 0;53+54+$searchesWithImmediateNudges->each(function (Search $search) use ($activity, &$skippedCount): void {55+$matchResult = $this->activityMightMatchSearch($activity, $search);565657-$searchesWithImmediateNudges->each(function (Search $search): void {57+if (! $matchResult['matches']) {58-$search->nudges->each(function (Nudge $nudge): void {58+$skippedCount++;59-// Filter only nudges that are set to be sent instantly59+ Log::info('Pre-filter skipped nudge dispatch', [60-if ($nudge->frequency === Nudge::FREQ_INSTANTLY) {60+'activity_uuid' => $activity->getUuid(),61- Log::info("Dispatching ProcessNudgeSearchJob for nudge $nudge->id.");61+'search_id' => $search->getId(),62+'mismatched_filter' => $matchResult['mismatch_reason'],63+'filter_value' => $matchResult['filter_value'],64+ ]);626563- ProcessNudgeSearchJob::dispatch($nudge);66+return;67+ }646865- Log::info("ProcessNudgeSearchJob dispatched for nudge $nudge->id.");69+$search->nudges->each(fn ($nudge) => ProcessNudgeSearchJob::dispatch($nudge));66- }67- });68 });70 });71+72+if ($totalSearches > 0) {73+ Log::info('Nudge pre-filter results', [74+'activity_uuid' => $activity->getUuid(),75+'total_searches' => $totalSearches,76+'skipped' => $skippedCount,77+'dispatched' => $totalSearches - $skippedCount,78+'skip_rate' => round(($skippedCount / $totalSearches) * 100, 2) . '%',79+ ]);80+ }81+ }82+83+private function activityMightMatchSearch(Activity $activity, Search $search): array84+ {85+foreach ($search->filters as $filter) {86+$filterName = $filter->getFilterProperty();87+88+$result = match ($filterName) {89+'group_id' => $this->checkGroupId($activity, $filter),90+'user_id' => $this->checkUserId($activity, $filter),91+'channel_id' => $this->checkChannelId($activity, $filter),92+'provider_id' => $this->checkProviderId($activity, $filter),93+'category_id' => $this->checkCategoryId($activity, $filter),94+'min_duration' => $this->checkMinDuration($activity, $filter),95+'max_duration' => $this->checkMaxDuration($activity, $filter),96+'not_logged' => $this->checkNotLogged($activity, $filter),97+'only_recorded' => $this->checkOnlyRecorded($activity, $filter),98+'languages' => $this->checkLanguages($activity, $filter),99+'stage_id' => $this->checkStageId($activity, $filter),100+'start_date' => $this->checkStartDate($activity, $filter),101+'end_date' => $this->checkEndDate($activity, $filter),102+default => null, // Unknown filter - can't pre-check, assume might match103+ };104+105+if ($result === false) {106+return [107+'matches' => false,108+'mismatch_reason' => $filterName,109+'filter_value' => $filter->getFilterValue(),110+ ];111+ }112+ }113+114+return ['matches' => true];115+ }116+117+private function checkGroupId(Activity $activity, SearchFilter $filter): ?bool118+ {119+$groupUuid = $activity->user->getGroup()?->getUuid();120+if ($groupUuid === null) {121+return null;122+ }123+124+return $filter->getFilterValue() === $groupUuid ? null : false;125+ }126+127+private function checkUserId(Activity $activity, SearchFilter $filter): ?bool128+ {129+return $filter->getFilterValue() === $activity->user->getUuid() ? null : false;130+ }131+132+private function checkChannelId(Activity $activity, SearchFilter $filter): ?bool133+ {134+return $filter->getFilterValue() === $activity->getType() ? null : false;135+ }136+137+private function checkProviderId(Activity $activity, SearchFilter $filter): ?bool138+ {139+return $filter->getFilterValue() === $activity->getProvider() ? null : false;140+ }141+142+private function checkCategoryId(Activity $activity, SearchFilter $filter): ?bool143+ {144+$categoryId = $activity->getCategory()?->getUuid();145+if ($categoryId === null) {146+return null;147+ }148+149+return $filter->getFilterValue() === $categoryId ? null : false;150+ }151+152+private function checkMinDuration(Activity $activity, SearchFilter $filter): ?bool153+ {154+return $activity->getDuration() >= (float) $filter->getFilterValue() ? null : false;155+ }156+157+private function checkMaxDuration(Activity $activity, SearchFilter $filter): ?bool158+ {159+return $activity->getDuration() <= (float) $filter->getFilterValue() ? null : false;160+ }161+162+private function checkNotLogged(Activity $activity, SearchFilter $filter): ?bool163+ {164+if (! $filter->getFilterValue()) {165+return null;166+ }167+168+$isLogged = $activity->getCrmProviderId() !== null;169+$isInternal = $activity->isInternal();170+171+return (! $isLogged || $isInternal) ? null : false;172+ }173+174+private function checkOnlyRecorded(Activity $activity, SearchFilter $filter): ?bool175+ {176+$filterValue = (int) $filter->getFilterValue();177+$hasRecording = $activity->recording_state !== Activity::RECORDING_OFF;178+179+return match ($filterValue) {180+1 => $hasRecording ? null : false, // Only recorded181+2 => ! $hasRecording ? null : false, // Only non-recorded182+default => null,183+ };184+ }185+186+private function checkStageId(Activity $activity, SearchFilter $filter): ?bool187+ {188+$stageId = $activity->getStage()?->getUuid();189+if ($stageId === null) {190+return null; // No stage, let ES handle191+ }192+193+return $filter->getFilterValue() === $stageId ? null : false;194+ }195+196+private function checkStartDate(Activity $activity, SearchFilter $filter): ?bool197+ {198+$startTime = $activity->getActualStartTime();199+if ($startTime === null) {200+return null;201+ }202+203+$filterDate = Carbon::parse($filter->getFilterValue());204+205+return $startTime->gte($filterDate) ? null : false;206+ }207+208+private function checkEndDate(Activity $activity, SearchFilter $filter): ?bool209+ {210+$endTime = $activity->getActualEndTime();211+if ($endTime === null) {212+return null;213+ }214+215+$filterDate = Carbon::parse($filter->getFilterValue())->endOfDay();216+217+return $endTime->lte($filterDate) ? null : false;218+ }219+220+private function checkLanguages(Activity $activity, SearchFilter $filter): ?bool221+ {222+$activityLanguage = $activity->getLanguageCode();223+if ($activityLanguage === null) {224+return null;225+ }226+227+// Filter values are always base language codes (e.g., 'en', 'fr').228+// Extract base code from activity locale (e.g., en_GB -> en) to match ES query behavior.229+// See LanguageFilterDefinition::getQueries() which uses regex: $language . '_[a-z]{2}'230+$activityLangCode = explode('_', $activityLanguage)[0];231+$filterLanguage = $filter->getFilterValue();232+233+return $activityLangCode === $filterLanguage ? null : false;69 }234 }70}235}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
This code selection introduces a
pre-filtering mechanism
to the
Jiminny\Component\Nudge\Job
namespace. The primary goal is to optimize performance by validating an activity against search criteria in-memory before dispatching costly background jobs.
Core Functionality Changes
Core Functionality Changes
Selective Loading:
The
handle()
method now eager-loads
user.group
for activities and specifically filters for
FREQ_INSTANTLY
nudges and their associated search filters.
Pre-Dispatch Validation:
Instead of dispatching jobs for every instant nudge, the system now calls
activityMightMatchSearch()
.
Short-Circuiting:
If an activity fails a pre-filter check (e.g., mismatched user ID or duration), the job dispatch is skipped, and the event is logged with the specific mismatch reason.
Performance Metrics:
Adds summary logging at the end of the process to track:
Total searches processed.
Number of skipped dispatches.
The "Skip Rate" percentage.
Implemented Filter Checks
Implemented Filter Checks
The logic includes a
match
expression to validate various activity attributes against
SearchFilter
values:
Identity & Metadata:
Matches for
group_id
,
user_id
,
channel_id
, and
provider_id
.
Temporal & Duration:
* Validates
min_duration
and
max_duration
.
Checks
start_date
and
end_date
using Carbon parsing.
Activity State:
*
Logging:
Determines if an activity is logged to a CRM or is internal via
checkNotLogged
.
Recording:
Uses
checkOnlyRecorded
to filter based on whether a recording exists.
Categorization:
Checks for
category_id
,
stage_id
, and
languages
.
Note:
The language check specifically extracts base codes (e.g.,
en
from
en_GB
) to align with Elasticsearch behavior.
Logic Design
Logic Design
Nullable Returns:
Filter methods return
null
if a match is possible (or cannot be determined), and
false
only when a definitive mismatch is found.
Safe Fallback:
If a filter type is unknown (
default
), the system assumes a match and proceeds to dispatch, ensuring no false negatives.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said what is the logic behind diff. Act as code reviewer. First review the changes then explain it and then evaluate. Try to find potential issues and bottlenecks
You said
what is the logic behind diff. Act as code reviewer. First review the changes then explain it and then evaluate. Try to find potential issues and bottlenecks
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Here is a review of the changes provided in the diff, broken down by your requested structure.
1. Review of Changes
1. Review of Changes
This PR refactors the
ProcessNudgeSearchJob
dispatching mechanism within the
handle()
method.
Query Optimization:
Eager loads necessary relationships (
user.group
,
filters
) and scopes the
nudges
relationship at the database level to only fetch
FREQ_INSTANTLY
records.
In-Memory Filtering:
Introduces a pre-filtering mechanism (
activityMightMatchSearch
) that checks the
Activity
against
SearchFilter...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SevenShores\\Hubspot\\Exceptions\\BadRequest: Client error: `POST https://api.hubapi.com/crm/v3/objects/contact/search` resulted in a `429 Too Many Requests` response: {\"status\":\"error\",\"message\":\"You have reached your secondly limit.\",\"errorType\":\"RATE_LIMIT","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Service-Desk - Queues - Platform team - Service space - Jira","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20807 check various issues with stages by nikolaybiaivanov · Pull Request #12041 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Illuminate\\Queue\\MaxAttemptsExceededException: Jiminny\\Jobs\\Activity\\DeleteTeamChurnData has been attempted too many times. — jiminny — app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Illuminate\\Queue\\MaxAttemptsExceededException: Jiminny\\Jobs\\Activity\\DeleteTeamChurnData has been attempted too many times. — jiminny — app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20818 move ask jiminny reports to its own datadog metric by LakyLak · Pull Request #12056 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20818 move ask jiminny reports to its own datadog metric by LakyLak · Pull Request #12056 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Userpilot | Ask Jiminny Report Generated","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Ask Jiminny Report Generated","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20773 fix user pilot tracking ofr automated report generated by LakyLak · Pull Request #12024 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Problem loading page","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Problem loading page","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Search the CRM - HubSpot docs","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Search the CRM - HubSpot docs","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Dashboards | Datadog","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Dashboards | Datadog","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"AI Features | Datadog","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"AI Features | Datadog","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jy 20493 smart instant nudge pre filtering by nikolaybiaivanov · Pull Request #12053 · jiminny/app","depth":4,"on_screen":true,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 20493 smart instant nudge pre filtering by nikolaybiaivanov · Pull Request #12053 · jiminny/app","depth":5,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.0,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.0013888889,"top":0.0,"width":0.022222223,"height":0.035555556},"on_screen":true,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Chat","depth":12,"on_screen":true,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"on_screen":true,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"on_screen":true,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said I’m on page “<tabTitle>Jy 20493 smart instant nudge pre filtering by niko</tabTitle>” with “<selection>@@ -4,16 +4,17 @@445namespace Jiminny\\Component\\Nudge\\Job;5namespace Jiminny\\Component\\Nudge\\Job;667+use Carbon\\Carbon;7use Illuminate\\Bus\\Queueable;8use Illuminate\\Bus\\Queueable;8use Illuminate\\Contracts\\Queue\\ShouldQueue;9use Illuminate\\Contracts\\Queue\\ShouldQueue;9-use Illuminate\\Database\\Eloquent\\Builder;10use Illuminate\\Foundation\\Bus\\Dispatchable;10use Illuminate\\Foundation\\Bus\\Dispatchable;11use Illuminate\\Queue\\InteractsWithQueue;11use Illuminate\\Queue\\InteractsWithQueue;12use Illuminate\\Queue\\SerializesModels;12use Illuminate\\Queue\\SerializesModels;13use Illuminate\\Support\\Facades\\Log;13use Illuminate\\Support\\Facades\\Log;14use Jiminny\\Component\\Queue\\Constants;14use Jiminny\\Component\\Queue\\Constants;15use Jiminny\\Models\\Activity;15use Jiminny\\Models\\Activity;16use Jiminny\\Models\\Activity\\Search;16use Jiminny\\Models\\Activity\\Search;17+use Jiminny\\Models\\Activity\\SearchFilter;17use Jiminny\\Models\\Nudge;18use Jiminny\\Models\\Nudge;18use Jiminny\\Models\\Team;19use Jiminny\\Models\\Team;1920@@ -34,37 +35,201 @@343535public function handle(): void36public function handle(): void36 {37 {37-/** @var Activity $activity */38+$activity = Activity::with(['user.group'])->uuid($this->activityUuid, false)->firstOrFail();38-$activity = Activity::with(['user'])->uuid($this->activityUuid, false)->firstOrFail();39-40-/** @var Team $team */41$team = Team::with(['users'])->findOrFail($activity->user->team_id);39$team = Team::with(['users'])->findOrFail($activity->user->team_id);424043- Log::info(__METHOD__ . " Running for team $team->id.", [44-'activity_id' => $activity->id,45-'activity_uuid' => $this->activityUuid,46-'team_id' => $team->id,47- ]);48-49$usersIds = $team->users->pluck('id')->toArray();41$usersIds = $team->users->pluck('id')->toArray();504251-$searchesWithImmediateNudges = Activity\\Search::with(['nudges'])43+$searchesWithImmediateNudges = Activity\\Search::with([44+'nudges' => fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY),45+'filters',46+ ])52 ->whereIn('user_id', $usersIds)47 ->whereIn('user_id', $usersIds)53- ->whereHas('nudges', function (Builder $query) {48+ ->whereHas('nudges', fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY))54-$query->where('frequency', Nudge::FREQ_INSTANTLY);49+ ->get();55- })->get();50+51+$totalSearches = $searchesWithImmediateNudges->count();52+$skippedCount = 0;53+54+$searchesWithImmediateNudges->each(function (Search $search) use ($activity, &$skippedCount): void {55+$matchResult = $this->activityMightMatchSearch($activity, $search);565657-$searchesWithImmediateNudges->each(function (Search $search): void {57+if (! $matchResult['matches']) {58-$search->nudges->each(function (Nudge $nudge): void {58+$skippedCount++;59-// Filter only nudges that are set to be sent instantly59+ Log::info('Pre-filter skipped nudge dispatch', [60-if ($nudge->frequency === Nudge::FREQ_INSTANTLY) {60+'activity_uuid' => $activity->getUuid(),61- Log::info("Dispatching ProcessNudgeSearchJob for nudge $nudge->id.");61+'search_id' => $search->getId(),62+'mismatched_filter' => $matchResult['mismatch_reason'],63+'filter_value' => $matchResult['filter_value'],64+ ]);626563- ProcessNudgeSearchJob::dispatch($nudge);66+return;67+ }646865- Log::info("ProcessNudgeSearchJob dispatched for nudge $nudge->id.");69+$search->nudges->each(fn ($nudge) => ProcessNudgeSearchJob::dispatch($nudge));66- }67- });68 });70 });71+72+if ($totalSearches > 0) {73+ Log::info('Nudge pre-filter results', [74+'activity_uuid' => $activity->getUuid(),75+'total_searches' => $totalSearches,76+'skipped' => $skippedCount,77+'dispatched' => $totalSearches - $skippedCount,78+'skip_rate' => round(($skippedCount / $totalSearches) * 100, 2) . '%',79+ ]);80+ }81+ }82+83+private function activityMightMatchSearch(Activity $activity, Search $search): array84+ {85+foreach ($search->filters as $filter) {86+$filterName = $filter->getFilterProperty();87+88+$result = match ($filterName) {89+'group_id' => $this->checkGroupId($activity, $filter),90+'user_id' => $this->checkUserId($activity, $filter),91+'channel_id' => $this->checkChannelId($activity, $filter),92+'provider_id' => $this->checkProviderId($activity, $filter),93+'category_id' => $this->checkCategoryId($activity, $filter),94+'min_duration' => $this->checkMinDuration($activity, $filter),95+'max_duration' => $this->checkMaxDuration($activity, $filter),96+'not_logged' => $this->checkNotLogged($activity, $filter),97+'only_recorded' => $this->checkOnlyRecorded($activity, $filter),98+'languages' => $this->checkLanguages($activity, $filter),99+'stage_id' => $this->checkStageId($activity, $filter),100+'start_date' => $this->checkStartDate($activity, $filter),101+'end_date' => $this->checkEndDate($activity, $filter),102+default => null, // Unknown filter - can't pre-check, assume might match103+ };104+105+if ($result === false) {106+return [107+'matches' => false,108+'mismatch_reason' => $filterName,109+'filter_value' => $filter->getFilterValue(),110+ ];111+ }112+ }113+114+return ['matches' => true];115+ }116+117+private function checkGroupId(Activity $activity, SearchFilter $filter): ?bool118+ {119+$groupUuid = $activity->user->getGroup()?->getUuid();120+if ($groupUuid === null) {121+return null;122+ }123+124+return $filter->getFilterValue() === $groupUuid ? null : false;125+ }126+127+private function checkUserId(Activity $activity, SearchFilter $filter): ?bool128+ {129+return $filter->getFilterValue() === $activity->user->getUuid() ? null : false;130+ }131+132+private function checkChannelId(Activity $activity, SearchFilter $filter): ?bool133+ {134+return $filter->getFilterValue() === $activity->getType() ? null : false;135+ }136+137+private function checkProviderId(Activity $activity, SearchFilter $filter): ?bool138+ {139+return $filter->getFilterValue() === $activity->getProvider() ? null : false;140+ }141+142+private function checkCategoryId(Activity $activity, SearchFilter $filter): ?bool143+ {144+$categoryId = $activity->getCategory()?->getUuid();145+if ($categoryId === null) {146+return null;147+ }148+149+return $filter->getFilterValue() === $categoryId ? null : false;150+ }151+152+private function checkMinDuration(Activity $activity, SearchFilter $filter): ?bool153+ {154+return $activity->getDuration() >= (float) $filter->getFilterValue() ? null : false;155+ }156+157+private function checkMaxDuration(Activity $activity, SearchFilter $filter): ?bool158+ {159+return $activity->getDuration() <= (float) $filter->getFilterValue() ? null : false;160+ }161+162+private function checkNotLogged(Activity $activity, SearchFilter $filter): ?bool163+ {164+if (! $filter->getFilterValue()) {165+return null;166+ }167+168+$isLogged = $activity->getCrmProviderId() !== null;169+$isInternal = $activity->isInternal();170+171+return (! $isLogged || $isInternal) ? null : false;172+ }173+174+private function checkOnlyRecorded(Activity $activity, SearchFilter $filter): ?bool175+ {176+$filterValue = (int) $filter->getFilterValue();177+$hasRecording = $activity->recording_state !== Activity::RECORDING_OFF;178+179+return match ($filterValue) {180+1 => $hasRecording ? null : false, // Only recorded181+2 => ! $hasRecording ? null : false, // Only non-recorded182+default => null,183+ };184+ }185+186+private function checkStageId(Activity $activity, SearchFilter $filter): ?bool187+ {188+$stageId = $activity->getStage()?->getUuid();189+if ($stageId === null) {190+return null; // No stage, let ES handle191+ }192+193+return $filter->getFilterValue() === $stageId ? null : false;194+ }195+196+private function checkStartDate(Activity $activity, SearchFilter $filter): ?bool197+ {198+$startTime = $activity->getActualStartTime();199+if ($startTime === null) {200+return null;201+ }202+203+$filterDate = Carbon::parse($filter->getFilterValue());204+205+return $startTime->gte($filterDate) ? null : false;206+ }207+208+private function checkEndDate(Activity $activity, SearchFilter $filter): ?bool209+ {210+$endTime = $activity->getActualEndTime();211+if ($endTime === null) {212+return null;213+ }214+215+$filterDate = Carbon::parse($filter->getFilterValue())->endOfDay();216+217+return $endTime->lte($filterDate) ? null : false;218+ }219+220+private function checkLanguages(Activity $activity, SearchFilter $filter): ?bool221+ {222+$activityLanguage = $activity->getLanguageCode();223+if ($activityLanguage === null) {224+return null;225+ }226+227+// Filter values are always base language codes (e.g., 'en', 'fr').228+// Extract base code from activity locale (e.g., en_GB -> en) to match ES query behavior.229+// See LanguageFilterDefinition::getQueries() which uses regex: $language . '_[a-z]{2}'230+$activityLangCode = explode('_', $activityLanguage)[0];231+$filterLanguage = $filter->getFilterValue();232+233+return $activityLangCode === $filterLanguage ? null : false;69 }234 }70}235}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"I’m on page “<tabTitle>Jy 20493 smart instant nudge pre filtering by niko</tabTitle>” with “<selection>@@ -4,16 +4,17 @@445namespace Jiminny\\Component\\Nudge\\Job;5namespace Jiminny\\Component\\Nudge\\Job;667+use Carbon\\Carbon;7use Illuminate\\Bus\\Queueable;8use Illuminate\\Bus\\Queueable;8use Illuminate\\Contracts\\Queue\\ShouldQueue;9use Illuminate\\Contracts\\Queue\\ShouldQueue;9-use Illuminate\\Database\\Eloquent\\Builder;10use Illuminate\\Foundation\\Bus\\Dispatchable;10use Illuminate\\Foundation\\Bus\\Dispatchable;11use Illuminate\\Queue\\InteractsWithQueue;11use Illuminate\\Queue\\InteractsWithQueue;12use Illuminate\\Queue\\SerializesModels;12use Illuminate\\Queue\\SerializesModels;13use Illuminate\\Support\\Facades\\Log;13use Illuminate\\Support\\Facades\\Log;14use Jiminny\\Component\\Queue\\Constants;14use Jiminny\\Component\\Queue\\Constants;15use Jiminny\\Models\\Activity;15use Jiminny\\Models\\Activity;16use Jiminny\\Models\\Activity\\Search;16use Jiminny\\Models\\Activity\\Search;17+use Jiminny\\Models\\Activity\\SearchFilter;17use Jiminny\\Models\\Nudge;18use Jiminny\\Models\\Nudge;18use Jiminny\\Models\\Team;19use Jiminny\\Models\\Team;1920@@ -34,37 +35,201 @@343535public function handle(): void36public function handle(): void36 {37 {37-/** @var Activity $activity */38+$activity = Activity::with(['user.group'])->uuid($this->activityUuid, false)->firstOrFail();38-$activity = Activity::with(['user'])->uuid($this->activityUuid, false)->firstOrFail();39-40-/** @var Team $team */41$team = Team::with(['users'])->findOrFail($activity->user->team_id);39$team = Team::with(['users'])->findOrFail($activity->user->team_id);424043- Log::info(__METHOD__ . " Running for team $team->id.", [44-'activity_id' => $activity->id,45-'activity_uuid' => $this->activityUuid,46-'team_id' => $team->id,47- ]);48-49$usersIds = $team->users->pluck('id')->toArray();41$usersIds = $team->users->pluck('id')->toArray();504251-$searchesWithImmediateNudges = Activity\\Search::with(['nudges'])43+$searchesWithImmediateNudges = Activity\\Search::with([44+'nudges' => fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY),45+'filters',46+ ])52 ->whereIn('user_id', $usersIds)47 ->whereIn('user_id', $usersIds)53- ->whereHas('nudges', function (Builder $query) {48+ ->whereHas('nudges', fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY))54-$query->where('frequency', Nudge::FREQ_INSTANTLY);49+ ->get();55- })->get();50+51+$totalSearches = $searchesWithImmediateNudges->count();52+$skippedCount = 0;53+54+$searchesWithImmediateNudges->each(function (Search $search) use ($activity, &$skippedCount): void {55+$matchResult = $this->activityMightMatchSearch($activity, $search);565657-$searchesWithImmediateNudges->each(function (Search $search): void {57+if (! $matchResult['matches']) {58-$search->nudges->each(function (Nudge $nudge): void {58+$skippedCount++;59-// Filter only nudges that are set to be sent instantly59+ Log::info('Pre-filter skipped nudge dispatch', [60-if ($nudge->frequency === Nudge::FREQ_INSTANTLY) {60+'activity_uuid' => $activity->getUuid(),61- Log::info("Dispatching ProcessNudgeSearchJob for nudge $nudge->id.");61+'search_id' => $search->getId(),62+'mismatched_filter' => $matchResult['mismatch_reason'],63+'filter_value' => $matchResult['filter_value'],64+ ]);626563- ProcessNudgeSearchJob::dispatch($nudge);66+return;67+ }646865- Log::info("ProcessNudgeSearchJob dispatched for nudge $nudge->id.");69+$search->nudges->each(fn ($nudge) => ProcessNudgeSearchJob::dispatch($nudge));66- }67- });68 });70 });71+72+if ($totalSearches > 0) {73+ Log::info('Nudge pre-filter results', [74+'activity_uuid' => $activity->getUuid(),75+'total_searches' => $totalSearches,76+'skipped' => $skippedCount,77+'dispatched' => $totalSearches - $skippedCount,78+'skip_rate' => round(($skippedCount / $totalSearches) * 100, 2) . '%',79+ ]);80+ }81+ }82+83+private function activityMightMatchSearch(Activity $activity, Search $search): array84+ {85+foreach ($search->filters as $filter) {86+$filterName = $filter->getFilterProperty();87+88+$result = match ($filterName) {89+'group_id' => $this->checkGroupId($activity, $filter),90+'user_id' => $this->checkUserId($activity, $filter),91+'channel_id' => $this->checkChannelId($activity, $filter),92+'provider_id' => $this->checkProviderId($activity, $filter),93+'category_id' => $this->checkCategoryId($activity, $filter),94+'min_duration' => $this->checkMinDuration($activity, $filter),95+'max_duration' => $this->checkMaxDuration($activity, $filter),96+'not_logged' => $this->checkNotLogged($activity, $filter),97+'only_recorded' => $this->checkOnlyRecorded($activity, $filter),98+'languages' => $this->checkLanguages($activity, $filter),99+'stage_id' => $this->checkStageId($activity, $filter),100+'start_date' => $this->checkStartDate($activity, $filter),101+'end_date' => $this->checkEndDate($activity, $filter),102+default => null, // Unknown filter - can't pre-check, assume might match103+ };104+105+if ($result === false) {106+return [107+'matches' => false,108+'mismatch_reason' => $filterName,109+'filter_value' => $filter->getFilterValue(),110+ ];111+ }112+ }113+114+return ['matches' => true];115+ }116+117+private function checkGroupId(Activity $activity, SearchFilter $filter): ?bool118+ {119+$groupUuid = $activity->user->getGroup()?->getUuid();120+if ($groupUuid === null) {121+return null;122+ }123+124+return $filter->getFilterValue() === $groupUuid ? null : false;125+ }126+127+private function checkUserId(Activity $activity, SearchFilter $filter): ?bool128+ {129+return $filter->getFilterValue() === $activity->user->getUuid() ? null : false;130+ }131+132+private function checkChannelId(Activity $activity, SearchFilter $filter): ?bool133+ {134+return $filter->getFilterValue() === $activity->getType() ? null : false;135+ }136+137+private function checkProviderId(Activity $activity, SearchFilter $filter): ?bool138+ {139+return $filter->getFilterValue() === $activity->getProvider() ? null : false;140+ }141+142+private function checkCategoryId(Activity $activity, SearchFilter $filter): ?bool143+ {144+$categoryId = $activity->getCategory()?->getUuid();145+if ($categoryId === null) {146+return null;147+ }148+149+return $filter->getFilterValue() === $categoryId ? null : false;150+ }151+152+private function checkMinDuration(Activity $activity, SearchFilter $filter): ?bool153+ {154+return $activity->getDuration() >= (float) $filter->getFilterValue() ? null : false;155+ }156+157+private function checkMaxDuration(Activity $activity, SearchFilter $filter): ?bool158+ {159+return $activity->getDuration() <= (float) $filter->getFilterValue() ? null : false;160+ }161+162+private function checkNotLogged(Activity $activity, SearchFilter $filter): ?bool163+ {164+if (! $filter->getFilterValue()) {165+return null;166+ }167+168+$isLogged = $activity->getCrmProviderId() !== null;169+$isInternal = $activity->isInternal();170+171+return (! $isLogged || $isInternal) ? null : false;172+ }173+174+private function checkOnlyRecorded(Activity $activity, SearchFilter $filter): ?bool175+ {176+$filterValue = (int) $filter->getFilterValue();177+$hasRecording = $activity->recording_state !== Activity::RECORDING_OFF;178+179+return match ($filterValue) {180+1 => $hasRecording ? null : false, // Only recorded181+2 => ! $hasRecording ? null : false, // Only non-recorded182+default => null,183+ };184+ }185+186+private function checkStageId(Activity $activity, SearchFilter $filter): ?bool187+ {188+$stageId = $activity->getStage()?->getUuid();189+if ($stageId === null) {190+return null; // No stage, let ES handle191+ }192+193+return $filter->getFilterValue() === $stageId ? null : false;194+ }195+196+private function checkStartDate(Activity $activity, SearchFilter $filter): ?bool197+ {198+$startTime = $activity->getActualStartTime();199+if ($startTime === null) {200+return null;201+ }202+203+$filterDate = Carbon::parse($filter->getFilterValue());204+205+return $startTime->gte($filterDate) ? null : false;206+ }207+208+private function checkEndDate(Activity $activity, SearchFilter $filter): ?bool209+ {210+$endTime = $activity->getActualEndTime();211+if ($endTime === null) {212+return null;213+ }214+215+$filterDate = Carbon::parse($filter->getFilterValue())->endOfDay();216+217+return $endTime->lte($filterDate) ? null : false;218+ }219+220+private function checkLanguages(Activity $activity, SearchFilter $filter): ?bool221+ {222+$activityLanguage = $activity->getLanguageCode();223+if ($activityLanguage === null) {224+return null;225+ }226+227+// Filter values are always base language codes (e.g., 'en', 'fr').228+// Extract base code from activity locale (e.g., en_GB -> en) to match ES query behavior.229+// See LanguageFilterDefinition::getQueries() which uses regex: $language . '_[a-z]{2}'230+$activityLangCode = explode('_', $activityLanguage)[0];231+$filterLanguage = $filter->getFilterValue();232+233+return $activityLangCode === $filterLanguage ? null : false;69 }234 }70}235}</selection>” selected.","depth":23,"on_screen":true,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"This code selection introduces a","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"pre-filtering mechanism","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jiminny\\Component\\Nudge\\Job","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"namespace. The primary goal is to optimize performance by validating an activity against search criteria in-memory before dispatching costly background jobs.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Core Functionality Changes","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Core Functionality Changes","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Selective Loading:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"handle()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method now eager-loads","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"user.group","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"for activities and specifically filters for","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"FREQ_INSTANTLY","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"nudges and their associated search filters.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pre-Dispatch Validation:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Instead of dispatching jobs for every instant nudge, the system now calls","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"activityMightMatchSearch()","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Short-Circuiting:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If an activity fails a pre-filter check (e.g., mismatched user ID or duration), the job dispatch is skipped, and the event is logged with the specific mismatch reason.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Performance Metrics:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Adds summary logging at the end of the process to track:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Total searches processed.","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Number of skipped dispatches.","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The \"Skip Rate\" percentage.","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Implemented Filter Checks","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Implemented Filter Checks","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The logic includes a","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"match","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"expression to validate various activity attributes against","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SearchFilter","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"values:","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Identity & Metadata:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Matches for","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"group_id","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"user_id","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"channel_id","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"provider_id","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Temporal & Duration:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"* Validates","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"min_duration","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"max_duration","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Checks","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"start_date","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"end_date","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"using Carbon parsing.","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Activity State:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"*","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Logging:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Determines if an activity is logged to a CRM or is internal via","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"checkNotLogged","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Recording:","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Uses","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"checkOnlyRecorded","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to filter based on whether a recording exists.","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Categorization:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Checks for","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"category_id","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"stage_id","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"languages","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Note:","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"The language check specifically extracts base codes (e.g.,","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"en","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"en_GB","depth":29,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") to align with Elasticsearch behavior.","depth":28,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Logic Design","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Logic Design","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Nullable Returns:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Filter methods return","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"null","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if a match is possible (or cannot be determined), and","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"false","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"only when a definitive mismatch is found.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Safe Fallback:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If a filter type is unknown (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"default","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"), the system assumes a match and proceeds to dispatch, ensuring no false negatives.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Good response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Bad response","depth":22,"on_screen":false,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Share & export","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy","depth":22,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Copy prompt","depth":21,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said what is the logic behind diff. Act as code reviewer. First review the changes then explain it and then evaluate. Try to find potential issues and bottlenecks","depth":21,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"what is the logic behind diff. Act as code reviewer. First review the changes then explain it and then evaluate. Try to find potential issues and bottlenecks","depth":23,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":22,"on_screen":false,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"on_screen":false,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is a review of the changes provided in the diff, broken down by your requested structure.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"1. Review of Changes","depth":23,"on_screen":false,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1. Review of Changes","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"This PR refactors the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"ProcessNudgeSearchJob","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"dispatching mechanism within the","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"handle()","depth":25,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"method.","depth":24,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Query Optimization:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Eager loads necessary relationships (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"user.group","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"filters","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") and scopes the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"nudges","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"relationship at the database level to only fetch","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"FREQ_INSTANTLY","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"records.","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"In-Memory Filtering:","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Introduces a pre-filtering mechanism (","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"activityMightMatchSearch","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":") that checks the","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Activity","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"against","depth":26,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"SearchFilter","depth":27,"on_screen":false,"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-7736885783467027958
|
6636142785247713539
|
click
|
accessibility
|
NULL
|
Platform Sprint 3 Q2 - Platform Team - Scrum Board Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
Platform Sprint 3 Q2 - Platform Team - Scrum Board - Jira
SevenShores\Hubspot\Exceptions\BadRequest: Client error: `POST [URL_WITH_CREDENTIALS] -4,16 +4,17 @@445namespace Jiminny\Component\Nudge\Job;5namespace Jiminny\Component\Nudge\Job;667+use Carbon\Carbon;7use Illuminate\Bus\Queueable;8use Illuminate\Bus\Queueable;8use Illuminate\Contracts\Queue\ShouldQueue;9use Illuminate\Contracts\Queue\ShouldQueue;9-use Illuminate\Database\Eloquent\Builder;10use Illuminate\Foundation\Bus\Dispatchable;10use Illuminate\Foundation\Bus\Dispatchable;11use Illuminate\Queue\InteractsWithQueue;11use Illuminate\Queue\InteractsWithQueue;12use Illuminate\Queue\SerializesModels;12use Illuminate\Queue\SerializesModels;13use Illuminate\Support\Facades\Log;13use Illuminate\Support\Facades\Log;14use Jiminny\Component\Queue\Constants;14use Jiminny\Component\Queue\Constants;15use Jiminny\Models\Activity;15use Jiminny\Models\Activity;16use Jiminny\Models\Activity\Search;16use Jiminny\Models\Activity\Search;17+use Jiminny\Models\Activity\SearchFilter;17use Jiminny\Models\Nudge;18use Jiminny\Models\Nudge;18use Jiminny\Models\Team;19use Jiminny\Models\Team;1920@@ -34,37 +35,201 @@343535public function handle(): void36public function handle(): void36 {37 {37-/** @var Activity $activity */38+$activity = Activity::with(['user.group'])->uuid($this->activityUuid, false)->firstOrFail();38-$activity = Activity::with(['user'])->uuid($this->activityUuid, false)->firstOrFail();39-40-/** @var Team $team */41$team = Team::with(['users'])->findOrFail($activity->user->team_id);39$team = Team::with(['users'])->findOrFail($activity->user->team_id);424043- Log::info(__METHOD__ . " Running for team $team->id.", [44-'activity_id' => $activity->id,45-'activity_uuid' => $this->activityUuid,46-'team_id' => $team->id,47- ]);48-49$usersIds = $team->users->pluck('id')->toArray();41$usersIds = $team->users->pluck('id')->toArray();504251-$searchesWithImmediateNudges = Activity\Search::with(['nudges'])43+$searchesWithImmediateNudges = Activity\Search::with([44+'nudges' => fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY),45+'filters',46+ ])52 ->whereIn('user_id', $usersIds)47 ->whereIn('user_id', $usersIds)53- ->whereHas('nudges', function (Builder $query) {48+ ->whereHas('nudges', fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY))54-$query->where('frequency', Nudge::FREQ_INSTANTLY);49+ ->get();55- })->get();50+51+$totalSearches = $searchesWithImmediateNudges->count();52+$skippedCount = 0;53+54+$searchesWithImmediateNudges->each(function (Search $search) use ($activity, &$skippedCount): void {55+$matchResult = $this->activityMightMatchSearch($activity, $search);565657-$searchesWithImmediateNudges->each(function (Search $search): void {57+if (! $matchResult['matches']) {58-$search->nudges->each(function (Nudge $nudge): void {58+$skippedCount++;59-// Filter only nudges that are set to be sent instantly59+ Log::info('Pre-filter skipped nudge dispatch', [60-if ($nudge->frequency === Nudge::FREQ_INSTANTLY) {60+'activity_uuid' => $activity->getUuid(),61- Log::info("Dispatching ProcessNudgeSearchJob for nudge $nudge->id.");61+'search_id' => $search->getId(),62+'mismatched_filter' => $matchResult['mismatch_reason'],63+'filter_value' => $matchResult['filter_value'],64+ ]);626563- ProcessNudgeSearchJob::dispatch($nudge);66+return;67+ }646865- Log::info("ProcessNudgeSearchJob dispatched for nudge $nudge->id.");69+$search->nudges->each(fn ($nudge) => ProcessNudgeSearchJob::dispatch($nudge));66- }67- });68 });70 });71+72+if ($totalSearches > 0) {73+ Log::info('Nudge pre-filter results', [74+'activity_uuid' => $activity->getUuid(),75+'total_searches' => $totalSearches,76+'skipped' => $skippedCount,77+'dispatched' => $totalSearches - $skippedCount,78+'skip_rate' => round(($skippedCount / $totalSearches) * 100, 2) . '%',79+ ]);80+ }81+ }82+83+private function activityMightMatchSearch(Activity $activity, Search $search): array84+ {85+foreach ($search->filters as $filter) {86+$filterName = $filter->getFilterProperty();87+88+$result = match ($filterName) {89+'group_id' => $this->checkGroupId($activity, $filter),90+'user_id' => $this->checkUserId($activity, $filter),91+'channel_id' => $this->checkChannelId($activity, $filter),92+'provider_id' => $this->checkProviderId($activity, $filter),93+'category_id' => $this->checkCategoryId($activity, $filter),94+'min_duration' => $this->checkMinDuration($activity, $filter),95+'max_duration' => $this->checkMaxDuration($activity, $filter),96+'not_logged' => $this->checkNotLogged($activity, $filter),97+'only_recorded' => $this->checkOnlyRecorded($activity, $filter),98+'languages' => $this->checkLanguages($activity, $filter),99+'stage_id' => $this->checkStageId($activity, $filter),100+'start_date' => $this->checkStartDate($activity, $filter),101+'end_date' => $this->checkEndDate($activity, $filter),102+default => null, // Unknown filter - can't pre-check, assume might match103+ };104+105+if ($result === false) {106+return [107+'matches' => false,108+'mismatch_reason' => $filterName,109+'filter_value' => $filter->getFilterValue(),110+ ];111+ }112+ }113+114+return ['matches' => true];115+ }116+117+private function checkGroupId(Activity $activity, SearchFilter $filter): ?bool118+ {119+$groupUuid = $activity->user->getGroup()?->getUuid();120+if ($groupUuid === null) {121+return null;122+ }123+124+return $filter->getFilterValue() === $groupUuid ? null : false;125+ }126+127+private function checkUserId(Activity $activity, SearchFilter $filter): ?bool128+ {129+return $filter->getFilterValue() === $activity->user->getUuid() ? null : false;130+ }131+132+private function checkChannelId(Activity $activity, SearchFilter $filter): ?bool133+ {134+return $filter->getFilterValue() === $activity->getType() ? null : false;135+ }136+137+private function checkProviderId(Activity $activity, SearchFilter $filter): ?bool138+ {139+return $filter->getFilterValue() === $activity->getProvider() ? null : false;140+ }141+142+private function checkCategoryId(Activity $activity, SearchFilter $filter): ?bool143+ {144+$categoryId = $activity->getCategory()?->getUuid();145+if ($categoryId === null) {146+return null;147+ }148+149+return $filter->getFilterValue() === $categoryId ? null : false;150+ }151+152+private function checkMinDuration(Activity $activity, SearchFilter $filter): ?bool153+ {154+return $activity->getDuration() >= (float) $filter->getFilterValue() ? null : false;155+ }156+157+private function checkMaxDuration(Activity $activity, SearchFilter $filter): ?bool158+ {159+return $activity->getDuration() <= (float) $filter->getFilterValue() ? null : false;160+ }161+162+private function checkNotLogged(Activity $activity, SearchFilter $filter): ?bool163+ {164+if (! $filter->getFilterValue()) {165+return null;166+ }167+168+$isLogged = $activity->getCrmProviderId() !== null;169+$isInternal = $activity->isInternal();170+171+return (! $isLogged || $isInternal) ? null : false;172+ }173+174+private function checkOnlyRecorded(Activity $activity, SearchFilter $filter): ?bool175+ {176+$filterValue = (int) $filter->getFilterValue();177+$hasRecording = $activity->recording_state !== Activity::RECORDING_OFF;178+179+return match ($filterValue) {180+1 => $hasRecording ? null : false, // Only recorded181+2 => ! $hasRecording ? null : false, // Only non-recorded182+default => null,183+ };184+ }185+186+private function checkStageId(Activity $activity, SearchFilter $filter): ?bool187+ {188+$stageId = $activity->getStage()?->getUuid();189+if ($stageId === null) {190+return null; // No stage, let ES handle191+ }192+193+return $filter->getFilterValue() === $stageId ? null : false;194+ }195+196+private function checkStartDate(Activity $activity, SearchFilter $filter): ?bool197+ {198+$startTime = $activity->getActualStartTime();199+if ($startTime === null) {200+return null;201+ }202+203+$filterDate = Carbon::parse($filter->getFilterValue());204+205+return $startTime->gte($filterDate) ? null : false;206+ }207+208+private function checkEndDate(Activity $activity, SearchFilter $filter): ?bool209+ {210+$endTime = $activity->getActualEndTime();211+if ($endTime === null) {212+return null;213+ }214+215+$filterDate = Carbon::parse($filter->getFilterValue())->endOfDay();216+217+return $endTime->lte($filterDate) ? null : false;218+ }219+220+private function checkLanguages(Activity $activity, SearchFilter $filter): ?bool221+ {222+$activityLanguage = $activity->getLanguageCode();223+if ($activityLanguage === null) {224+return null;225+ }226+227+// Filter values are always base language codes (e.g., 'en', 'fr').228+// Extract base code from activity locale (e.g., en_GB -> en) to match ES query behavior.229+// See LanguageFilterDefinition::getQueries() which uses regex: $language . '_[a-z]{2}'230+$activityLangCode = explode('_', $activityLanguage)[0];231+$filterLanguage = $filter->getFilterValue();232+233+return $activityLangCode === $filterLanguage ? null : false;69 }234 }70}235}</selection>” selected. Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
You said
I’m on page “<tabTitle>Jy 20493 smart instant nudge pre filtering by niko</tabTitle>” with “<selection>@@ -4,16 +4,17 @@445namespace Jiminny\Component\Nudge\Job;5namespace Jiminny\Component\Nudge\Job;667+use Carbon\Carbon;7use Illuminate\Bus\Queueable;8use Illuminate\Bus\Queueable;8use Illuminate\Contracts\Queue\ShouldQueue;9use Illuminate\Contracts\Queue\ShouldQueue;9-use Illuminate\Database\Eloquent\Builder;10use Illuminate\Foundation\Bus\Dispatchable;10use Illuminate\Foundation\Bus\Dispatchable;11use Illuminate\Queue\InteractsWithQueue;11use Illuminate\Queue\InteractsWithQueue;12use Illuminate\Queue\SerializesModels;12use Illuminate\Queue\SerializesModels;13use Illuminate\Support\Facades\Log;13use Illuminate\Support\Facades\Log;14use Jiminny\Component\Queue\Constants;14use Jiminny\Component\Queue\Constants;15use Jiminny\Models\Activity;15use Jiminny\Models\Activity;16use Jiminny\Models\Activity\Search;16use Jiminny\Models\Activity\Search;17+use Jiminny\Models\Activity\SearchFilter;17use Jiminny\Models\Nudge;18use Jiminny\Models\Nudge;18use Jiminny\Models\Team;19use Jiminny\Models\Team;1920@@ -34,37 +35,201 @@343535public function handle(): void36public function handle(): void36 {37 {37-/** @var Activity $activity */38+$activity = Activity::with(['user.group'])->uuid($this->activityUuid, false)->firstOrFail();38-$activity = Activity::with(['user'])->uuid($this->activityUuid, false)->firstOrFail();39-40-/** @var Team $team */41$team = Team::with(['users'])->findOrFail($activity->user->team_id);39$team = Team::with(['users'])->findOrFail($activity->user->team_id);424043- Log::info(__METHOD__ . " Running for team $team->id.", [44-'activity_id' => $activity->id,45-'activity_uuid' => $this->activityUuid,46-'team_id' => $team->id,47- ]);48-49$usersIds = $team->users->pluck('id')->toArray();41$usersIds = $team->users->pluck('id')->toArray();504251-$searchesWithImmediateNudges = Activity\Search::with(['nudges'])43+$searchesWithImmediateNudges = Activity\Search::with([44+'nudges' => fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY),45+'filters',46+ ])52 ->whereIn('user_id', $usersIds)47 ->whereIn('user_id', $usersIds)53- ->whereHas('nudges', function (Builder $query) {48+ ->whereHas('nudges', fn ($q) => $q->where('frequency', Nudge::FREQ_INSTANTLY))54-$query->where('frequency', Nudge::FREQ_INSTANTLY);49+ ->get();55- })->get();50+51+$totalSearches = $searchesWithImmediateNudges->count();52+$skippedCount = 0;53+54+$searchesWithImmediateNudges->each(function (Search $search) use ($activity, &$skippedCount): void {55+$matchResult = $this->activityMightMatchSearch($activity, $search);565657-$searchesWithImmediateNudges->each(function (Search $search): void {57+if (! $matchResult['matches']) {58-$search->nudges->each(function (Nudge $nudge): void {58+$skippedCount++;59-// Filter only nudges that are set to be sent instantly59+ Log::info('Pre-filter skipped nudge dispatch', [60-if ($nudge->frequency === Nudge::FREQ_INSTANTLY) {60+'activity_uuid' => $activity->getUuid(),61- Log::info("Dispatching ProcessNudgeSearchJob for nudge $nudge->id.");61+'search_id' => $search->getId(),62+'mismatched_filter' => $matchResult['mismatch_reason'],63+'filter_value' => $matchResult['filter_value'],64+ ]);626563- ProcessNudgeSearchJob::dispatch($nudge);66+return;67+ }646865- Log::info("ProcessNudgeSearchJob dispatched for nudge $nudge->id.");69+$search->nudges->each(fn ($nudge) => ProcessNudgeSearchJob::dispatch($nudge));66- }67- });68 });70 });71+72+if ($totalSearches > 0) {73+ Log::info('Nudge pre-filter results', [74+'activity_uuid' => $activity->getUuid(),75+'total_searches' => $totalSearches,76+'skipped' => $skippedCount,77+'dispatched' => $totalSearches - $skippedCount,78+'skip_rate' => round(($skippedCount / $totalSearches) * 100, 2) . '%',79+ ]);80+ }81+ }82+83+private function activityMightMatchSearch(Activity $activity, Search $search): array84+ {85+foreach ($search->filters as $filter) {86+$filterName = $filter->getFilterProperty();87+88+$result = match ($filterName) {89+'group_id' => $this->checkGroupId($activity, $filter),90+'user_id' => $this->checkUserId($activity, $filter),91+'channel_id' => $this->checkChannelId($activity, $filter),92+'provider_id' => $this->checkProviderId($activity, $filter),93+'category_id' => $this->checkCategoryId($activity, $filter),94+'min_duration' => $this->checkMinDuration($activity, $filter),95+'max_duration' => $this->checkMaxDuration($activity, $filter),96+'not_logged' => $this->checkNotLogged($activity, $filter),97+'only_recorded' => $this->checkOnlyRecorded($activity, $filter),98+'languages' => $this->checkLanguages($activity, $filter),99+'stage_id' => $this->checkStageId($activity, $filter),100+'start_date' => $this->checkStartDate($activity, $filter),101+'end_date' => $this->checkEndDate($activity, $filter),102+default => null, // Unknown filter - can't pre-check, assume might match103+ };104+105+if ($result === false) {106+return [107+'matches' => false,108+'mismatch_reason' => $filterName,109+'filter_value' => $filter->getFilterValue(),110+ ];111+ }112+ }113+114+return ['matches' => true];115+ }116+117+private function checkGroupId(Activity $activity, SearchFilter $filter): ?bool118+ {119+$groupUuid = $activity->user->getGroup()?->getUuid();120+if ($groupUuid === null) {121+return null;122+ }123+124+return $filter->getFilterValue() === $groupUuid ? null : false;125+ }126+127+private function checkUserId(Activity $activity, SearchFilter $filter): ?bool128+ {129+return $filter->getFilterValue() === $activity->user->getUuid() ? null : false;130+ }131+132+private function checkChannelId(Activity $activity, SearchFilter $filter): ?bool133+ {134+return $filter->getFilterValue() === $activity->getType() ? null : false;135+ }136+137+private function checkProviderId(Activity $activity, SearchFilter $filter): ?bool138+ {139+return $filter->getFilterValue() === $activity->getProvider() ? null : false;140+ }141+142+private function checkCategoryId(Activity $activity, SearchFilter $filter): ?bool143+ {144+$categoryId = $activity->getCategory()?->getUuid();145+if ($categoryId === null) {146+return null;147+ }148+149+return $filter->getFilterValue() === $categoryId ? null : false;150+ }151+152+private function checkMinDuration(Activity $activity, SearchFilter $filter): ?bool153+ {154+return $activity->getDuration() >= (float) $filter->getFilterValue() ? null : false;155+ }156+157+private function checkMaxDuration(Activity $activity, SearchFilter $filter): ?bool158+ {159+return $activity->getDuration() <= (float) $filter->getFilterValue() ? null : false;160+ }161+162+private function checkNotLogged(Activity $activity, SearchFilter $filter): ?bool163+ {164+if (! $filter->getFilterValue()) {165+return null;166+ }167+168+$isLogged = $activity->getCrmProviderId() !== null;169+$isInternal = $activity->isInternal();170+171+return (! $isLogged || $isInternal) ? null : false;172+ }173+174+private function checkOnlyRecorded(Activity $activity, SearchFilter $filter): ?bool175+ {176+$filterValue = (int) $filter->getFilterValue();177+$hasRecording = $activity->recording_state !== Activity::RECORDING_OFF;178+179+return match ($filterValue) {180+1 => $hasRecording ? null : false, // Only recorded181+2 => ! $hasRecording ? null : false, // Only non-recorded182+default => null,183+ };184+ }185+186+private function checkStageId(Activity $activity, SearchFilter $filter): ?bool187+ {188+$stageId = $activity->getStage()?->getUuid();189+if ($stageId === null) {190+return null; // No stage, let ES handle191+ }192+193+return $filter->getFilterValue() === $stageId ? null : false;194+ }195+196+private function checkStartDate(Activity $activity, SearchFilter $filter): ?bool197+ {198+$startTime = $activity->getActualStartTime();199+if ($startTime === null) {200+return null;201+ }202+203+$filterDate = Carbon::parse($filter->getFilterValue());204+205+return $startTime->gte($filterDate) ? null : false;206+ }207+208+private function checkEndDate(Activity $activity, SearchFilter $filter): ?bool209+ {210+$endTime = $activity->getActualEndTime();211+if ($endTime === null) {212+return null;213+ }214+215+$filterDate = Carbon::parse($filter->getFilterValue())->endOfDay();216+217+return $endTime->lte($filterDate) ? null : false;218+ }219+220+private function checkLanguages(Activity $activity, SearchFilter $filter): ?bool221+ {222+$activityLanguage = $activity->getLanguageCode();223+if ($activityLanguage === null) {224+return null;225+ }226+227+// Filter values are always base language codes (e.g., 'en', 'fr').228+// Extract base code from activity locale (e.g., en_GB -> en) to match ES query behavior.229+// See LanguageFilterDefinition::getQueries() which uses regex: $language . '_[a-z]{2}'230+$activityLangCode = explode('_', $activityLanguage)[0];231+$filterLanguage = $filter->getFilterValue();232+233+return $activityLangCode === $filterLanguage ? null : false;69 }234 }70}235}</selection>” selected.
Please summarize the selection using precise and concise language. Use headers and bulleted lists in the summary, to make it scannable. Maintain the meaning and factual accuracy.
Expand
Listen
Gemini said
Gemini said
This code selection introduces a
pre-filtering mechanism
to the
Jiminny\Component\Nudge\Job
namespace. The primary goal is to optimize performance by validating an activity against search criteria in-memory before dispatching costly background jobs.
Core Functionality Changes
Core Functionality Changes
Selective Loading:
The
handle()
method now eager-loads
user.group
for activities and specifically filters for
FREQ_INSTANTLY
nudges and their associated search filters.
Pre-Dispatch Validation:
Instead of dispatching jobs for every instant nudge, the system now calls
activityMightMatchSearch()
.
Short-Circuiting:
If an activity fails a pre-filter check (e.g., mismatched user ID or duration), the job dispatch is skipped, and the event is logged with the specific mismatch reason.
Performance Metrics:
Adds summary logging at the end of the process to track:
Total searches processed.
Number of skipped dispatches.
The "Skip Rate" percentage.
Implemented Filter Checks
Implemented Filter Checks
The logic includes a
match
expression to validate various activity attributes against
SearchFilter
values:
Identity & Metadata:
Matches for
group_id
,
user_id
,
channel_id
, and
provider_id
.
Temporal & Duration:
* Validates
min_duration
and
max_duration
.
Checks
start_date
and
end_date
using Carbon parsing.
Activity State:
*
Logging:
Determines if an activity is logged to a CRM or is internal via
checkNotLogged
.
Recording:
Uses
checkOnlyRecorded
to filter based on whether a recording exists.
Categorization:
Checks for
category_id
,
stage_id
, and
languages
.
Note:
The language check specifically extracts base codes (e.g.,
en
from
en_GB
) to align with Elasticsearch behavior.
Logic Design
Logic Design
Nullable Returns:
Filter methods return
null
if a match is possible (or cannot be determined), and
false
only when a definitive mismatch is found.
Safe Fallback:
If a filter type is unknown (
default
), the system assumes a match and proceeds to dispatch, ensuring no false negatives.
Good response
Bad response
Share & export
Copy
Show more options
Copy prompt
You said what is the logic behind diff. Act as code reviewer. First review the changes then explain it and then evaluate. Try to find potential issues and bottlenecks
You said
what is the logic behind diff. Act as code reviewer. First review the changes then explain it and then evaluate. Try to find potential issues and bottlenecks
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Here is a review of the changes provided in the diff, broken down by your requested structure.
1. Review of Changes
1. Review of Changes
This PR refactors the
ProcessNudgeSearchJob
dispatching mechanism within the
handle()
method.
Query Optimization:
Eager loads necessary relationships (
user.group
,
filters
) and scopes the
nudges
relationship at the database level to only fetch
FREQ_INSTANTLY
records.
In-Memory Filtering:
Introduces a pre-filtering mechanism (
activityMightMatchSearch
) that checks the
Activity
against
SearchFilter...
|
8217
|
NULL
|
NULL
|
NULL
|
|
8507
|
378
|
6
|
2026-05-08T10:47:50.215848+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-08/1778 /Users/lukas/.screenpipe/data/data/2026-05-08/1778237270215_m2.jpg...
|
PhpStorm
|
faVsco.js – Client.php
|
True
|
NULL
|
monitor_2
|
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
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Show Replace Field
Search History
rateLimiter
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/4
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Sync Changes
Hide This Notification
Code changed:
Hide
2
65
1
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
//use Jiminny\Component\Utility\Service\ProviderRateLimiter;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
public function isHubspotRateLimit(Throwable $e): bool
{
return method_exists($e, 'getCode') && (int) $e->getCode() === 429;
}
public function parseRetryAfter(Throwable $e): int
{
// First try to get Retry-After from response headers
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
// For search APIs, headers are often missing - check response body for policyName
if (method_exists($e, 'getResponseBody')) {
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
$policyName = $body['policyName'] ?? $body['policy'] ?? null;
// Map policy names to retry delays
if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {
return 10;
}
if ($policyName === 'SECONDLY' || $policyName === 'secondly') {
return 1;
}
}
// Also check nested context object if present
if (method_exists($e, 'getResponseBody')) {
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
$context = $body['context'] ?? [];
$policyName = $context['policyName'] ?? null;
if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {
return 10;
}
if ($policyName === 'SECONDLY' || $policyName === 'secondly') {
return 1;
}
}
$this->log->debug('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
$response = $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
$response = $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
//
// $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // "110"
// $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // "109"
// $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"
// $body = json_decode((string) $response->getBody(), true);
//
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));
return $response;
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options...
|
[{"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":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"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,"bounds":{"left":0.8081782,"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":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"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 'AskJiminnyReportActivityServiceTest'","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 'AskJiminnyReportActivityServiceTest'","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":"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":"19","depth":4,"bounds":{"left":0.6615692,"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.67287236,"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.68018615,"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-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","depth":4,"bounds":{"left":0.40259308,"top":0.09736632,"width":0.5728058,"height":0.8818835},"on_screen":true,"lines":[{"char_start":207,"char_count":30,"bounds":{"left":0.40259308,"top":0.0,"width":0.07513298,"height":0.014365523}},{"char_start":237,"char_count":36,"bounds":{"left":0.40259308,"top":0.0,"width":0.09075798,"height":0.014365523}},{"char_start":273,"char_count":32,"bounds":{"left":0.40259308,"top":0.0,"width":0.080119684,"height":0.014365523}},{"char_start":305,"char_count":79,"bounds":{"left":0.40259308,"top":0.0,"width":0.20212767,"height":0.014365523}},{"char_start":384,"char_count":18,"bounds":{"left":0.40259308,"top":0.0,"width":0.043882977,"height":0.014365523}},{"char_start":402,"char_count":21,"bounds":{"left":0.40259308,"top":0.0,"width":0.051861703,"height":0.014365523}},{"char_start":423,"char_count":48,"bounds":{"left":0.40259308,"top":0.008778931,"width":0.12167553,"height":0.014365523}},{"char_start":471,"char_count":72,"bounds":{"left":0.40259308,"top":0.026336791,"width":0.18384309,"height":0.014365523}},{"char_start":543,"char_count":40,"bounds":{"left":0.40259308,"top":0.043894652,"width":0.10106383,"height":0.014365523}},{"char_start":583,"char_count":41,"bounds":{"left":0.40259308,"top":0.061452515,"width":0.10372341,"height":0.014365523}},{"char_start":624,"char_count":72,"bounds":{"left":0.40259308,"top":0.079010375,"width":0.18384309,"height":0.014365523}},{"char_start":696,"char_count":219,"bounds":{"left":0.40259308,"top":0.096568234,"width":0.56515956,"height":0.014365523}},{"char_start":915,"char_count":83,"bounds":{"left":0.40259308,"top":0.11412609,"width":0.21243352,"height":0.014365523}},{"char_start":998,"char_count":20,"bounds":{"left":0.40259308,"top":0.13168396,"width":0.04920213,"height":0.014365523}},{"char_start":1018,"char_count":17,"bounds":{"left":0.40259308,"top":0.14924182,"width":0.041223403,"height":0.014365523}},{"char_start":1035,"char_count":203,"bounds":{"left":0.40259308,"top":0.16679968,"width":0.52360374,"height":0.014365523}},{"char_start":1238,"char_count":22,"bounds":{"left":0.40259308,"top":0.18435754,"width":0.05418883,"height":0.014365523}},{"char_start":1260,"char_count":23,"bounds":{"left":0.40259308,"top":0.2019154,"width":0.056848403,"height":0.014365523}},{"char_start":1283,"char_count":10,"bounds":{"left":0.40259308,"top":0.21947326,"width":0.023271276,"height":0.014365523}},{"char_start":1293,"char_count":27,"bounds":{"left":0.40259308,"top":0.23703113,"width":0.06715426,"height":0.014365523}},{"char_start":1320,"char_count":26,"bounds":{"left":0.40259308,"top":0.254589,"width":0.06482713,"height":0.014365523}},{"char_start":1346,"char_count":23,"bounds":{"left":0.40259308,"top":0.27214685,"width":0.056848403,"height":0.014365523}},{"char_start":1369,"char_count":28,"bounds":{"left":0.40259308,"top":0.2897047,"width":0.06981383,"height":0.014365523}},{"char_start":1397,"char_count":57,"bounds":{"left":0.40259308,"top":0.30726257,"width":0.14494681,"height":0.014365523}}],"value":"[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {\n\"headers\":{\n\"Date\":[\"Thu,07 May 2026 14:21:15 GMT\"],\n \"Content-Type\":[\"application/json;charset=utf-8\"],\n \"Transfer-Encoding\":[\"chunked\"],\n \"Connection\":[\"keep-alive\"],\n \"CF-Ray\":[\"9f80deb8db60dc3a-SOF\"],\n \"CF-Cache-Status\":[\"DYNAMIC\"],\n \"Strict-Transport-Security\":[\"max-age=31536000; includeSubDomains; preload\"],\n \"Vary\":[\"origin,\n accept-encoding\"],\n \"access-control-allow-credentials\":[\"false\"],\n \"server-timing\":[\"hcid;desc=\\\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\\\",\n cfr;desc=\\\"9f80deb8e7c6dc3a-IAD\\\"\"],\n \"x-content-type-options\":[\"nosniff\"],\n \"x-hubspot-correlation-id\":[\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\"],\n \"Set-Cookie\":[\"__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-1.0.1.1-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,\n 07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None\"],\n \"Report-To\":[\"{\n\\\"endpoints\\\":[{\n\\\"url\\\":\\\"https:\\\\/\\\\/a.nel.cloudflare.com\\\\/report\\\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\\\"}],\n\\\"group\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"NEL\":[\"{\n\\\"success_fraction\\\":0.01,\n\\\"report_to\\\":\\\"cf-nel\\\",\n\\\"max_age\\\":604800}\"],\n\"Server\":[\"cloudflare\"]}} {\n\"correlation_id\":\"95236535-ec98-4541-b92a-adfa73b69eab\",\n\"trace_id\":\"c7ab8365-903f-46d4-9403-0e5b551e3545\"}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Show Replace Field","depth":4,"bounds":{"left":0.10472074,"top":0.1300878,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Search History","depth":3,"bounds":{"left":0.11735372,"top":0.1292897,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"rateLimiter","depth":4,"bounds":{"left":0.12832446,"top":0.1292897,"width":0.043882977,"height":0.015961692},"on_screen":true,"value":"rateLimiter","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":3,"bounds":{"left":0.18118352,"top":0.1292897,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Match Case","depth":3,"bounds":{"left":0.19115691,"top":0.1292897,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Words","depth":3,"bounds":{"left":0.19980054,"top":0.1292897,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Regex","depth":3,"bounds":{"left":0.20844415,"top":0.1292897,"width":0.00731383,"height":0.017557861},"on_screen":true,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Replace History","depth":3,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Replace","depth":4,"on_screen":false,"role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"New Line","depth":3,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXCheckBox","text":"Preserve case","depth":3,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"checkbox","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1/4","depth":4,"bounds":{"left":0.22207446,"top":0.12849163,"width":0.025598405,"height":0.017557861},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Occurrence","depth":4,"bounds":{"left":0.24767287,"top":0.12769353,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Occurrence","depth":4,"bounds":{"left":0.25631648,"top":0.12769353,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Filter Search Results","depth":4,"bounds":{"left":0.2649601,"top":0.12769353,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open in Window, Multiple Cursors","depth":4,"bounds":{"left":0.27360374,"top":0.12769353,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Click to highlight","depth":4,"on_screen":false,"role_description":"link","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":4,"bounds":{"left":0.37034574,"top":0.12769353,"width":0.008643617,"height":0.01915403},"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.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":"2","depth":4,"bounds":{"left":0.32779256,"top":0.15881884,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"65","depth":4,"bounds":{"left":0.33776596,"top":0.15881884,"width":0.010305851,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.35006648,"top":0.15881884,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.359375,"top":0.15881884,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.36901596,"top":0.15722266,"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.37632978,"top":0.15722266,"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\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\n//use Jiminny\\Component\\Utility\\Service\\ProviderRateLimiter;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n// private ProviderRateLimiter $rateLimiter;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n// ProviderRateLimiter $rateLimiter,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n// $this->rateLimiter = $rateLimiter;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Single entry point for every HubSpot API call. Enforces the per-portal\n * rate limit configured in the rate_limits table (morphed to the current\n * Configuration) and reacts to a real 429 from HubSpot by translating it\n * into a RateLimitException carrying Retry-After.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n return method_exists($e, 'getCode') && (int) $e->getCode() === 429;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n // First try to get Retry-After from response headers\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n // For search APIs, headers are often missing - check response body for policyName\n if (method_exists($e, 'getResponseBody')) {\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n $policyName = $body['policyName'] ?? $body['policy'] ?? null;\n\n // Map policy names to retry delays\n if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {\n return 10;\n }\n if ($policyName === 'SECONDLY' || $policyName === 'secondly') {\n return 1;\n }\n }\n\n // Also check nested context object if present\n if (method_exists($e, 'getResponseBody')) {\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n $context = $body['context'] ?? [];\n $policyName = $context['policyName'] ?? null;\n\n if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {\n return 10;\n }\n if ($policyName === 'SECONDLY' || $policyName === 'secondly') {\n return 1;\n }\n }\n\n $this->log->debug('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n//\n// $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n// $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n// $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n// $body = json_decode((string) $response->getBody(), true);\n//\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot;\n\nuse HubSpot\\Client\\Crm\\Deals\\ApiException as DealApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\ApiException as ContactApiException;\nuse HubSpot\\Client\\Crm\\Companies\\ApiException as CompanyApiException;\nuse HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectWithAssociations as ContactsWithAssociations;\nuse HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectWithAssociations as CompaniesWithAssociations;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectWithAssociations as DealWithAssociations;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectInput;\nuse HubSpot\\Client\\Crm\\Objects\\Model\\SimplePublicObjectWithAssociations as ObjectWithAssociations;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\Error;\nuse HubSpot\\Client\\Crm\\Pipelines\\Model\\PipelineStage;\nuse HubSpot\\Client\\Crm\\Properties\\Model\\Property;\nuse HubSpot\\Discovery\\Discovery;\n//use Jiminny\\Component\\Utility\\Service\\ProviderRateLimiter;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\RateLimitException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Jobs\\Crm\\NoteObject;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Services\\Crm\\BaseClient;\nuse Jiminny\\Services\\Crm\\Hubspot\\DTO\\Response\\Owner;\nuse Jiminny\\Services\\SocialAccountService;\nuse SevenShores\\Hubspot\\Exceptions\\BadRequest;\nuse SevenShores\\Hubspot\\Exceptions\\HubspotException;\nuse SevenShores\\Hubspot\\Factory;\nuse SevenShores\\Hubspot\\Http\\Response;\nuse Jiminny\\Services\\Crm\\Hubspot\\Pagination\\HubspotPaginationService;\nuse Throwable;\n\n/**\n * @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}\n */\nclass Client extends BaseClient implements HubspotClientInterface\n{\n public const string MIN_API_VERSION = '2';\n\n public const string BASE_URL = 'https://api.hubapi.com';\n\n public const int ASSOCIATIONS_BATCH_SIZE_LIMIT = 1000;\n\n private HubspotPaginationService $paginationService;\n private HubspotTokenManager $tokenManager;\n// private ProviderRateLimiter $rateLimiter;\n\n public function __construct(\n SocialAccountService $socialAccountService,\n HubspotPaginationService $paginationService,\n HubspotTokenManager $tokenManager,\n// ProviderRateLimiter $rateLimiter,\n ) {\n parent::__construct($socialAccountService);\n $this->paginationService = $paginationService;\n $this->tokenManager = $tokenManager;\n// $this->rateLimiter = $rateLimiter;\n\n $this->setBaseUrl(self::BASE_URL);\n $this->setVersion(self::MIN_API_VERSION);\n }\n\n /**\n * Single entry point for every HubSpot API call. Enforces the per-portal\n * rate limit configured in the rate_limits table (morphed to the current\n * Configuration) and reacts to a real 429 from HubSpot by translating it\n * into a RateLimitException carrying Retry-After.\n *\n * Wrap any outbound HubSpot call (SDK or raw HTTP) like:\n *\n * $this->executeRequest(fn () => $this->getNewInstance()->crm()->...);\n *\n * @template T\n * @param callable(): T $apiCall\n * @return T\n *\n * @throws RateLimitException\n */\n private function executeRequest(callable $apiCall)\n {\n try {\n return $apiCall();\n } catch (Throwable $e) {\n if ($this->isHubspotRateLimit($e)) {\n $retryAfter = $this->parseRetryAfter($e);\n\n $this->log->warning('[Hubspot] Received 429 from API', [\n 'team_id' => $this->config->team_id,\n 'config_id' => $this->config->getId(),\n 'retry_after' => $retryAfter,\n 'reason' => $e->getMessage(),\n ]);\n\n throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);\n }\n\n throw $e;\n }\n }\n\n public function isHubspotRateLimit(Throwable $e): bool\n {\n return method_exists($e, 'getCode') && (int) $e->getCode() === 429;\n }\n\n public function parseRetryAfter(Throwable $e): int\n {\n // First try to get Retry-After from response headers\n if (method_exists($e, 'getResponseHeaders')) {\n $headers = $e->getResponseHeaders() ?: [];\n $value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;\n if (is_array($value)) {\n $value = $value[0] ?? null;\n }\n if (is_numeric($value)) {\n return (int) $value;\n }\n }\n\n // For search APIs, headers are often missing - check response body for policyName\n if (method_exists($e, 'getResponseBody')) {\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n $policyName = $body['policyName'] ?? $body['policy'] ?? null;\n\n // Map policy names to retry delays\n if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {\n return 10;\n }\n if ($policyName === 'SECONDLY' || $policyName === 'secondly') {\n return 1;\n }\n }\n\n // Also check nested context object if present\n if (method_exists($e, 'getResponseBody')) {\n $body = $e->getResponseBody();\n if (is_string($body)) {\n $body = json_decode($body, true) ?? [];\n }\n $context = $body['context'] ?? [];\n $policyName = $context['policyName'] ?? null;\n\n if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {\n return 10;\n }\n if ($policyName === 'SECONDLY' || $policyName === 'secondly') {\n return 1;\n }\n }\n\n $this->log->debug('[Hubspot] No retry-after header or policy name found, using default', [\n 'exception_class' => get_class($e),\n ]);\n\n return 10;\n }\n\n public function getMinimumApiVersion(): string\n {\n return self::MIN_API_VERSION;\n }\n\n public function getInstance(): Factory\n {\n return new Factory([\n 'key' => $this->accessToken,\n 'oauth2' => true,\n 'base_url' => $this->baseUrl,\n ]);\n }\n\n public function getNewInstance(): Discovery\n {\n return \\HubSpot\\Factory::createWithAccessToken($this->accessToken);\n }\n\n /**\n * Secondly and daily limits for Hubspot API\n *\n * Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)\n * Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds\n * Daily: 250,000 | 500,000 | 1,000,000\n *\n * Official documentation states: The search endpoints are rate limited to five requests per second.\n * Since with 5 RPS were still hitting secondly rate limits we lowered it to 4\n */\n public function getPaginatedData(array $payload, string $type, int $offset = 0): array\n {\n $total = 0;\n $lastId = null;\n $rows = [];\n foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {\n $rows[] = $row;\n }\n\n return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];\n }\n\n /**\n * @throws HubspotException\n * @throws SocialAccountTokenInvalidException\n * @throws BadRequest\n */\n public function getPaginatedDataGenerator(\n array $payload,\n string $type,\n int $offset = 0,\n int &$total = 0,\n ?string &$lastRecordId = null\n ): \\Generator {\n return $this->paginationService->getPaginatedDataGenerator(\n $this,\n $payload,\n $type,\n $offset,\n $total,\n $lastRecordId\n );\n }\n\n /**\n * Execute a search request against HubSpot CRM objects with rate limiting.\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')\n * @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.\n * @return array The search response with 'results', 'total', 'paging' keys\n * @throws RateLimitException When rate limit is hit\n * @throws HubspotException On API errors\n */\n public function search(string $objectType, array $payload): array\n {\n $endpoint = self::BASE_URL . \"/crm/v3/objects/{$objectType}/search\";\n\n return $this->executeRequest(function () use ($endpoint, $payload) {\n $response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);\n\n return $response->toArray();\n });\n }\n\n /**\n * @throws DealApiException\n * @throws CrmException\n */\n public function getOpportunityById(string $crmId, array $fields): array\n {\n try {\n// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n 'companies,contacts'\n );\n } catch (DealApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $deal instanceof DealWithAssociations) {\n throw new CrmException('Deal not found');\n }\n\n return [\n 'id' => $deal->getId(),\n 'properties' => $deal->getProperties(),\n 'associations' => $deal->getAssociations(),\n ];\n }\n\n /**\n * Generic batch read method for HubSpot objects\n *\n * @param string $objectType The object type ('deals', 'companies', 'contacts')\n * @param array<string> $crmIds Array of HubSpot object IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with object data\n */\n private function batchReadObjects(string $objectType, array $crmIds, array $fields): array\n {\n if (empty($crmIds)) {\n return [];\n }\n\n $this->validateBatchSize($objectType, $crmIds);\n $this->ensureValidToken();\n\n try {\n $batchConfig = $this->createBatchConfiguration($objectType);\n $batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);\n $response = $batchConfig['api']->read($batchReadRequest);\n\n $this->validateApiResponse($response, $objectType);\n\n $results = $this->processApiResults($response);\n $this->logBatchResults($objectType, $crmIds, $results);\n\n return $results;\n } catch (\\Throwable $e) {\n $this->handleBatchError($e, $objectType, $crmIds);\n }\n }\n\n private function validateBatchSize(string $objectType, array $crmIds): void\n {\n if (count($crmIds) > 100) {\n throw new \\InvalidArgumentException(\"Batch size cannot exceed 100 {$objectType}\");\n }\n }\n\n private function createBatchConfiguration(string $objectType): array\n {\n $configurations = [\n 'deals' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Deals\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Deals\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->deals()->batchApi(),\n ],\n 'companies' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Companies\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Companies\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->companies()->batchApi(),\n ],\n 'contacts' => [\n 'batchReadRequest' => new \\HubSpot\\Client\\Crm\\Contacts\\Model\\BatchReadInputSimplePublicObjectId(),\n 'inputClass' => \\HubSpot\\Client\\Crm\\Contacts\\Model\\SimplePublicObjectId::class,\n 'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),\n ],\n ];\n\n if (! isset($configurations[$objectType])) {\n throw new \\InvalidArgumentException(\"Unsupported object type: {$objectType}\");\n }\n\n return $configurations[$objectType];\n }\n\n private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object\n {\n $batchReadRequest = $batchConfig['batchReadRequest'];\n $inputClass = $batchConfig['inputClass'];\n\n $inputs = array_map(function ($crmId) use ($inputClass) {\n $input = new $inputClass();\n $input->setId($crmId);\n\n return $input;\n }, $crmIds);\n\n $batchReadRequest->setInputs($inputs);\n $batchReadRequest->setProperties($fields);\n\n return $batchReadRequest;\n }\n\n private function validateApiResponse($response, string $objectType): void\n {\n if (! $response) {\n throw new CrmException(\"HubSpot API returned null response for {$objectType} batch read\");\n }\n }\n\n private function processApiResults($response): array\n {\n $results = [];\n $responseResults = $response->getResults();\n\n if ($responseResults) {\n foreach ($responseResults as $object) {\n if ($object && $object->getId()) {\n $results[$object->getId()] = [\n 'id' => $object->getId(),\n 'properties' => $object->getProperties() ?: [],\n ];\n }\n }\n }\n\n return $results;\n }\n\n private function logBatchResults(string $objectType, array $crmIds, array $results): void\n {\n $this->log->info(\"[HubSpot] Batch fetched {$objectType}\", [\n 'requested_count' => count($crmIds),\n 'returned_count' => count($results),\n 'crm_ids' => $crmIds,\n ]);\n }\n\n private function handleBatchError(\\Throwable $e, string $objectType, array $crmIds): void\n {\n $errorMessage = $e->getMessage() ?: 'Unknown error';\n $errorTrace = $e->getTraceAsString() ?: 'No trace available';\n\n $this->log->error(\"[HubSpot] Failed to batch fetch {$objectType}\", [\n 'crm_ids' => $crmIds,\n 'error' => $errorMessage,\n 'trace' => $errorTrace,\n ]);\n\n throw new CrmException(\"Failed to batch fetch {$objectType}: \" . $errorMessage);\n }\n\n /**\n * Batch read multiple opportunities by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot deal IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with opportunity data\n */\n public function getOpportunitiesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('deals', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple companies by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot company IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with company data\n */\n public function getCompaniesByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('companies', $crmIds, $fields);\n }\n\n /**\n * Batch read multiple contacts by their CRM IDs\n *\n * @param array<string> $crmIds Array of HubSpot contact IDs (max 100)\n * @param array<string> $fields Array of property names to fetch\n *\n * @return array<string, array> Array keyed by CRM ID with contact data\n */\n public function getContactsByIds(array $crmIds, array $fields): array\n {\n return $this->batchReadObjects('contacts', $crmIds, $fields);\n }\n\n /**\n * @throws CompanyApiException\n * @throws CrmException\n */\n public function getAccountById(string $crmId, array $fields): array\n {\n try {\n $company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(\n $crmId,\n implode(',', $fields),\n );\n } catch (CompanyApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch account', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $company instanceof CompaniesWithAssociations) {\n throw new CrmException('Account not found');\n }\n\n return [\n 'id' => $company->getId(),\n 'properties' => $company->getProperties(),\n ];\n }\n\n /**\n * @throws ContactApiException\n * @throws CrmException\n */\n public function getContactById(string $crmId, array $fields): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $crmId,\n implode(',', $fields)\n );\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'crm_id' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n if (! $contact instanceof ContactsWithAssociations) {\n throw new CrmException('Contact not found');\n }\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n }\n\n /**\n * This is email search request that Hubspot offers as GET (more generous quota)\n */\n public function getContactByEmail(string $email, array $fields = []): array\n {\n try {\n $contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(\n $email,\n implode(',', $fields),\n null,\n false,\n 'email'\n );\n\n return [\n 'id' => $contact->getId(),\n 'properties' => $contact->getProperties(),\n ];\n } catch (ContactApiException $e) {\n $this->log->info('[Hubspot] Failed to fetch contact', [\n 'email' => $email,\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n }\n\n /**\n * @throws CrmException\n */\n public function fetchProperty(string $objectType, string $propertyId): Property\n {\n $result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);\n\n if (! $result instanceof Property) {\n $this->log->error('[Hubspot] Failed to fetch property', [\n 'object_type' => $objectType,\n 'property_id' => $propertyId,\n 'reason' => $result->getMessage(),\n ]);\n\n throw new CrmException('Failed to fetch property');\n }\n\n return $result;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchPropertyOptions(string $objectType, string $propertyId): array\n {\n /** @var array<CrmFieldOption> */\n return $this->fetchProperty($objectType, $propertyId)->getOptions();\n }\n\n /**\n * @return array<array{id:string, label:string, deleted:bool}>\n */\n public function fetchCallDispositions(): array\n {\n /** @var Response $response */\n $response = $this->getInstance()->engagements()->getCallDispositions();\n\n /**\n * @var array<array{\n * id:string,\n * label:string,\n * deleted: bool\n * }>\n */\n return $response->toArray();\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityPipelineStages(): array\n {\n $stages = [];\n $apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');\n\n if ($apiResponse instanceof Error) {\n $this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $apiResponse->getMessage(),\n ]);\n\n return [];\n }\n\n foreach ($apiResponse->getResults() as $pipeline) {\n $pipelineStages = array_map(\n static function (PipelineStage $stage) {\n return [\n 'id' => $stage->getId(),\n 'label' => $stage->getLabel(),\n ];\n },\n $pipeline->getStages()\n );\n\n $stages = array_merge($stages, $pipelineStages);\n }\n\n return $stages;\n }\n\n public function fetchOpportunityPipelines(): array\n {\n $pipelines = [];\n\n try {\n $apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');\n } catch (\\Exception $e) {\n $this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [\n 'reason' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n $response = $apiResponse->toArray();\n\n foreach ($response['results'] as $pipeline) {\n $pipelines[] = [\n 'id' => $pipeline['id'],\n 'label' => $pipeline['label'],\n ];\n }\n\n return $pipelines;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchMeetingOutcomeFieldOptions(Field $field): array\n {\n return $field->getCrmProviderId() === 'meetingOutcome'\n ? $this->fetchMeetingOutcomeTypes()\n : $this->fetchCallActivityTypes();\n }\n\n public function fetchMeetingOutcomeTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/meeting/hs_meeting_outcome'\n );\n }\n\n public function fetchCallActivityTypes(): array\n {\n return $this->extractMeetingTypeOptions(\n 'https://api.hubapi.com/crm/v3/properties/call/hs_activity_type'\n );\n }\n\n private function extractMeetingTypeOptions(string $endpoint): array\n {\n /** @var Response $response */\n $response = $this->getInstance()\n ->getClient()\n ->request('GET', $endpoint);\n\n /**\n * @var array<array{\n * value: string,\n * label: string,\n * displayOrder: int\n * }> $optionData\n */\n $optionData = $response->toArray()['options'] ?? [];\n\n $options = [];\n foreach ($optionData as $item) {\n $options[] = [\n 'id' => $item['value'],\n 'value' => $item['value'],\n 'label' => $item['label'],\n 'display_order' => $item['displayOrder'],\n ];\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchDispositionFieldOptions(): array\n {\n $options = [];\n\n $dispositions = $this->fetchCallDispositions();\n\n foreach ($dispositions as $disposition) {\n if ($disposition['deleted'] !== false) {\n continue;\n }\n\n $option['value'] = $disposition['id'];\n $option['id'] = $disposition['id'];\n $option['label'] = $disposition['label'];\n\n $options[] = $option;\n }\n\n return $options;\n }\n\n /**\n * @return array<CrmFieldOption>\n */\n public function fetchOpportunityFieldOptions(Field $field): array\n {\n if ($field->isStageField()) {\n return $this->fetchOpportunityPipelineStages();\n }\n\n if ($field->isPipelineField()) {\n return $this->fetchOpportunityPipelines();\n }\n\n return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)\n {\n $endpoint = self::BASE_URL . $endpoint;\n\n if ($method === 'GET') {\n $response = $this->getInstance()->getClient()?->request(\n method: $method,\n endpoint: $endpoint,\n query_string: $queryString\n );\n } else {\n $response = $this->getInstance()->getClient()->request($method, $endpoint, [\n 'json' => ($payload),\n ]);\n }\n//\n// $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // \"110\"\n// $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // \"109\"\n// $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // \"10000\"\n// $body = json_decode((string) $response->getBody(), true);\n//\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));\n// \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));\n\n return $response;\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function createMeeting(array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings';\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n /**\n * @throws BadRequest\n * @throws HubspotException\n */\n public function updateMeeting(string $meetingId, array $payload): Response\n {\n $endpoint = '/crm/v3/objects/meetings/' . $meetingId;\n\n return $this->makeRequest($endpoint, 'PATCH', $payload);\n }\n\n /**\n * @throws \\Exception\n */\n public function createNote(\n string $body,\n string $ownerId,\n int $timestamp,\n string $objectId,\n NoteObject $noteObject\n ): ?string {\n try {\n $noteInput = new SimplePublicObjectInput([\n 'properties' => [\n 'hs_note_body' => $body,\n 'hubspot_owner_id' => $ownerId,\n 'hs_timestamp' => $timestamp,\n ],\n ]);\n\n // Create note\n $note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);\n\n $this->getNewInstance()->crm()->objects()->associationsApi()->create(\n 'note',\n $note->getId(),\n $this->getNoteObject($noteObject),\n $objectId,\n $this->getNoteAssociationType($noteObject),\n );\n\n return $note->getId();\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to create note', [\n 'objectId' => $objectId,\n 'noteObject' => $noteObject->getObjectType(),\n 'reason' => $e->getMessage(),\n ]);\n\n \\Sentry::captureException($e);\n }\n\n return null;\n }\n\n public function updateEngagement(string $objectId, array $engagement, array $metadata): void\n {\n $this->getInstance()->engagements()->update($objectId, $engagement, $metadata);\n }\n\n public function getEngagementData(string $engagementId): array\n {\n $engagement = $this->getInstance()->engagements()->get($engagementId);\n\n return $engagement->toArray();\n }\n\n public function createEngagement(array $engagement, array $associations, array $metadata): Response\n {\n return $this->getInstance()\n ->engagements()\n ->create($engagement, $associations, $metadata);\n }\n\n public function isUnauthorizedException(\\Exception $e): bool\n {\n // Check for specific HubSpot API exception types first\n if ($e instanceof BadRequest) {\n // BadRequest can contain 401 status codes\n return $e->getCode() === 401;\n }\n\n // Check for HTTP client exceptions with status codes\n if ($e instanceof \\GuzzleHttp\\Exception\\RequestException && $e->hasResponse()) {\n $response = $e->getResponse();\n if ($response !== null) {\n return $response->getStatusCode() === 401;\n }\n }\n\n // Check for Guzzle HTTP exceptions\n if ($e instanceof \\GuzzleHttp\\Exception\\ClientException) {\n return $e->getCode() === 401;\n }\n\n // Fallback to string matching as last resort, but be more specific\n $message = strtolower($e->getMessage());\n\n return str_contains($message, '401 unauthorized') ||\n str_contains($message, 'http 401') ||\n str_contains($message, 'status code 401') ||\n (preg_match('/\\b401\\b/', $message) && str_contains($message, 'unauthorized'));\n }\n\n /**\n * Validates and refreshes the access token if needed before API requests.\n * This ensures long-running processes don't fail due to token expiration.\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function ensureValidToken(): void\n {\n if ($this->oauthAccount === null) {\n return;\n }\n\n $newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);\n if ($newToken !== null) {\n $this->accessToken = $newToken;\n }\n }\n\n public function getConfig()\n {\n return $this->config;\n }\n\n // returns only active (archived=false)\n public function getOwners(): array\n {\n return $this->getNewInstance()->crm()->owners()->getAll();\n }\n\n /**\n * @param bool $archived\n *\n * @return array<Owner>|[]\n */\n public function getOwnersArchived(bool $archived = true): array\n {\n $endpoint = '/crm/v3/owners';\n $queryParams = [\n 'archived' => $archived ? 'true' : 'false',\n ];\n $queryString = http_build_query($queryParams);\n\n $owners = [];\n\n try {\n $response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);\n $responseData = $response?->toArray();\n\n foreach ($responseData['results'] as $result) {\n try {\n $owners[] = Owner::create($result);\n } catch (Throwable $e) {\n $this->log->error('[HubSpot] Failed to process owner data', [\n 'result' => $result,\n 'error' => $e->getMessage(),\n ]);\n\n continue;\n }\n }\n } catch (Throwable $e) {\n $this->log->error('HubSpot] Failed to fetch owners', [\n 'archived' => $archived,\n 'error' => $e->getMessage(),\n ]);\n\n return [];\n }\n\n return $owners;\n }\n\n public function getMeeting(string $engagementId): ObjectWithAssociations\n {\n return $this->getNewInstance()->crm()->objects()->basicApi()\n ->getById('meeting', $engagementId, null, 'contact,company,deal');\n }\n\n public function deleteEngagement(string $engagementId): void\n {\n $this->getInstance()->engagements()->delete((int) $engagementId);\n }\n\n public function getAssociationsData(array $ids, string $fromObject, string $toObject): array\n {\n $associationData = [];\n $idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);\n\n foreach ($idChunks as $idChunk) {\n try {\n $batchInput = new \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchInputPublicObjectId();\n $batchInput->setInputs(array_map(function ($id) {\n $publicObjectId = new \\HubSpot\\Client\\Crm\\Associations\\Model\\PublicObjectId();\n $publicObjectId->setId($id);\n\n return $publicObjectId;\n }, $idChunk));\n\n $associatedObjectsData = $this\n ->getNewInstance()\n ->crm()\n ->associations()\n ->batchApi()\n ->read($fromObject, $toObject, $batchInput);\n\n if ($associatedObjectsData instanceof \\HubSpot\\Client\\Crm\\Associations\\Model\\BatchResponsePublicAssociationMulti) {\n foreach ($associatedObjectsData->getResults() as $association) {\n $from = $association->getFrom()->getId();\n $toAssociations = $association->getTo();\n\n if (! empty($toAssociations)) {\n $associationData[$from] = array_map(function ($item) {\n return $item->getId();\n }, $toAssociations);\n }\n }\n }\n } catch (\\Exception $e) {\n $this->log->error('[Hubspot] Failed to fetch associations', [\n 'from_object' => $fromObject,\n 'to_object' => $toObject,\n 'reason' => $e->getMessage(),\n ]);\n }\n }\n\n return $associationData;\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteAssociationType(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'note_to_deal',\n NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it\n NoteObject::Account => 'note_to_company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n /**\n * @throws \\Exception\n */\n private function getNoteObject(NoteObject $noteObject): string\n {\n return match($noteObject) {\n NoteObject::Opportunity => 'deal',\n NoteObject::Lead, NoteObject::Contact => 'contact',\n NoteObject::Account => 'company',\n NoteObject::Call, NoteObject::Event => throw new \\Exception('Not supported'),\n };\n }\n\n public function addAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/create\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n\n public function removeAssociations(string $objectType, string $associationType, array $payload): Response\n {\n $endpoint = \"/crm/v4/associations/$objectType/$associationType/batch/archive\";\n\n return $this->makeRequest($endpoint, 'POST', $payload);\n }\n}","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}]...
|
-7736239136245084212
|
-2844612687923636124
|
visual_change
|
accessibility
|
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
19
Previous Highlighted Error
Next Highlighted Error
[2026-05-07 14:21:15] local.INFO: [Hubspot] DEBUG Getting headers {
"headers":{
"Date":["Thu,07 May 2026 14:21:15 GMT"],
"Content-Type":["application/json;charset=utf-8"],
"Transfer-Encoding":["chunked"],
"Connection":["keep-alive"],
"CF-Ray":["9f80deb8db60dc3a-SOF"],
"CF-Cache-Status":["DYNAMIC"],
"Strict-Transport-Security":["max-age=31536000; includeSubDomains; preload"],
"Vary":["origin,
accept-encoding"],
"access-control-allow-credentials":["false"],
"server-timing":["hcid;desc=\"019e02d0-6fd8-7812-bdba-885b7ccb3ee3\",
cfr;desc=\"9f80deb8e7c6dc3a-IAD\""],
"x-content-type-options":["nosniff"],
"x-hubspot-correlation-id":["019e02d0-6fd8-7812-bdba-885b7ccb3ee3"],
"Set-Cookie":["__cf_bm=SIUrtdQgXVrik50pdqF6hZVYKhzTnQBidvMabeCtm0Y-1778163675-[IP_ADDRESS]-rI.ZggtDKxTge5zr8_2gbBfWMQQ.ufZEXDZyHz2mBUFdzdo2gTHEsOkXMSEShjK0hGYxNhUGM1ZoBpX7BcFZcHEjA7Cs_.SMUhUnd2nYjko; path=/; expires=Thu,
07-May-26 14:51:15 GMT; domain=.hubapi.com; HttpOnly; Secure; SameSite=None"],
"Report-To":["{
\"endpoints\":[{
\"url\":\"https:\\/\\/a.nel.cloudflare.com\\/report\\/v4?s=NYAlsVTP0fYm32qrSDjxYE4sd2RWRqiSp3wHsmdEgZlzoYdxI%2BIxVpHmsKn3O%2BKVA3mFIJ2m7YRECDGSM%2BW2IYTzo6FM4%2BdUIjURO8srzKSvJgZ%2BQ6R79arKQw3uHLlX\"}],
\"group\":\"cf-nel\",
\"max_age\":604800}"],
"NEL":["{
\"success_fraction\":0.01,
\"report_to\":\"cf-nel\",
\"max_age\":604800}"],
"Server":["cloudflare"]}} {
"correlation_id":"95236535-ec98-4541-b92a-adfa73b69eab",
"trace_id":"c7ab8365-903f-46d4-9403-0e5b551e3545"}
Show Replace Field
Search History
rateLimiter
New Line
Match Case
Words
Regex
Replace History
Replace
New Line
Preserve case
1/4
Previous Occurrence
Next Occurrence
Filter Search Results
Open in Window, Multiple Cursors
Click to highlight
Close
Sync Changes
Hide This Notification
Code changed:
Hide
2
65
1
2
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot;
use HubSpot\Client\Crm\Deals\ApiException as DealApiException;
use HubSpot\Client\Crm\Contacts\ApiException as ContactApiException;
use HubSpot\Client\Crm\Companies\ApiException as CompanyApiException;
use HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectWithAssociations as ContactsWithAssociations;
use HubSpot\Client\Crm\Companies\Model\SimplePublicObjectWithAssociations as CompaniesWithAssociations;
use HubSpot\Client\Crm\Deals\Model\SimplePublicObjectWithAssociations as DealWithAssociations;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectInput;
use HubSpot\Client\Crm\Objects\Model\SimplePublicObjectWithAssociations as ObjectWithAssociations;
use HubSpot\Client\Crm\Pipelines\Model\Error;
use HubSpot\Client\Crm\Pipelines\Model\PipelineStage;
use HubSpot\Client\Crm\Properties\Model\Property;
use HubSpot\Discovery\Discovery;
//use Jiminny\Component\Utility\Service\ProviderRateLimiter;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\RateLimitException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Jobs\Crm\NoteObject;
use Jiminny\Models\Crm\Field;
use Jiminny\Services\Crm\BaseClient;
use Jiminny\Services\Crm\Hubspot\DTO\Response\Owner;
use Jiminny\Services\SocialAccountService;
use SevenShores\Hubspot\Exceptions\BadRequest;
use SevenShores\Hubspot\Exceptions\HubspotException;
use SevenShores\Hubspot\Factory;
use SevenShores\Hubspot\Http\Response;
use Jiminny\Services\Crm\Hubspot\Pagination\HubspotPaginationService;
use Throwable;
/**
* @phpstan-type CrmFieldOption array{id:string, label:string, value?:string}
*/
class Client extends BaseClient implements HubspotClientInterface
{
public const string MIN_API_VERSION = '2';
public const string BASE_URL = '[URL_WITH_CREDENTIALS] T
* @param callable(): T $apiCall
* @return T
*
* @throws RateLimitException
*/
private function executeRequest(callable $apiCall)
{
try {
return $apiCall();
} catch (Throwable $e) {
if ($this->isHubspotRateLimit($e)) {
$retryAfter = $this->parseRetryAfter($e);
$this->log->warning('[Hubspot] Received 429 from API', [
'team_id' => $this->config->team_id,
'config_id' => $this->config->getId(),
'retry_after' => $retryAfter,
'reason' => $e->getMessage(),
]);
throw new RateLimitException('Hubspot returned 429', $retryAfter, $e);
}
throw $e;
}
}
public function isHubspotRateLimit(Throwable $e): bool
{
return method_exists($e, 'getCode') && (int) $e->getCode() === 429;
}
public function parseRetryAfter(Throwable $e): int
{
// First try to get Retry-After from response headers
if (method_exists($e, 'getResponseHeaders')) {
$headers = $e->getResponseHeaders() ?: [];
$value = $headers['Retry-After'] ?? $headers['retry-after'] ?? null;
if (is_array($value)) {
$value = $value[0] ?? null;
}
if (is_numeric($value)) {
return (int) $value;
}
}
// For search APIs, headers are often missing - check response body for policyName
if (method_exists($e, 'getResponseBody')) {
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
$policyName = $body['policyName'] ?? $body['policy'] ?? null;
// Map policy names to retry delays
if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {
return 10;
}
if ($policyName === 'SECONDLY' || $policyName === 'secondly') {
return 1;
}
}
// Also check nested context object if present
if (method_exists($e, 'getResponseBody')) {
$body = $e->getResponseBody();
if (is_string($body)) {
$body = json_decode($body, true) ?? [];
}
$context = $body['context'] ?? [];
$policyName = $context['policyName'] ?? null;
if ($policyName === 'TEN_SECONDLY_ROLLING' || $policyName === 'ten_secondly_rolling') {
return 10;
}
if ($policyName === 'SECONDLY' || $policyName === 'secondly') {
return 1;
}
}
$this->log->debug('[Hubspot] No retry-after header or policy name found, using default', [
'exception_class' => get_class($e),
]);
return 10;
}
public function getMinimumApiVersion(): string
{
return self::MIN_API_VERSION;
}
public function getInstance(): Factory
{
return new Factory([
'key' => $this->accessToken,
'oauth2' => true,
'base_url' => $this->baseUrl,
]);
}
public function getNewInstance(): Discovery
{
return \HubSpot\Factory::createWithAccessToken($this->accessToken);
}
/**
* Secondly and daily limits for Hubspot API
*
* Product Tier: Free & Starter | Professional & Enterprise | API add-on (any tier)
* Burst: 100/10 seconds | 150/10 seconds | 200/10 seconds
* Daily: 250,000 | 500,000 | 1,000,000
*
* Official documentation states: The search endpoints are rate limited to five requests per second.
* Since with 5 RPS were still hitting secondly rate limits we lowered it to 4
*/
public function getPaginatedData(array $payload, string $type, int $offset = 0): array
{
$total = 0;
$lastId = null;
$rows = [];
foreach ($this->getPaginatedDataGenerator($payload, $type, $offset, $total, $lastId) as $row) {
$rows[] = $row;
}
return ['results' => $rows, 'total' => $total, 'last_record' => $lastId];
}
/**
* @throws HubspotException
* @throws SocialAccountTokenInvalidException
* @throws BadRequest
*/
public function getPaginatedDataGenerator(
array $payload,
string $type,
int $offset = 0,
int &$total = 0,
?string &$lastRecordId = null
): \Generator {
return $this->paginationService->getPaginatedDataGenerator(
$this,
$payload,
$type,
$offset,
$total,
$lastRecordId
);
}
/**
* Execute a search request against HubSpot CRM objects with rate limiting.
*
* @param string $objectType The object type ('deals', 'companies', 'contacts', 'calls')
* @param array<string, mixed> $payload The search payload with filters, sorts, properties, etc.
* @return array The search response with 'results', 'total', 'paging' keys
* @throws RateLimitException When rate limit is hit
* @throws HubspotException On API errors
*/
public function search(string $objectType, array $payload): array
{
$endpoint = self::BASE_URL . "/crm/v3/objects/{$objectType}/search";
return $this->executeRequest(function () use ($endpoint, $payload) {
$response = $this->getInstance()->getClient()->request('POST', $endpoint, ['json' => $payload]);
return $response->toArray();
});
}
/**
* @throws DealApiException
* @throws CrmException
*/
public function getOpportunityById(string $crmId, array $fields): array
{
try {
// $deal = $this->executeRequest(fn () => $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$deal = $this->getNewInstance()->crm()->deals()->basicApi()->getById(
$crmId,
implode(',', $fields),
'companies,contacts'
);
} catch (DealApiException $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $deal instanceof DealWithAssociations) {
throw new CrmException('Deal not found');
}
return [
'id' => $deal->getId(),
'properties' => $deal->getProperties(),
'associations' => $deal->getAssociations(),
];
}
/**
* Generic batch read method for HubSpot objects
*
* @param string $objectType The object type ('deals', 'companies', 'contacts')
* @param array<string> $crmIds Array of HubSpot object IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with object data
*/
private function batchReadObjects(string $objectType, array $crmIds, array $fields): array
{
if (empty($crmIds)) {
return [];
}
$this->validateBatchSize($objectType, $crmIds);
$this->ensureValidToken();
try {
$batchConfig = $this->createBatchConfiguration($objectType);
$batchReadRequest = $this->prepareBatchRequest($batchConfig, $crmIds, $fields);
$response = $batchConfig['api']->read($batchReadRequest);
$this->validateApiResponse($response, $objectType);
$results = $this->processApiResults($response);
$this->logBatchResults($objectType, $crmIds, $results);
return $results;
} catch (\Throwable $e) {
$this->handleBatchError($e, $objectType, $crmIds);
}
}
private function validateBatchSize(string $objectType, array $crmIds): void
{
if (count($crmIds) > 100) {
throw new \InvalidArgumentException("Batch size cannot exceed 100 {$objectType}");
}
}
private function createBatchConfiguration(string $objectType): array
{
$configurations = [
'deals' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Deals\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Deals\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->deals()->batchApi(),
],
'companies' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Companies\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Companies\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->companies()->batchApi(),
],
'contacts' => [
'batchReadRequest' => new \HubSpot\Client\Crm\Contacts\Model\BatchReadInputSimplePublicObjectId(),
'inputClass' => \HubSpot\Client\Crm\Contacts\Model\SimplePublicObjectId::class,
'api' => $this->getNewInstance()->crm()->contacts()->batchApi(),
],
];
if (! isset($configurations[$objectType])) {
throw new \InvalidArgumentException("Unsupported object type: {$objectType}");
}
return $configurations[$objectType];
}
private function prepareBatchRequest(array $batchConfig, array $crmIds, array $fields): object
{
$batchReadRequest = $batchConfig['batchReadRequest'];
$inputClass = $batchConfig['inputClass'];
$inputs = array_map(function ($crmId) use ($inputClass) {
$input = new $inputClass();
$input->setId($crmId);
return $input;
}, $crmIds);
$batchReadRequest->setInputs($inputs);
$batchReadRequest->setProperties($fields);
return $batchReadRequest;
}
private function validateApiResponse($response, string $objectType): void
{
if (! $response) {
throw new CrmException("HubSpot API returned null response for {$objectType} batch read");
}
}
private function processApiResults($response): array
{
$results = [];
$responseResults = $response->getResults();
if ($responseResults) {
foreach ($responseResults as $object) {
if ($object && $object->getId()) {
$results[$object->getId()] = [
'id' => $object->getId(),
'properties' => $object->getProperties() ?: [],
];
}
}
}
return $results;
}
private function logBatchResults(string $objectType, array $crmIds, array $results): void
{
$this->log->info("[HubSpot] Batch fetched {$objectType}", [
'requested_count' => count($crmIds),
'returned_count' => count($results),
'crm_ids' => $crmIds,
]);
}
private function handleBatchError(\Throwable $e, string $objectType, array $crmIds): void
{
$errorMessage = $e->getMessage() ?: 'Unknown error';
$errorTrace = $e->getTraceAsString() ?: 'No trace available';
$this->log->error("[HubSpot] Failed to batch fetch {$objectType}", [
'crm_ids' => $crmIds,
'error' => $errorMessage,
'trace' => $errorTrace,
]);
throw new CrmException("Failed to batch fetch {$objectType}: " . $errorMessage);
}
/**
* Batch read multiple opportunities by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot deal IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with opportunity data
*/
public function getOpportunitiesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('deals', $crmIds, $fields);
}
/**
* Batch read multiple companies by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot company IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with company data
*/
public function getCompaniesByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('companies', $crmIds, $fields);
}
/**
* Batch read multiple contacts by their CRM IDs
*
* @param array<string> $crmIds Array of HubSpot contact IDs (max 100)
* @param array<string> $fields Array of property names to fetch
*
* @return array<string, array> Array keyed by CRM ID with contact data
*/
public function getContactsByIds(array $crmIds, array $fields): array
{
return $this->batchReadObjects('contacts', $crmIds, $fields);
}
/**
* @throws CompanyApiException
* @throws CrmException
*/
public function getAccountById(string $crmId, array $fields): array
{
try {
$company = $this->getNewInstance()->crm()->companies()->basicApi()->getById(
$crmId,
implode(',', $fields),
);
} catch (CompanyApiException $e) {
$this->log->info('[Hubspot] Failed to fetch account', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $company instanceof CompaniesWithAssociations) {
throw new CrmException('Account not found');
}
return [
'id' => $company->getId(),
'properties' => $company->getProperties(),
];
}
/**
* @throws ContactApiException
* @throws CrmException
*/
public function getContactById(string $crmId, array $fields): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$crmId,
implode(',', $fields)
);
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'crm_id' => $crmId,
'reason' => $e->getMessage(),
]);
throw $e;
}
if (! $contact instanceof ContactsWithAssociations) {
throw new CrmException('Contact not found');
}
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
}
/**
* This is email search request that Hubspot offers as GET (more generous quota)
*/
public function getContactByEmail(string $email, array $fields = []): array
{
try {
$contact = $this->getNewInstance()->crm()->contacts()->basicApi()->getById(
$email,
implode(',', $fields),
null,
false,
'email'
);
return [
'id' => $contact->getId(),
'properties' => $contact->getProperties(),
];
} catch (ContactApiException $e) {
$this->log->info('[Hubspot] Failed to fetch contact', [
'email' => $email,
'reason' => $e->getMessage(),
]);
return [];
}
}
/**
* @throws CrmException
*/
public function fetchProperty(string $objectType, string $propertyId): Property
{
$result = $this->getNewInstance()->crm()->properties()->coreApi()->getByName($objectType, $propertyId);
if (! $result instanceof Property) {
$this->log->error('[Hubspot] Failed to fetch property', [
'object_type' => $objectType,
'property_id' => $propertyId,
'reason' => $result->getMessage(),
]);
throw new CrmException('Failed to fetch property');
}
return $result;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchPropertyOptions(string $objectType, string $propertyId): array
{
/** @var array<CrmFieldOption> */
return $this->fetchProperty($objectType, $propertyId)->getOptions();
}
/**
* @return array<array{id:string, label:string, deleted:bool}>
*/
public function fetchCallDispositions(): array
{
/** @var Response $response */
$response = $this->getInstance()->engagements()->getCallDispositions();
/**
* @var array<array{
* id:string,
* label:string,
* deleted: bool
* }>
*/
return $response->toArray();
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityPipelineStages(): array
{
$stages = [];
$apiResponse = $this->getNewInstance()->crm()->pipelines()->pipelinesApi()->getAll('deals');
if ($apiResponse instanceof Error) {
$this->log->error('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $apiResponse->getMessage(),
]);
return [];
}
foreach ($apiResponse->getResults() as $pipeline) {
$pipelineStages = array_map(
static function (PipelineStage $stage) {
return [
'id' => $stage->getId(),
'label' => $stage->getLabel(),
];
},
$pipeline->getStages()
);
$stages = array_merge($stages, $pipelineStages);
}
return $stages;
}
public function fetchOpportunityPipelines(): array
{
$pipelines = [];
try {
$apiResponse = $this->makeRequest('/crm/v3/pipelines/deals');
} catch (\Exception $e) {
$this->log->info('[Hubspot] Failed to fetch opportunity pipelines', [
'reason' => $e->getMessage(),
]);
return [];
}
$response = $apiResponse->toArray();
foreach ($response['results'] as $pipeline) {
$pipelines[] = [
'id' => $pipeline['id'],
'label' => $pipeline['label'],
];
}
return $pipelines;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchMeetingOutcomeFieldOptions(Field $field): array
{
return $field->getCrmProviderId() === 'meetingOutcome'
? $this->fetchMeetingOutcomeTypes()
: $this->fetchCallActivityTypes();
}
public function fetchMeetingOutcomeTypes(): array
{
return $this->extractMeetingTypeOptions(
'[URL_WITH_CREDENTIALS] Response $response */
$response = $this->getInstance()
->getClient()
->request('GET', $endpoint);
/**
* @var array<array{
* value: string,
* label: string,
* displayOrder: int
* }> $optionData
*/
$optionData = $response->toArray()['options'] ?? [];
$options = [];
foreach ($optionData as $item) {
$options[] = [
'id' => $item['value'],
'value' => $item['value'],
'label' => $item['label'],
'display_order' => $item['displayOrder'],
];
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchDispositionFieldOptions(): array
{
$options = [];
$dispositions = $this->fetchCallDispositions();
foreach ($dispositions as $disposition) {
if ($disposition['deleted'] !== false) {
continue;
}
$option['value'] = $disposition['id'];
$option['id'] = $disposition['id'];
$option['label'] = $disposition['label'];
$options[] = $option;
}
return $options;
}
/**
* @return array<CrmFieldOption>
*/
public function fetchOpportunityFieldOptions(Field $field): array
{
if ($field->isStageField()) {
return $this->fetchOpportunityPipelineStages();
}
if ($field->isPipelineField()) {
return $this->fetchOpportunityPipelines();
}
return $this->fetchPropertyOptions('deals', $field->getCrmProviderId());
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function makeRequest(string $endpoint, $method = 'GET', $payload = [], ?string $queryString = null)
{
$endpoint = self::BASE_URL . $endpoint;
if ($method === 'GET') {
$response = $this->getInstance()->getClient()?->request(
method: $method,
endpoint: $endpoint,
query_string: $queryString
);
} else {
$response = $this->getInstance()->getClient()->request($method, $endpoint, [
'json' => ($payload),
]);
}
//
// $max = $response->getHeaderLine('X-HubSpot-RateLimit-Max'); // "110"
// $remaining = $response->getHeaderLine('X-HubSpot-RateLimit-Remaining'); // "109"
// $interval = $response->getHeaderLine('X-HubSpot-RateLimit-Interval-Milliseconds'); // "10000"
// $body = json_decode((string) $response->getBody(), true);
//
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$max ' . PHP_EOL . print_r($max, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$remaining ' . PHP_EOL . print_r($remaining, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$interval ' . PHP_EOL . print_r($interval, true));
// \Illuminate\Support\Facades\Log::channel('custom_channel')->info('$body ' . PHP_EOL . print_r($body, true));
return $response;
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function createMeeting(array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings';
return $this->makeRequest($endpoint, 'POST', $payload);
}
/**
* @throws BadRequest
* @throws HubspotException
*/
public function updateMeeting(string $meetingId, array $payload): Response
{
$endpoint = '/crm/v3/objects/meetings/' . $meetingId;
return $this->makeRequest($endpoint, 'PATCH', $payload);
}
/**
* @throws \Exception
*/
public function createNote(
string $body,
string $ownerId,
int $timestamp,
string $objectId,
NoteObject $noteObject
): ?string {
try {
$noteInput = new SimplePublicObjectInput([
'properties' => [
'hs_note_body' => $body,
'hubspot_owner_id' => $ownerId,
'hs_timestamp' => $timestamp,
],
]);
// Create note
$note = $this->getNewInstance()->crm()->objects()->basicApi()->create('note', $noteInput);
$this->getNewInstance()->crm()->objects()->associationsApi()->create(
'note',
$note->getId(),
$this->getNoteObject($noteObject),
$objectId,
$this->getNoteAssociationType($noteObject),
);
return $note->getId();
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to create note', [
'objectId' => $objectId,
'noteObject' => $noteObject->getObjectType(),
'reason' => $e->getMessage(),
]);
\Sentry::captureException($e);
}
return null;
}
public function updateEngagement(string $objectId, array $engagement, array $metadata): void
{
$this->getInstance()->engagements()->update($objectId, $engagement, $metadata);
}
public function getEngagementData(string $engagementId): array
{
$engagement = $this->getInstance()->engagements()->get($engagementId);
return $engagement->toArray();
}
public function createEngagement(array $engagement, array $associations, array $metadata): Response
{
return $this->getInstance()
->engagements()
->create($engagement, $associations, $metadata);
}
public function isUnauthorizedException(\Exception $e): bool
{
// Check for specific HubSpot API exception types first
if ($e instanceof BadRequest) {
// BadRequest can contain 401 status codes
return $e->getCode() === 401;
}
// Check for HTTP client exceptions with status codes
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
if ($response !== null) {
return $response->getStatusCode() === 401;
}
}
// Check for Guzzle HTTP exceptions
if ($e instanceof \GuzzleHttp\Exception\ClientException) {
return $e->getCode() === 401;
}
// Fallback to string matching as last resort, but be more specific
$message = strtolower($e->getMessage());
return str_contains($message, '401 unauthorized') ||
str_contains($message, 'http 401') ||
str_contains($message, 'status code 401') ||
(preg_match('/\b401\b/', $message) && str_contains($message, 'unauthorized'));
}
/**
* Validates and refreshes the access token if needed before API requests.
* This ensures long-running processes don't fail due to token expiration.
*
* @throws SocialAccountTokenInvalidException
*/
public function ensureValidToken(): void
{
if ($this->oauthAccount === null) {
return;
}
$newToken = $this->tokenManager->ensureValidToken($this->oauthAccount);
if ($newToken !== null) {
$this->accessToken = $newToken;
}
}
public function getConfig()
{
return $this->config;
}
// returns only active (archived=false)
public function getOwners(): array
{
return $this->getNewInstance()->crm()->owners()->getAll();
}
/**
* @param bool $archived
*
* @return array<Owner>|[]
*/
public function getOwnersArchived(bool $archived = true): array
{
$endpoint = '/crm/v3/owners';
$queryParams = [
'archived' => $archived ? 'true' : 'false',
];
$queryString = http_build_query($queryParams);
$owners = [];
try {
$response = $this->makeRequest(endpoint: $endpoint, queryString: $queryString);
$responseData = $response?->toArray();
foreach ($responseData['results'] as $result) {
try {
$owners[] = Owner::create($result);
} catch (Throwable $e) {
$this->log->error('[HubSpot] Failed to process owner data', [
'result' => $result,
'error' => $e->getMessage(),
]);
continue;
}
}
} catch (Throwable $e) {
$this->log->error('HubSpot] Failed to fetch owners', [
'archived' => $archived,
'error' => $e->getMessage(),
]);
return [];
}
return $owners;
}
public function getMeeting(string $engagementId): ObjectWithAssociations
{
return $this->getNewInstance()->crm()->objects()->basicApi()
->getById('meeting', $engagementId, null, 'contact,company,deal');
}
public function deleteEngagement(string $engagementId): void
{
$this->getInstance()->engagements()->delete((int) $engagementId);
}
public function getAssociationsData(array $ids, string $fromObject, string $toObject): array
{
$associationData = [];
$idChunks = array_chunk($ids, self::ASSOCIATIONS_BATCH_SIZE_LIMIT);
foreach ($idChunks as $idChunk) {
try {
$batchInput = new \HubSpot\Client\Crm\Associations\Model\BatchInputPublicObjectId();
$batchInput->setInputs(array_map(function ($id) {
$publicObjectId = new \HubSpot\Client\Crm\Associations\Model\PublicObjectId();
$publicObjectId->setId($id);
return $publicObjectId;
}, $idChunk));
$associatedObjectsData = $this
->getNewInstance()
->crm()
->associations()
->batchApi()
->read($fromObject, $toObject, $batchInput);
if ($associatedObjectsData instanceof \HubSpot\Client\Crm\Associations\Model\BatchResponsePublicAssociationMulti) {
foreach ($associatedObjectsData->getResults() as $association) {
$from = $association->getFrom()->getId();
$toAssociations = $association->getTo();
if (! empty($toAssociations)) {
$associationData[$from] = array_map(function ($item) {
return $item->getId();
}, $toAssociations);
}
}
}
} catch (\Exception $e) {
$this->log->error('[Hubspot] Failed to fetch associations', [
'from_object' => $fromObject,
'to_object' => $toObject,
'reason' => $e->getMessage(),
]);
}
}
return $associationData;
}
/**
* @throws \Exception
*/
private function getNoteAssociationType(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'note_to_deal',
NoteObject::Lead, NoteObject::Contact => 'note_to_contact', // or 'note_to_lead' if your portal supports it
NoteObject::Account => 'note_to_company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
/**
* @throws \Exception
*/
private function getNoteObject(NoteObject $noteObject): string
{
return match($noteObject) {
NoteObject::Opportunity => 'deal',
NoteObject::Lead, NoteObject::Contact => 'contact',
NoteObject::Account => 'company',
NoteObject::Call, NoteObject::Event => throw new \Exception('Not supported'),
};
}
public function addAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/create";
return $this->makeRequest($endpoint, 'POST', $payload);
}
public function removeAssociations(string $objectType, string $associationType, array $payload): Response
{
$endpoint = "/crm/v4/associations/$objectType/$associationType/batch/archive";
return $this->makeRequest($endpoint, 'POST', $payload);
}
}
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options...
|
NULL
|
NULL
|
NULL
|
NULL
|