@symbo.ls/connect 3.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/build.js +205 -0
  2. package/dist/assets/1024x1024.png +0 -0
  3. package/dist/assets/128x128.png +0 -0
  4. package/dist/assets/144x144.png +0 -0
  5. package/dist/assets/192x192.png +0 -0
  6. package/dist/assets/48x48.png +0 -0
  7. package/dist/assets/512x512.png +0 -0
  8. package/dist/assets/72x72.png +0 -0
  9. package/dist/assets/96x96.png +0 -0
  10. package/dist/assets/active_cursor.png +0 -0
  11. package/dist/assets/favicon.svg +6 -0
  12. package/dist/assets/old/144x144.png +0 -0
  13. package/dist/assets/old/192x192.png +0 -0
  14. package/dist/assets/old/48x48.png +0 -0
  15. package/dist/assets/old/48x48_faint.png +0 -0
  16. package/dist/assets/old/512x512.png +0 -0
  17. package/dist/assets/old/72x72.png +0 -0
  18. package/dist/assets/old/96x96.png +0 -0
  19. package/dist/auth.js +373 -0
  20. package/dist/content.css +46 -0
  21. package/dist/content.js +1171 -0
  22. package/dist/content.js.map +7 -0
  23. package/dist/devtools.html +7 -0
  24. package/dist/devtools.js +5 -0
  25. package/dist/manifest.json +87 -0
  26. package/dist/page-agent.js +727 -0
  27. package/dist/panel.css +2239 -0
  28. package/dist/panel.html +235 -0
  29. package/dist/panel.js +4973 -0
  30. package/dist/picker.html +111 -0
  31. package/dist/picker.js +300 -0
  32. package/dist/service_worker.js +219 -0
  33. package/dist/service_worker.js.map +7 -0
  34. package/dist/settings.css +128 -0
  35. package/dist/settings.html +26 -0
  36. package/dist/settings_ui.js +57 -0
  37. package/dist/settings_ui.js.map +7 -0
  38. package/package.json +20 -0
  39. package/src/content.js +104 -0
  40. package/src/grabber/clean.js +605 -0
  41. package/src/grabber/computed.js +78 -0
  42. package/src/grabber/parse.js +268 -0
  43. package/src/grabber/stylesheets.js +117 -0
  44. package/src/grabber/utils.js +238 -0
  45. package/src/service_worker.js +246 -0
  46. package/src/settings/settings_ui.js +52 -0
  47. package/src/settings/settings_utils.js +70 -0
  48. package/static/assets/1024x1024.png +0 -0
  49. package/static/assets/128x128.png +0 -0
  50. package/static/assets/144x144.png +0 -0
  51. package/static/assets/192x192.png +0 -0
  52. package/static/assets/48x48.png +0 -0
  53. package/static/assets/512x512.png +0 -0
  54. package/static/assets/72x72.png +0 -0
  55. package/static/assets/96x96.png +0 -0
  56. package/static/assets/active_cursor.png +0 -0
  57. package/static/assets/favicon.svg +6 -0
  58. package/static/assets/old/144x144.png +0 -0
  59. package/static/assets/old/192x192.png +0 -0
  60. package/static/assets/old/48x48.png +0 -0
  61. package/static/assets/old/48x48_faint.png +0 -0
  62. package/static/assets/old/512x512.png +0 -0
  63. package/static/assets/old/72x72.png +0 -0
  64. package/static/assets/old/96x96.png +0 -0
  65. package/static/auth.js +373 -0
  66. package/static/content.css +46 -0
  67. package/static/devtools.html +7 -0
  68. package/static/devtools.js +5 -0
  69. package/static/manifest.json +56 -0
  70. package/static/page-agent.js +727 -0
  71. package/static/panel.css +2239 -0
  72. package/static/panel.html +235 -0
  73. package/static/panel.js +4973 -0
  74. package/static/picker.html +111 -0
  75. package/static/picker.js +300 -0
  76. package/static/settings.css +128 -0
  77. package/static/settings.html +26 -0
