@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.
- package/build.js +205 -0
- package/dist/assets/1024x1024.png +0 -0
- package/dist/assets/128x128.png +0 -0
- package/dist/assets/144x144.png +0 -0
- package/dist/assets/192x192.png +0 -0
- package/dist/assets/48x48.png +0 -0
- package/dist/assets/512x512.png +0 -0
- package/dist/assets/72x72.png +0 -0
- package/dist/assets/96x96.png +0 -0
- package/dist/assets/active_cursor.png +0 -0
- package/dist/assets/favicon.svg +6 -0
- package/dist/assets/old/144x144.png +0 -0
- package/dist/assets/old/192x192.png +0 -0
- package/dist/assets/old/48x48.png +0 -0
- package/dist/assets/old/48x48_faint.png +0 -0
- package/dist/assets/old/512x512.png +0 -0
- package/dist/assets/old/72x72.png +0 -0
- package/dist/assets/old/96x96.png +0 -0
- package/dist/auth.js +373 -0
- package/dist/content.css +46 -0
- package/dist/content.js +1171 -0
- package/dist/content.js.map +7 -0
- package/dist/devtools.html +7 -0
- package/dist/devtools.js +5 -0
- package/dist/manifest.json +87 -0
- package/dist/page-agent.js +727 -0
- package/dist/panel.css +2239 -0
- package/dist/panel.html +235 -0
- package/dist/panel.js +4973 -0
- package/dist/picker.html +111 -0
- package/dist/picker.js +300 -0
- package/dist/service_worker.js +219 -0
- package/dist/service_worker.js.map +7 -0
- package/dist/settings.css +128 -0
- package/dist/settings.html +26 -0
- package/dist/settings_ui.js +57 -0
- package/dist/settings_ui.js.map +7 -0
- package/package.json +20 -0
- package/src/content.js +104 -0
- package/src/grabber/clean.js +605 -0
- package/src/grabber/computed.js +78 -0
- package/src/grabber/parse.js +268 -0
- package/src/grabber/stylesheets.js +117 -0
- package/src/grabber/utils.js +238 -0
- package/src/service_worker.js +246 -0
- package/src/settings/settings_ui.js +52 -0
- package/src/settings/settings_utils.js +70 -0
- package/static/assets/1024x1024.png +0 -0
- package/static/assets/128x128.png +0 -0
- package/static/assets/144x144.png +0 -0
- package/static/assets/192x192.png +0 -0
- package/static/assets/48x48.png +0 -0
- package/static/assets/512x512.png +0 -0
- package/static/assets/72x72.png +0 -0
- package/static/assets/96x96.png +0 -0
- package/static/assets/active_cursor.png +0 -0
- package/static/assets/favicon.svg +6 -0
- package/static/assets/old/144x144.png +0 -0
- package/static/assets/old/192x192.png +0 -0
- package/static/assets/old/48x48.png +0 -0
- package/static/assets/old/48x48_faint.png +0 -0
- package/static/assets/old/512x512.png +0 -0
- package/static/assets/old/72x72.png +0 -0
- package/static/assets/old/96x96.png +0 -0
- package/static/auth.js +373 -0
- package/static/content.css +46 -0
- package/static/devtools.html +7 -0
- package/static/devtools.js +5 -0
- package/static/manifest.json +56 -0
- package/static/page-agent.js +727 -0
- package/static/panel.css +2239 -0
- package/static/panel.html +235 -0
- package/static/panel.js +4973 -0
- package/static/picker.html +111 -0
- package/static/picker.js +300 -0
- package/static/settings.css +128 -0
- 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
|
|
Binary file
|