@@ -0,0 +1,246 @@
1
+ import { initSettings } from './settings/settings_utils'
2
+
3
+ // ============================================================
4
+ // Tab state helpers (for grabber toggle)
5
+ // ============================================================
6
+ const getTabState = (tabId) =>
7
+ chrome.storage.session
8
+ .get(String(tabId))
9
+ .then((data) => parseInt(data[tabId] || 0, 10))
10
+
11
+ const setTabState = (tabId, state) =>
12
+ chrome.storage.session.set({ [tabId]: state })
13
+
14
+ const getActiveTabs = () =>
15
+ chrome.tabs.query({ active: true, currentWindow: true })
16
+
17
+ const messageActiveTabs = async (message, { condition, modifyMsg } = {}) => {
18
+ let tabs = await getActiveTabs()
19
+ tabs = tabs.filter(
20
+ (tab) => /^https?:/u.test(tab.url) && (!condition || condition(tab))
21
+ )
22
+
23
+ return Promise.all(
24
+ tabs.map((tab, index) => {
25
+ const msg = modifyMsg ? modifyMsg(tab, message, index) : message
26
+ return chrome.tabs
27
+ .sendMessage(tab.id, msg)
28
+ .then((response) => response)
29
+ .catch((reason) => {
30
+ console.log(`Failed to send msg to tab ${tab.id}`, { reason })
31
+ })
32
+ })
33
+ )
34
+ }
35
+
36
+ const toggleActiveTabsState = async () => {
37
+ const tabs = await getActiveTabs()
38
+ let states = await Promise.all(tabs.map((tab) => getTabState(tab.id)))
39
+ states = states.map((s) => (s ? 0 : 1))
40
+
41
+ return messageActiveTabs(
42
+ { type: 'toggle' },
43
+ {
44
+ modifyMsg: (tab, msg, index) => {
45
+ const state = states[index]
46
+ setTabState(tab.id, state)
47
+ return { ...msg, state }
48
+ }
49
+ }
50
+ )
51
+ }
52
+
53
+ // ============================================================
54
+ // Install / update
55
+ // ============================================================
56
+ chrome.runtime.onInstalled.addListener(({ previousVersion, reason }) => {
57
+ const { name } = chrome.runtime.getManifest()
58
+ chrome.action.setBadgeBackgroundColor({ color: '#099058ff' })
59
+ console.log(`${name} ${reason}`, { id: chrome.runtime.id, previousVersion })
60
+
61
+ if (['install', 'update'].includes(reason)) {
62
+ initSettings()
63
+
64
+ // Override Origin header on API requests to avoid CORS rejection
65
+ chrome.declarativeNetRequest.updateDynamicRules({
66
+ removeRuleIds: [1, 2, 3],
67
+ addRules: [
68
+ {
69
+ id: 1,
70
+ priority: 1,
71
+ action: {
72
+ type: 'modifyHeaders',
73
+ requestHeaders: [
74
+ { header: 'Origin', operation: 'set', value: 'https://symbols.app' }
75
+ ]
76
+ },
77
+ condition: {
78
+ urlFilter: 'https://api.symbols.app/*',
79
+ resourceTypes: ['xmlhttprequest', 'other']
80
+ }
81
+ },
82
+ {
83
+ id: 2,
84
+ priority: 1,
85
+ action: {
86
+ type: 'modifyHeaders',
87
+ requestHeaders: [
88
+ { header: 'Origin', operation: 'remove' }
89
+ ]
90
+ },
91
+ condition: {
92
+ urlFilter: 'https://api.anthropic.com/*',
93
+ resourceTypes: ['xmlhttprequest', 'other']
94
+ }
95
+ }
96
+ ]
97
+ })
98
+ }
99
+ })
100
+
101
+ // ============================================================
102
+ // Badge state
103
+ // ============================================================
104
+ chrome.storage.onChanged.addListener((changes, areas) => {
105
+ if (
106
+ areas === 'session' &&
107
+ Object.values(changes).some((change) => parseInt(change.newValue, 10))
108
+ ) {
109
+ chrome.action.setBadgeText({ text: 'ON' })
110
+ } else {
111
+ chrome.action.setBadgeText({ text: null })
112
+ }
113
+ })
114
+
115
+ chrome.tabs.onActivated.addListener(({ tabId }) => {
116
+ chrome.action.setBadgeText({ text: null })
117
+ setTabState(tabId, 0)
118
+ })
119
+
120
+ // ============================================================
121
+ // Keyboard shortcut (Ctrl+E / Cmd+E)
122
+ // ============================================================
123
+ chrome.commands.onCommand.addListener(async (command) => {
124
+ if (command === 'toggleGrabber') {
125
+ await toggleActiveTabsState()
126
+ }
127
+ })
128
+
129
+ // ============================================================
130
+ // Toolbar icon click -> toggle grabber
131
+ // ============================================================
132
+ chrome.action.onClicked.addListener(async () => {
133
+ await toggleActiveTabsState()
134
+ })
135
+
136
+ // ============================================================
137
+ // Internal messaging (from devtools panel)
138
+ // ============================================================
139
+ let pickerTabId = null
140
+
141
+ chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => {
142
+ if (msg.type === 'open-picker') {
143
+ const pickerUrl = chrome.runtime.getURL('picker.html')
144
+ chrome.tabs.create({ url: pickerUrl, active: true }, (tab) => {
145
+ pickerTabId = tab.id
146
+ })
147
+ sendResponse({ ok: true })
148
+ return true
149
+ }
150
+
151
+ // Forward file operations to the picker tab
152
+ if (msg.type === 'read-file' || msg.type === 'write-file' || msg.type === 'rescan-project') {
153
+ const forwardToPickerTab = (tabId) => {
154
+ chrome.tabs.sendMessage(tabId, msg, (response) => {
155
+ if (chrome.runtime.lastError) {
156
+ sendResponse({ error: 'Picker tab error: ' + chrome.runtime.lastError.message })
157
+ } else {
158
+ sendResponse(response)
159
+ }
160
+ })
161
+ }
162
+
163
+ const openNewPickerTab = () => {
164
+ const pickerUrl = chrome.runtime.getURL('picker.html?bg')
165
+ chrome.tabs.create({ url: pickerUrl, active: false }, (tab) => {
166
+ pickerTabId = tab.id
167
+ // Wait for the page to load before forwarding
168
+ setTimeout(() => forwardToPickerTab(tab.id), 800)
169
+ })
170
+ }
171
+
172
+ if (pickerTabId) {
173
+ // Verify the tab still exists
174
+ chrome.tabs.get(pickerTabId, (tab) => {
175
+ if (chrome.runtime.lastError || !tab) {
176
+ pickerTabId = null
177
+ openNewPickerTab()
178
+ } else {
179
+ forwardToPickerTab(pickerTabId)
180
+ }
181
+ })
182
+ } else {
183
+ openNewPickerTab()
184
+ }
185
+ return true
186
+ }
187
+
188
+ // Proxy API requests — strip Origin to avoid CORS rejection on server
189
+ if (msg.type === 'api-fetch') {
190
+ const headers = new Headers(msg.headers || {})
191
+ headers.delete('Origin')
192
+ const fetchOpts = {
193
+ method: msg.method || 'GET',
194
+ headers
195
+ }
196
+ if (msg.body && msg.method && msg.method !== 'GET') {
197
+ fetchOpts.body = msg.body
198
+ }
199
+ fetch(msg.url, fetchOpts)
200
+ .then((res) => res.text().then((text) => ({ ok: res.ok, status: res.status, text })))
201
+ .then(({ ok, status, text }) => {
202
+ let json = null
203
+ try { json = JSON.parse(text) } catch (e) {}
204
+ sendResponse({ ok, status, data: json, text })
205
+ })
206
+ .catch((e) => {
207
+ sendResponse({ ok: false, status: 0, error: e.message || String(e) })
208
+ })
209
+ return true
210
+ }
211
+
212
+ // Forward folder-picked to all extension pages
213
+ if (msg.type === 'folder-picked') {
214
+ // Already handled by chrome.runtime.onMessage in panel
215
+ }
216
+
217
+ return true
218
+ })
219
+
220
+ // ============================================================
221
+ // External messaging (from symbols.app / platform.symbo.ls)
222
+ // ============================================================
223
+ chrome.runtime.onMessageExternal.addListener(async (msg, sender, respond) => {
224
+ switch (msg.type) {
225
+ case 'toggle_platform_mode': {
226
+ const responses = await toggleActiveTabsState()
227
+ if (responses.some((res) => res && res.success)) {
228
+ const domql = responses.find((res) => res && res.domql)?.domql || null
229
+ setTabState(sender.tab.id, 0)
230
+ respond({ success: true, domql })
231
+ }
232
+ break
233
+ }
234
+ case 'request_domql': {
235
+ const data = await chrome.storage.local.get('domqlStr')
236
+ const domql = JSON.parse(data.domqlStr)
237
+ respond(domql)
238
+ break
239
+ }
240
+ default: {
241
+ console.error('Invalid message received', { msg, sender })
242
+ }
243
+ }
244
+
245
+ return true
246
+ })
@@ -0,0 +1,52 @@
1
+ import {
2
+ getSettings,
3
+ updateSettings,
4
+ settingsDefinitions
5
+ } from './settings_utils'
6
+
7
+ const container = document.getElementById('settings-container')
8
+
9
+ const curSettings = await getSettings()
10
+
11
+ // Build settings UI from definitions
12
+ settingsDefinitions.forEach(({ key, name, type, default: defValue }) => {
13
+ const input = document.createElement('input')
14
+ input.id = key
15
+ input.type = type
16
+
17
+ if (!(key in curSettings)) {
18
+ console.error(`Setting ${key} missing value`, curSettings)
19
+ }
20
+
21
+ const value = curSettings[key] ?? defValue ?? null
22
+
23
+ if ((defValue ?? null) !== null) {
24
+ input.defaultValue = defValue
25
+ }
26
+
27
+ if ((value ?? null) !== null) {
28
+ if (type === 'checkbox') {
29
+ input.checked = value
30
+ } else {
31
+ input.value = value
32
+ }
33
+ }
34
+
35
+ const label = document.createElement('label')
36
+ label.htmlFor = key
37
+ label.textContent = name
38
+
39
+ const wrapper = document.createElement('div')
40
+ wrapper.classList.add('setting')
41
+
42
+ wrapper.append(label)
43
+ wrapper.append(input)
44
+
45
+ container.append(wrapper)
46
+
47
+ input.addEventListener('change', (event) => {
48
+ const val = type === 'checkbox' ? event.target.checked : event.target.value
49
+
50
+ updateSettings({ [key]: val })
51
+ })
52
+ })
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @typedef {Object} Settings
3
+ * @property {boolean} useComputed
4
+ * @property {boolean} useStylesheets
5
+ */
6
+
7
+ const storageKey = 'settings'
8
+
9
+ /**
10
+ * @typedef {Object} SettingDefinition
11
+ * @property {string} type
12
+ * @property {String} name
13
+ * @property {string} [key]
14
+ * @property {any} [default]
15
+ * @property {value} [any]
16
+ */
17
+
18
+ /**
19
+ * @type {SettingDefinition[]}
20
+ */
21
+ export const settingsDefinitions = [
22
+ {
23
+ key: 'useStylesheets',
24
+ name: 'Use Stylesheets',
25
+ type: 'checkbox',
26
+ default: true
27
+ },
28
+ {
29
+ key: 'useComputed',
30
+ name: 'Use Computed',
31
+ type: 'checkbox',
32
+ default: false
33
+ }
34
+ ]
35
+
36
+ /**
37
+ * @returns {Promise<Settings>}
38
+ */
39
+ export const getSettings = async () =>
40
+ (await chrome.storage.local.get(storageKey)).settings
41
+
42
+ /**
43
+ * @param {Partial<Settings>} updates
44
+ */
45
+ export async function updateSettings(updates) {
46
+ const cur = await getSettings()
47
+ chrome.storage.local
48
+ .set({ [storageKey]: { ...cur, ...updates } })
49
+ .catch((reason) => console.error(`failed to update settings : ${reason}`))
50
+ }
51
+
52
+ export async function initSettings() {
53
+ const curSettings = (await getSettings()) ?? {}
54
+
55
+ // construct default settings from definitions
56
+ const defaultSettings = {}
57
+ settingsDefinitions.forEach(({ key, default: defValue }) => {
58
+ defaultSettings[key] = defValue
59
+ })
60
+
61
+ // override defaults with any existing settings
62
+ Object.keys(curSettings).forEach((key) => {
63
+ // only include settings within the current defined set
64
+ if (key in defaultSettings) {
65
+ defaultSettings[key] = curSettings[key]
66
+ }
67
+ })
68
+
69
+ updateSettings(defaultSettings)
70
+ }
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,6 @@
1
+ <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
2
+ <style>
3
+ path { fill: #0085FF; }
4
+ </style>
5
+ <path d="M13.843 2.7C19.063 2.7 23 6.366 23 11.228c0 3.754-2.862 6.584-6.658 6.584-3.287 0-5.007-2.318-5.007-4.609 0-2.395 1.923-4.344 4.287-4.344.566 0 1.023.12 1.309.223a.212.212 0 01.137.229l-.016.058-.514 1.18a.223.223 0 01-.245.13 2.965 2.965 0 00-.506-.046c-1.245 0-2.258 1.027-2.258 2.288 0 1.33 1.165 2.373 2.651 2.373 2.195 0 3.913-1.777 3.913-4.046 0-3.024-2.294-5.135-5.58-5.135-4.076 0-7.393 3.36-7.393 7.491a7.519 7.519 0 002.871 5.924l-4.96 3.18A12.042 12.042 0 012 14.7c0-6.617 5.313-12 11.843-12z" fill-rule="evenodd"/>
6
+ </svg>
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file