@rubytech/create-sitedesk-code 0.1.526 → 0.1.527
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/package.json +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +73 -7
- package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +7 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +70 -4
- package/payload/platform/plugins/docs/references/internals.md +1 -1
- package/payload/platform/plugins/docs/references/platform.md +1 -1
- package/payload/platform/plugins/linkedin-extension/extension/README.md +10 -2
- package/payload/platform/plugins/linkedin-extension/extension/background/sw.js +37 -4
- package/payload/platform/plugins/linkedin-extension/extension/content/profile.js +17 -2
- package/payload/platform/plugins/linkedin-extension/extension/content/thread.js +17 -2
- package/payload/platform/plugins/linkedin-extension/extension/manifest.json +1 -0
- package/payload/platform/plugins/linkedin-extension/extension/options/options.html +1 -0
- package/payload/platform/plugins/linkedin-extension/extension/options/options.js +78 -3
- package/payload/server/{chunk-WT2PFGY4.js → chunk-KY3BBT67.js} +216 -1
- package/payload/server/maxy-edge.js +226 -6
- package/payload/server/public/activity.html +5 -5
- package/payload/server/public/agents.html +4 -4
- package/payload/server/public/assets/{AdminLoginScreens-BgDjueVe.js → AdminLoginScreens-DSt9DYZZ.js} +1 -1
- package/payload/server/public/assets/AdminLoginScreens-DSt9DYZZ.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-DSt9DYZZ.js.gz +0 -0
- package/payload/server/public/assets/{AdminShell-YctTrR-D.js → AdminShell-MM3_yp3N.js} +1 -1
- package/payload/server/public/assets/AdminShell-MM3_yp3N.js.br +0 -0
- package/payload/server/public/assets/AdminShell-MM3_yp3N.js.gz +0 -0
- package/payload/server/public/assets/{activity-DGQt5ys_.js → activity-aVvbaVd4.js} +1 -1
- package/payload/server/public/assets/activity-aVvbaVd4.js.br +0 -0
- package/payload/server/public/assets/activity-aVvbaVd4.js.gz +0 -0
- package/payload/server/public/assets/{admin-DnUxbB3P.js → admin-B0lQnkH-.js} +1 -1
- package/payload/server/public/assets/admin-B0lQnkH-.js.br +0 -0
- package/payload/server/public/assets/admin-B0lQnkH-.js.gz +0 -0
- package/payload/server/public/assets/{agents-Bc2LZjwC.js → agents-CrpVTPRG.js} +1 -1
- package/payload/server/public/assets/agents-CrpVTPRG.js.br +0 -0
- package/payload/server/public/assets/agents-CrpVTPRG.js.gz +0 -0
- package/payload/server/public/assets/browser-CYHUzTop.js +1 -0
- package/payload/server/public/assets/browser-CYHUzTop.js.br +0 -0
- package/payload/server/public/assets/browser-CYHUzTop.js.gz +0 -0
- package/payload/server/public/assets/{calendar-D25EhXbD.js → calendar-4IWQpwYv.js} +1 -1
- package/payload/server/public/assets/calendar-4IWQpwYv.js.br +0 -0
- package/payload/server/public/assets/calendar-4IWQpwYv.js.gz +0 -0
- package/payload/server/public/assets/chat-DmjZTqnV.js +1 -0
- package/payload/server/public/assets/chat-DmjZTqnV.js.br +0 -0
- package/payload/server/public/assets/chat-DmjZTqnV.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-CIl-s3LZ.js +1 -0
- package/payload/server/public/assets/chevron-left-CIl-s3LZ.js.br +0 -0
- package/payload/server/public/assets/chevron-right-DpAi2BsF.js +1 -0
- package/payload/server/public/assets/chevron-right-DpAi2BsF.js.br +0 -0
- package/payload/server/public/assets/clock-CGuM9VRx.js +1 -0
- package/payload/server/public/assets/clock-CGuM9VRx.js.br +0 -0
- package/payload/server/public/assets/data-BpdFiZKH.js +1 -0
- package/payload/server/public/assets/data-BpdFiZKH.js.br +2 -0
- package/payload/server/public/assets/data-BpdFiZKH.js.gz +0 -0
- package/payload/server/public/assets/{file-download-CiGklOfA.js → file-download-DayBHhKS.js} +1 -1
- package/payload/server/public/assets/file-download-DayBHhKS.js.br +0 -0
- package/payload/server/public/assets/file-download-DayBHhKS.js.gz +0 -0
- package/payload/server/public/assets/{file-text-XjJPULAZ.js → file-text-BSyhVH0m.js} +1 -1
- package/payload/server/public/assets/file-text-BSyhVH0m.js.br +0 -0
- package/payload/server/public/assets/file-text-BSyhVH0m.js.gz +0 -0
- package/payload/server/public/assets/{graph-BjHJ0z_6.js → graph-Bjv3Tc3B.js} +1 -1
- package/payload/server/public/assets/graph-Bjv3Tc3B.js.br +0 -0
- package/payload/server/public/assets/graph-Bjv3Tc3B.js.gz +0 -0
- package/payload/server/public/assets/{graph-labels-D-0u37KA.js → graph-labels-DegLKGdx.js} +1 -1
- package/payload/server/public/assets/graph-labels-DegLKGdx.js.br +0 -0
- package/payload/server/public/assets/graph-labels-DegLKGdx.js.gz +0 -0
- package/payload/server/public/assets/{maximize-2-BJ9S-nfS.js → maximize-2-DJFG2EXJ.js} +1 -1
- package/payload/server/public/assets/maximize-2-DJFG2EXJ.js.br +0 -0
- package/payload/server/public/assets/maximize-2-DJFG2EXJ.js.gz +0 -0
- package/payload/server/public/assets/{operator-Cay4rOOK.js → operator-Du9Ve_PR.js} +1 -1
- package/payload/server/public/assets/operator-Du9Ve_PR.js.br +0 -0
- package/payload/server/public/assets/operator-Du9Ve_PR.js.gz +0 -0
- package/payload/server/public/assets/{page-shuh4ES9.js → page-DgHYxG3M.js} +1 -1
- package/payload/server/public/assets/page-DgHYxG3M.js.br +0 -0
- package/payload/server/public/assets/page-DgHYxG3M.js.gz +0 -0
- package/payload/server/public/assets/{page-Cci_j_y7.js → page-qV1ypb6i.js} +5 -5
- package/payload/server/public/assets/page-qV1ypb6i.js.br +0 -0
- package/payload/server/public/assets/page-qV1ypb6i.js.gz +0 -0
- package/payload/server/public/assets/{public-BbJcQGsO.js → public-CNVEM-Bx.js} +1 -1
- package/payload/server/public/assets/public-CNVEM-Bx.js.br +0 -0
- package/payload/server/public/assets/public-CNVEM-Bx.js.gz +0 -0
- package/payload/server/public/assets/{rotate-ccw-jeSVwUAv.js → rotate-ccw-DQCaky8_.js} +1 -1
- package/payload/server/public/assets/rotate-ccw-DQCaky8_.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-DQCaky8_.js.gz +0 -0
- package/payload/server/public/assets/{routines-D3M1Wh3a.js → routines-DwK5FeLm.js} +1 -1
- package/payload/server/public/assets/routines-DwK5FeLm.js.br +0 -0
- package/payload/server/public/assets/routines-DwK5FeLm.js.gz +0 -0
- package/payload/server/public/assets/{skills-Bhej2ub1.js → skills-CosN3uA4.js} +1 -1
- package/payload/server/public/assets/skills-CosN3uA4.js.br +0 -0
- package/payload/server/public/assets/skills-CosN3uA4.js.gz +0 -0
- package/payload/server/public/assets/tasks-f0QikHmw.js +3 -0
- package/payload/server/public/assets/tasks-f0QikHmw.js.br +0 -0
- package/payload/server/public/assets/tasks-f0QikHmw.js.gz +0 -0
- package/payload/server/public/assets/{time-entry-format-r5UY9rjG.js → time-entry-format-DLTdS35_.js} +1 -1
- package/payload/server/public/assets/time-entry-format-DLTdS35_.js.br +0 -0
- package/payload/server/public/assets/time-entry-format-DLTdS35_.js.gz +0 -0
- package/payload/server/public/assets/{triangle-alert--PCKaewD.js → triangle-alert-CpwrbdYq.js} +1 -1
- package/payload/server/public/assets/triangle-alert-CpwrbdYq.js.br +3 -0
- package/payload/server/public/assets/triangle-alert-CpwrbdYq.js.gz +0 -0
- package/payload/server/public/assets/{useCopyFeedback-Dg5lNgqH.js → useCopyFeedback-D01gSp36.js} +1 -1
- package/payload/server/public/assets/useCopyFeedback-D01gSp36.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-D01gSp36.js.gz +0 -0
- package/payload/server/public/assets/useSubAccountSwitcher-CJzJ9xV3.css +1 -0
- package/payload/server/public/assets/useSubAccountSwitcher-CJzJ9xV3.css.br +0 -0
- package/payload/server/public/assets/useSubAccountSwitcher-CJzJ9xV3.css.gz +0 -0
- package/payload/server/public/assets/{useVoiceRecorder-BY6ZsGMH.js → useVoiceRecorder-DiPgyDUy.js} +1 -1
- package/payload/server/public/assets/useVoiceRecorder-DiPgyDUy.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-DiPgyDUy.js.gz +0 -0
- package/payload/server/public/assets/{wrench-Bw1FMolk.js → wrench-C5SJreEu.js} +1 -1
- package/payload/server/public/assets/wrench-C5SJreEu.js.br +1 -0
- package/payload/server/public/assets/wrench-C5SJreEu.js.gz +0 -0
- package/payload/server/public/brand-defaults.css +1 -1
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/calendar.html +7 -7
- package/payload/server/public/chat.html +13 -13
- package/payload/server/public/data.html +12 -12
- package/payload/server/public/graph.html +9 -9
- package/payload/server/public/index.html +15 -15
- package/payload/server/public/operator.html +14 -14
- package/payload/server/public/public.html +13 -13
- package/payload/server/public/routines.html +7 -7
- package/payload/server/public/skills.html +5 -5
- package/payload/server/public/tasks.html +6 -6
- package/payload/server/server.js +43 -5
- package/payload/server/public/assets/AdminLoginScreens-BgDjueVe.js.br +0 -0
- package/payload/server/public/assets/AdminLoginScreens-BgDjueVe.js.gz +0 -0
- package/payload/server/public/assets/AdminShell-YctTrR-D.js.br +0 -0
- package/payload/server/public/assets/AdminShell-YctTrR-D.js.gz +0 -0
- package/payload/server/public/assets/activity-DGQt5ys_.js.br +0 -0
- package/payload/server/public/assets/activity-DGQt5ys_.js.gz +0 -0
- package/payload/server/public/assets/admin-DnUxbB3P.js.br +0 -0
- package/payload/server/public/assets/admin-DnUxbB3P.js.gz +0 -0
- package/payload/server/public/assets/agents-Bc2LZjwC.js.br +0 -0
- package/payload/server/public/assets/agents-Bc2LZjwC.js.gz +0 -0
- package/payload/server/public/assets/browser-BtF7SzvG.js +0 -1
- package/payload/server/public/assets/browser-BtF7SzvG.js.br +0 -0
- package/payload/server/public/assets/browser-BtF7SzvG.js.gz +0 -0
- package/payload/server/public/assets/calendar-D25EhXbD.js.br +0 -0
- package/payload/server/public/assets/calendar-D25EhXbD.js.gz +0 -0
- package/payload/server/public/assets/chat-z4jsHFXg.js +0 -1
- package/payload/server/public/assets/chat-z4jsHFXg.js.br +0 -0
- package/payload/server/public/assets/chat-z4jsHFXg.js.gz +0 -0
- package/payload/server/public/assets/chevron-left-BD09SN6R.js +0 -1
- package/payload/server/public/assets/chevron-right-ChmWeo7T.js +0 -1
- package/payload/server/public/assets/chevron-right-ChmWeo7T.js.br +0 -0
- package/payload/server/public/assets/clock-Yqf7Ke7I.js +0 -1
- package/payload/server/public/assets/clock-Yqf7Ke7I.js.br +0 -0
- package/payload/server/public/assets/clock-Yqf7Ke7I.js.gz +0 -0
- package/payload/server/public/assets/data-RmnKj5nC.js +0 -1
- package/payload/server/public/assets/data-RmnKj5nC.js.br +0 -2
- package/payload/server/public/assets/data-RmnKj5nC.js.gz +0 -0
- package/payload/server/public/assets/file-download-CiGklOfA.js.br +0 -0
- package/payload/server/public/assets/file-download-CiGklOfA.js.gz +0 -0
- package/payload/server/public/assets/file-text-XjJPULAZ.js.br +0 -0
- package/payload/server/public/assets/file-text-XjJPULAZ.js.gz +0 -0
- package/payload/server/public/assets/graph-BjHJ0z_6.js.br +0 -0
- package/payload/server/public/assets/graph-BjHJ0z_6.js.gz +0 -0
- package/payload/server/public/assets/graph-labels-D-0u37KA.js.br +0 -0
- package/payload/server/public/assets/graph-labels-D-0u37KA.js.gz +0 -0
- package/payload/server/public/assets/maximize-2-BJ9S-nfS.js.br +0 -0
- package/payload/server/public/assets/maximize-2-BJ9S-nfS.js.gz +0 -0
- package/payload/server/public/assets/operator-Cay4rOOK.js.br +0 -0
- package/payload/server/public/assets/operator-Cay4rOOK.js.gz +0 -0
- package/payload/server/public/assets/page-Cci_j_y7.js.br +0 -0
- package/payload/server/public/assets/page-Cci_j_y7.js.gz +0 -0
- package/payload/server/public/assets/page-shuh4ES9.js.br +0 -0
- package/payload/server/public/assets/page-shuh4ES9.js.gz +0 -0
- package/payload/server/public/assets/public-BbJcQGsO.js.br +0 -0
- package/payload/server/public/assets/public-BbJcQGsO.js.gz +0 -0
- package/payload/server/public/assets/rotate-ccw-jeSVwUAv.js.br +0 -0
- package/payload/server/public/assets/rotate-ccw-jeSVwUAv.js.gz +0 -0
- package/payload/server/public/assets/routines-D3M1Wh3a.js.br +0 -0
- package/payload/server/public/assets/routines-D3M1Wh3a.js.gz +0 -0
- package/payload/server/public/assets/skills-Bhej2ub1.js.br +0 -0
- package/payload/server/public/assets/skills-Bhej2ub1.js.gz +0 -0
- package/payload/server/public/assets/tasks-qY-dtOI2.js +0 -1
- package/payload/server/public/assets/tasks-qY-dtOI2.js.br +0 -0
- package/payload/server/public/assets/tasks-qY-dtOI2.js.gz +0 -0
- package/payload/server/public/assets/time-entry-format-r5UY9rjG.js.br +0 -0
- package/payload/server/public/assets/time-entry-format-r5UY9rjG.js.gz +0 -0
- package/payload/server/public/assets/triangle-alert--PCKaewD.js.br +0 -2
- package/payload/server/public/assets/triangle-alert--PCKaewD.js.gz +0 -0
- package/payload/server/public/assets/useCopyFeedback-Dg5lNgqH.js.br +0 -0
- package/payload/server/public/assets/useCopyFeedback-Dg5lNgqH.js.gz +0 -0
- package/payload/server/public/assets/useSubAccountSwitcher-BYfe9vj8.css +0 -1
- package/payload/server/public/assets/useSubAccountSwitcher-BYfe9vj8.css.br +0 -0
- package/payload/server/public/assets/useSubAccountSwitcher-BYfe9vj8.css.gz +0 -0
- package/payload/server/public/assets/useVoiceRecorder-BY6ZsGMH.js.br +0 -0
- package/payload/server/public/assets/useVoiceRecorder-BY6ZsGMH.js.gz +0 -0
- package/payload/server/public/assets/wrench-Bw1FMolk.js.br +0 -0
- package/payload/server/public/assets/wrench-Bw1FMolk.js.gz +0 -0
- /package/payload/server/public/assets/{useSubAccountSwitcher-CnpeWIYq.js → useSubAccountSwitcher-BRHYXwGO.js} +0 -0
- /package/payload/server/public/assets/{useSubAccountSwitcher-CnpeWIYq.js.br → useSubAccountSwitcher-BRHYXwGO.js.br} +0 -0
- /package/payload/server/public/assets/{useSubAccountSwitcher-CnpeWIYq.js.gz → useSubAccountSwitcher-BRHYXwGO.js.gz} +0 -0
|
@@ -1,15 +1,59 @@
|
|
|
1
|
-
// Options-page glue. Reads existing values,
|
|
1
|
+
// Options-page glue. Reads existing values, requests browser access for the
|
|
2
|
+
// configured admin host, probes it, then saves.
|
|
3
|
+
//
|
|
4
|
+
// Task 2185 — the manifest's static host_permissions cover linkedin.com only,
|
|
5
|
+
// so a service-worker fetch to the admin host is an ordinary cross-origin
|
|
6
|
+
// request that Chrome preflights and the admin route never answers. The
|
|
7
|
+
// runtime grant requested here is what makes that fetch permission-exempt.
|
|
8
|
+
// Without it every capture dies in the browser and the server sees nothing.
|
|
2
9
|
|
|
3
10
|
const $host = document.getElementById('admin-host')
|
|
4
11
|
const $key = document.getElementById('session-key')
|
|
5
12
|
const $btn = document.getElementById('save')
|
|
6
13
|
const $status = document.getElementById('status')
|
|
7
14
|
|
|
15
|
+
const TAG = '[linkedin-ext-options]'
|
|
16
|
+
|
|
8
17
|
function setStatus(text, isError) {
|
|
9
18
|
$status.textContent = text
|
|
10
19
|
$status.classList.toggle('error', !!isError)
|
|
11
20
|
}
|
|
12
21
|
|
|
22
|
+
// Chrome match pattern covering every path on the admin host's origin.
|
|
23
|
+
function originPattern(adminHost) {
|
|
24
|
+
return new URL(adminHost).origin + '/*'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// What the operator reads when the probe fails. The reason tokens are for the
|
|
28
|
+
// console; this page says what actually went wrong in plain words.
|
|
29
|
+
const PROBE_COPY = {
|
|
30
|
+
unreachable: 'that host did not answer',
|
|
31
|
+
auth: 'that host rejected the session key',
|
|
32
|
+
server: 'that host answered with an unexpected status',
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Config-time probe. The body carries none of the five envelope fields, so
|
|
36
|
+
// the route answers 400 {error:'schema', reason:'envelope', missing:[all
|
|
37
|
+
// five]} — a signature no real capture can produce, because both content
|
|
38
|
+
// scripts always set all five. Nothing is dispatched and nothing is written.
|
|
39
|
+
async function probe(adminHost, sessionKey) {
|
|
40
|
+
let res
|
|
41
|
+
try {
|
|
42
|
+
res = await fetch(adminHost + '/api/admin/linkedin-ingest', {
|
|
43
|
+
method: 'POST',
|
|
44
|
+
headers: { 'content-type': 'application/json' },
|
|
45
|
+
body: JSON.stringify({ session_key: sessionKey }),
|
|
46
|
+
})
|
|
47
|
+
} catch (err) {
|
|
48
|
+
return { ok: false, reason: 'unreachable', detail: err && err.message ? err.message : String(err) }
|
|
49
|
+
}
|
|
50
|
+
if (res.status === 401) return { ok: false, reason: 'auth', detail: 'session-rejected' }
|
|
51
|
+
let body = null
|
|
52
|
+
try { body = await res.json() } catch { /* non-JSON body */ }
|
|
53
|
+
if (res.status === 400 && body && body.error === 'schema') return { ok: true }
|
|
54
|
+
return { ok: false, reason: 'server', detail: 'http-' + res.status }
|
|
55
|
+
}
|
|
56
|
+
|
|
13
57
|
async function load() {
|
|
14
58
|
const stored = await chrome.storage.local.get(['adminHost', 'sessionKey'])
|
|
15
59
|
if (typeof stored.adminHost === 'string') $host.value = stored.adminHost
|
|
@@ -17,13 +61,44 @@ async function load() {
|
|
|
17
61
|
}
|
|
18
62
|
|
|
19
63
|
async function save() {
|
|
20
|
-
const adminHost = $host.value.trim()
|
|
64
|
+
const adminHost = $host.value.trim().replace(/\/+$/, '')
|
|
21
65
|
const sessionKey = $key.value.trim()
|
|
22
66
|
if (!adminHost) return setStatus('Admin host is required.', true)
|
|
23
67
|
if (!/^https?:\/\//.test(adminHost)) return setStatus('Admin host must start with http(s)://.', true)
|
|
24
68
|
if (!sessionKey) return setStatus('Session key is required.', true)
|
|
69
|
+
|
|
70
|
+
let origin
|
|
71
|
+
try {
|
|
72
|
+
origin = originPattern(adminHost)
|
|
73
|
+
} catch {
|
|
74
|
+
return setStatus('Admin host is not a valid URL.', true)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// A rejected request() is not a refusal — it means Chrome would not even ask
|
|
78
|
+
// (a malformed match pattern, no user gesture). Left uncaught it aborts save()
|
|
79
|
+
// with no status at all, so the operator clicks Save and sees nothing happen.
|
|
80
|
+
let granted
|
|
81
|
+
try {
|
|
82
|
+
granted = await chrome.permissions.request({ origins: [origin] })
|
|
83
|
+
} catch (err) {
|
|
84
|
+
const detail = err && err.message ? err.message : String(err)
|
|
85
|
+
console.error(TAG + ' op=permission origin=' + origin + ' granted=error detail=' + detail)
|
|
86
|
+
return setStatus('Chrome refused to ask for access to ' + origin + ': ' + detail, true)
|
|
87
|
+
}
|
|
88
|
+
console.log(TAG + ' op=permission origin=' + origin + ' granted=' + granted)
|
|
89
|
+
if (!granted) {
|
|
90
|
+
return setStatus(
|
|
91
|
+
'Access to ' + origin + ' was declined, so nothing was saved. The pill cannot post without it.',
|
|
92
|
+
true,
|
|
93
|
+
)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const reachable = await probe(adminHost, sessionKey)
|
|
25
97
|
await chrome.storage.local.set({ adminHost: adminHost, sessionKey: sessionKey })
|
|
26
|
-
|
|
98
|
+
if (reachable.ok) {
|
|
99
|
+
return setStatus('Saved. The admin host is reachable and accepted the session key.', false)
|
|
100
|
+
}
|
|
101
|
+
setStatus('Saved, but ' + PROBE_COPY[reachable.reason] + ' (' + reachable.detail + ')', true)
|
|
27
102
|
}
|
|
28
103
|
|
|
29
104
|
$btn.addEventListener('click', save)
|
|
@@ -4075,6 +4075,214 @@ var clientIpMiddleware = async (c, next) => {
|
|
|
4075
4075
|
await next();
|
|
4076
4076
|
};
|
|
4077
4077
|
|
|
4078
|
+
// app/lib/cdp-screencast.ts
|
|
4079
|
+
var CDP_WS_PATH = "/cdp-screencast";
|
|
4080
|
+
var TARGET_ID_RE = /^[0-9A-Fa-f]{32}$/;
|
|
4081
|
+
function selectPageTargets(parsed) {
|
|
4082
|
+
if (!Array.isArray(parsed)) return [];
|
|
4083
|
+
const out = [];
|
|
4084
|
+
for (const raw2 of parsed) {
|
|
4085
|
+
if (raw2?.type !== "page") continue;
|
|
4086
|
+
const id = typeof raw2.id === "string" ? raw2.id : "";
|
|
4087
|
+
if (!TARGET_ID_RE.test(id)) continue;
|
|
4088
|
+
const url = typeof raw2.url === "string" ? raw2.url : "";
|
|
4089
|
+
const title = typeof raw2.title === "string" && raw2.title.length > 0 ? raw2.title : url;
|
|
4090
|
+
out.push({ id, title, url });
|
|
4091
|
+
}
|
|
4092
|
+
return out;
|
|
4093
|
+
}
|
|
4094
|
+
var CLIENT_SCREENCAST_OPS = [
|
|
4095
|
+
"request",
|
|
4096
|
+
"screencast-started",
|
|
4097
|
+
"start-failed",
|
|
4098
|
+
"send-failed",
|
|
4099
|
+
"frame",
|
|
4100
|
+
"input",
|
|
4101
|
+
"teardown"
|
|
4102
|
+
];
|
|
4103
|
+
function isClientScreencastOp(v) {
|
|
4104
|
+
return typeof v === "string" && CLIENT_SCREENCAST_OPS.includes(v);
|
|
4105
|
+
}
|
|
4106
|
+
|
|
4107
|
+
// app/lib/cdp-screencast-server.ts
|
|
4108
|
+
var HOP_BY_HOP = /* @__PURE__ */ new Set([
|
|
4109
|
+
"connection",
|
|
4110
|
+
"keep-alive",
|
|
4111
|
+
"proxy-authenticate",
|
|
4112
|
+
"proxy-authorization",
|
|
4113
|
+
"te",
|
|
4114
|
+
"trailer",
|
|
4115
|
+
"transfer-encoding",
|
|
4116
|
+
"upgrade"
|
|
4117
|
+
]);
|
|
4118
|
+
var DROP_UPSTREAM = /* @__PURE__ */ new Set(["origin", "cookie"]);
|
|
4119
|
+
function decideCdpUpgrade(input) {
|
|
4120
|
+
const corrId = newCorrId();
|
|
4121
|
+
const qsIndex = input.url.indexOf("?");
|
|
4122
|
+
const pathname = qsIndex === -1 ? input.url : input.url.slice(0, qsIndex);
|
|
4123
|
+
const query = qsIndex === -1 ? "" : input.url.slice(qsIndex + 1);
|
|
4124
|
+
const sid = sanitizeClientCorrId(parseQueryParam(query, "sid"));
|
|
4125
|
+
if (pathname !== CDP_WS_PATH) {
|
|
4126
|
+
return { allow: false, reason: "wrong-path", status: 0, sid, corrId };
|
|
4127
|
+
}
|
|
4128
|
+
const access = input.canAccess({
|
|
4129
|
+
host: input.host,
|
|
4130
|
+
remoteAddress: input.remoteAddress,
|
|
4131
|
+
xForwardedFor: input.xForwardedFor,
|
|
4132
|
+
cookieHeader: input.cookieHeader,
|
|
4133
|
+
isPublicHost: input.isPublicHost
|
|
4134
|
+
});
|
|
4135
|
+
if (!access.allow) {
|
|
4136
|
+
const publicHost = access.reason === "public-host";
|
|
4137
|
+
return {
|
|
4138
|
+
allow: false,
|
|
4139
|
+
reason: publicHost ? "public-host" : "unauthorized",
|
|
4140
|
+
status: publicHost ? 404 : 401,
|
|
4141
|
+
sid,
|
|
4142
|
+
corrId
|
|
4143
|
+
};
|
|
4144
|
+
}
|
|
4145
|
+
const originHost = parseOriginHost(input.origin);
|
|
4146
|
+
if (!originHost) {
|
|
4147
|
+
return { allow: false, reason: "origin-missing-or-invalid", status: 403, sid, corrId };
|
|
4148
|
+
}
|
|
4149
|
+
if (originHost !== input.host) {
|
|
4150
|
+
return { allow: false, reason: "origin-mismatch", status: 403, sid, corrId };
|
|
4151
|
+
}
|
|
4152
|
+
if (input.isPublicHost(originHost)) {
|
|
4153
|
+
return { allow: false, reason: "origin-public-host", status: 403, sid, corrId };
|
|
4154
|
+
}
|
|
4155
|
+
if (input.isOperatorHost(originHost)) {
|
|
4156
|
+
return { allow: false, reason: "origin-operator-host", status: 403, sid, corrId };
|
|
4157
|
+
}
|
|
4158
|
+
const targetId = parseQueryParam(query, "targetId");
|
|
4159
|
+
if (!targetId || !TARGET_ID_RE.test(targetId)) {
|
|
4160
|
+
return { allow: false, reason: "target-id-invalid", status: 400, sid, corrId };
|
|
4161
|
+
}
|
|
4162
|
+
return { allow: true, targetId, sid, corrId };
|
|
4163
|
+
}
|
|
4164
|
+
function buildCdpUpstreamRequest(input) {
|
|
4165
|
+
const lines = [];
|
|
4166
|
+
lines.push(`${input.method} /devtools/page/${input.targetId} HTTP/${input.httpVersion}`);
|
|
4167
|
+
lines.push(`host: ${input.upstreamHost}:${input.upstreamPort}`);
|
|
4168
|
+
for (const [rawName, value] of Object.entries(input.headers)) {
|
|
4169
|
+
const name = rawName.toLowerCase();
|
|
4170
|
+
if (name === "host") continue;
|
|
4171
|
+
if (HOP_BY_HOP.has(name)) continue;
|
|
4172
|
+
if (DROP_UPSTREAM.has(name)) continue;
|
|
4173
|
+
if (value == null) continue;
|
|
4174
|
+
if (Array.isArray(value)) {
|
|
4175
|
+
for (const v of value) lines.push(`${name}: ${v}`);
|
|
4176
|
+
} else {
|
|
4177
|
+
lines.push(`${name}: ${value}`);
|
|
4178
|
+
}
|
|
4179
|
+
}
|
|
4180
|
+
const upgrade = headerString(input.headers.upgrade);
|
|
4181
|
+
const connection = headerString(input.headers.connection);
|
|
4182
|
+
if (upgrade) lines.push(`upgrade: ${upgrade}`);
|
|
4183
|
+
if (connection) lines.push(`connection: ${connection}`);
|
|
4184
|
+
return lines.join("\r\n") + "\r\n\r\n";
|
|
4185
|
+
}
|
|
4186
|
+
async function fetchPageTargets(deps) {
|
|
4187
|
+
if (deps.platform !== "linux") {
|
|
4188
|
+
return {
|
|
4189
|
+
ok: false,
|
|
4190
|
+
status: 501,
|
|
4191
|
+
error: "The device browser is available on the Linux display stack only."
|
|
4192
|
+
};
|
|
4193
|
+
}
|
|
4194
|
+
let res;
|
|
4195
|
+
try {
|
|
4196
|
+
res = await deps.fetchImpl(`http://127.0.0.1:${deps.cdpPort}/json/list`, {
|
|
4197
|
+
signal: AbortSignal.timeout(5e3)
|
|
4198
|
+
});
|
|
4199
|
+
} catch {
|
|
4200
|
+
return { ok: false, status: 502, error: "Chromium is not reachable on this device." };
|
|
4201
|
+
}
|
|
4202
|
+
if (!res.ok) {
|
|
4203
|
+
return { ok: false, status: 502, error: `CDP /json/list returned ${res.status}` };
|
|
4204
|
+
}
|
|
4205
|
+
let parsed;
|
|
4206
|
+
try {
|
|
4207
|
+
parsed = await res.json();
|
|
4208
|
+
} catch {
|
|
4209
|
+
return { ok: false, status: 502, error: "CDP /json/list response was not JSON." };
|
|
4210
|
+
}
|
|
4211
|
+
return { ok: true, targets: selectPageTargets(parsed) };
|
|
4212
|
+
}
|
|
4213
|
+
var EVENT_DETAIL_KEYS = [
|
|
4214
|
+
"seq",
|
|
4215
|
+
"kind",
|
|
4216
|
+
"count",
|
|
4217
|
+
"format",
|
|
4218
|
+
"everyNthFrame",
|
|
4219
|
+
"stopSent",
|
|
4220
|
+
"ackMs",
|
|
4221
|
+
"err",
|
|
4222
|
+
"method"
|
|
4223
|
+
];
|
|
4224
|
+
var DETAIL_MAX_LEN = 128;
|
|
4225
|
+
function parseScreencastEvent(body) {
|
|
4226
|
+
if (typeof body !== "object" || body === null) return { ok: false };
|
|
4227
|
+
const raw2 = body;
|
|
4228
|
+
if (!isClientScreencastOp(raw2.op)) return { ok: false };
|
|
4229
|
+
const detail = {
|
|
4230
|
+
sid: sanitizeClientCorrId(typeof raw2.sid === "string" ? raw2.sid : null)
|
|
4231
|
+
};
|
|
4232
|
+
for (const key of EVENT_DETAIL_KEYS) {
|
|
4233
|
+
const v = raw2[key];
|
|
4234
|
+
if (typeof v === "number" || typeof v === "boolean") {
|
|
4235
|
+
detail[key] = v;
|
|
4236
|
+
} else if (typeof v === "string") {
|
|
4237
|
+
detail[key] = sanitizeLogValue(v);
|
|
4238
|
+
}
|
|
4239
|
+
}
|
|
4240
|
+
return { ok: true, op: raw2.op, detail };
|
|
4241
|
+
}
|
|
4242
|
+
function sanitizeLogValue(v) {
|
|
4243
|
+
return v.replace(/[\r\n]+/g, " ").slice(0, DETAIL_MAX_LEN);
|
|
4244
|
+
}
|
|
4245
|
+
function renderFields(fields) {
|
|
4246
|
+
return Object.entries(fields).filter(([, v]) => v !== void 0).map(([k, v]) => {
|
|
4247
|
+
const s = v === null ? "null" : String(v);
|
|
4248
|
+
return `${k}=${sanitizeLogValue(s)}`;
|
|
4249
|
+
}).join(" ");
|
|
4250
|
+
}
|
|
4251
|
+
function screencastLog(op, fields = {}) {
|
|
4252
|
+
const rendered = renderFields(fields);
|
|
4253
|
+
console.error(`[browser/screencast] op=${sanitizeLogValue(op)}${rendered ? " " + rendered : ""}`);
|
|
4254
|
+
}
|
|
4255
|
+
function cdpWsCensusLog(fields) {
|
|
4256
|
+
console.error(`[cdp-ws-census] ${renderFields(fields)}`);
|
|
4257
|
+
}
|
|
4258
|
+
function parseQueryParam(query, key) {
|
|
4259
|
+
if (!query) return null;
|
|
4260
|
+
for (const pair of query.split("&")) {
|
|
4261
|
+
const eq = pair.indexOf("=");
|
|
4262
|
+
const k = eq === -1 ? pair : pair.slice(0, eq);
|
|
4263
|
+
if (k !== key) continue;
|
|
4264
|
+
const v = eq === -1 ? "" : pair.slice(eq + 1);
|
|
4265
|
+
try {
|
|
4266
|
+
return decodeURIComponent(v);
|
|
4267
|
+
} catch {
|
|
4268
|
+
return null;
|
|
4269
|
+
}
|
|
4270
|
+
}
|
|
4271
|
+
return null;
|
|
4272
|
+
}
|
|
4273
|
+
function headerString(value) {
|
|
4274
|
+
if (value == null) return void 0;
|
|
4275
|
+
return Array.isArray(value) ? value[0] : value;
|
|
4276
|
+
}
|
|
4277
|
+
function parseOriginHost(origin) {
|
|
4278
|
+
if (!origin) return null;
|
|
4279
|
+
try {
|
|
4280
|
+
return new URL(origin).hostname;
|
|
4281
|
+
} catch {
|
|
4282
|
+
return null;
|
|
4283
|
+
}
|
|
4284
|
+
}
|
|
4285
|
+
|
|
4078
4286
|
export {
|
|
4079
4287
|
HTTPException,
|
|
4080
4288
|
HtmlEscapedCallbackPhase,
|
|
@@ -4137,5 +4345,12 @@ export {
|
|
|
4137
4345
|
requireAdminSession,
|
|
4138
4346
|
tryCookieBridgeForConversation,
|
|
4139
4347
|
requireAdminCookie,
|
|
4140
|
-
clientIpMiddleware
|
|
4348
|
+
clientIpMiddleware,
|
|
4349
|
+
CDP_WS_PATH,
|
|
4350
|
+
decideCdpUpgrade,
|
|
4351
|
+
buildCdpUpstreamRequest,
|
|
4352
|
+
fetchPageTargets,
|
|
4353
|
+
parseScreencastEvent,
|
|
4354
|
+
screencastLog,
|
|
4355
|
+
cdpWsCensusLog
|
|
4141
4356
|
};
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { createRequire as __createRequire } from 'node:module'; const require = __createRequire(import.meta.url);
|
|
2
2
|
import {
|
|
3
|
+
CDP_WS_PATH,
|
|
3
4
|
Hono,
|
|
5
|
+
buildCdpUpstreamRequest,
|
|
4
6
|
canAccessAdmin,
|
|
7
|
+
cdpWsCensusLog,
|
|
5
8
|
clientIpMiddleware,
|
|
9
|
+
decideCdpUpgrade,
|
|
6
10
|
describeRemoteSession,
|
|
7
11
|
getOperatorDomains,
|
|
8
12
|
getRequestListener,
|
|
@@ -12,10 +16,12 @@ import {
|
|
|
12
16
|
requireAdminCookie,
|
|
13
17
|
requirePortEnv,
|
|
14
18
|
sanitizeClientCorrId,
|
|
19
|
+
screencastLog,
|
|
15
20
|
vncLog,
|
|
16
21
|
websockifyLog
|
|
17
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-KY3BBT67.js";
|
|
18
23
|
import {
|
|
24
|
+
CDP_PORT,
|
|
19
25
|
LOG_DIR,
|
|
20
26
|
WEBSOCKIFY_PORT
|
|
21
27
|
} from "./chunk-XCR5D2G3.js";
|
|
@@ -23,7 +29,7 @@ import "./chunk-PFF6I7KP.js";
|
|
|
23
29
|
|
|
24
30
|
// server/edge.ts
|
|
25
31
|
import { createServer, request as httpRequest } from "http";
|
|
26
|
-
import { createConnection as
|
|
32
|
+
import { createConnection as createConnection3 } from "net";
|
|
27
33
|
import { readFileSync as readFileSync4, existsSync as existsSync4, watchFile } from "fs";
|
|
28
34
|
import { homedir } from "os";
|
|
29
35
|
import { join as join4 } from "path";
|
|
@@ -315,10 +321,10 @@ function parseOriginHost(origin) {
|
|
|
315
321
|
return null;
|
|
316
322
|
}
|
|
317
323
|
}
|
|
318
|
-
function writeStatusAndDestroy(socket, status,
|
|
324
|
+
function writeStatusAndDestroy(socket, status, statusText2) {
|
|
319
325
|
try {
|
|
320
326
|
socket.write(
|
|
321
|
-
`HTTP/1.1 ${status} ${
|
|
327
|
+
`HTTP/1.1 ${status} ${statusText2}\r
|
|
322
328
|
Connection: close\r
|
|
323
329
|
Content-Length: 0\r
|
|
324
330
|
\r
|
|
@@ -329,6 +335,215 @@ Content-Length: 0\r
|
|
|
329
335
|
socket.destroy();
|
|
330
336
|
}
|
|
331
337
|
|
|
338
|
+
// server/cdp-ws-proxy.ts
|
|
339
|
+
import { createConnection as createConnection2 } from "net";
|
|
340
|
+
var UPSTREAM_TIMEOUT_MS2 = 5e3;
|
|
341
|
+
var REAP_INTERVAL_MS = 6e4;
|
|
342
|
+
var liveSockets = /* @__PURE__ */ new Set();
|
|
343
|
+
var reaper = null;
|
|
344
|
+
function cdpSessionCount() {
|
|
345
|
+
const sids = /* @__PURE__ */ new Set();
|
|
346
|
+
for (const e of liveSockets) sids.add(e.sid);
|
|
347
|
+
return sids.size;
|
|
348
|
+
}
|
|
349
|
+
function ensureReaperArmed() {
|
|
350
|
+
if (reaper) return;
|
|
351
|
+
reaper = setInterval(sweepOrphans, REAP_INTERVAL_MS);
|
|
352
|
+
if (typeof reaper.unref === "function") reaper.unref();
|
|
353
|
+
}
|
|
354
|
+
function disarmReaperIfIdle() {
|
|
355
|
+
if (liveSockets.size > 0 || !reaper) return;
|
|
356
|
+
clearInterval(reaper);
|
|
357
|
+
reaper = null;
|
|
358
|
+
}
|
|
359
|
+
function sweepOrphans() {
|
|
360
|
+
reapOrphanedCdpSockets();
|
|
361
|
+
disarmReaperIfIdle();
|
|
362
|
+
}
|
|
363
|
+
function registerCdpSocket(entry) {
|
|
364
|
+
liveSockets.add(entry);
|
|
365
|
+
ensureReaperArmed();
|
|
366
|
+
cdpWsCensusLog({ liveSockets: liveSockets.size, sessions: cdpSessionCount() });
|
|
367
|
+
}
|
|
368
|
+
function unregisterCdpSocket(entry) {
|
|
369
|
+
if (!liveSockets.delete(entry)) return;
|
|
370
|
+
disarmReaperIfIdle();
|
|
371
|
+
cdpWsCensusLog({ liveSockets: liveSockets.size, sessions: cdpSessionCount() });
|
|
372
|
+
}
|
|
373
|
+
function reapOrphanedCdpSockets() {
|
|
374
|
+
let reaped = 0;
|
|
375
|
+
for (const entry of [...liveSockets]) {
|
|
376
|
+
if (!entry.client.destroyed) continue;
|
|
377
|
+
if (!entry.upstream.destroyed) {
|
|
378
|
+
try {
|
|
379
|
+
entry.upstream.destroy();
|
|
380
|
+
} catch {
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
liveSockets.delete(entry);
|
|
384
|
+
reaped += 1;
|
|
385
|
+
}
|
|
386
|
+
if (reaped > 0) {
|
|
387
|
+
screencastLog("orphan-reap", { closed: reaped, liveSockets: liveSockets.size });
|
|
388
|
+
cdpWsCensusLog({ liveSockets: liveSockets.size, sessions: cdpSessionCount() });
|
|
389
|
+
}
|
|
390
|
+
return reaped;
|
|
391
|
+
}
|
|
392
|
+
function attachCdpWsProxy(server2, opts) {
|
|
393
|
+
const upstreamHost = opts.upstreamHost ?? "127.0.0.1";
|
|
394
|
+
const upstreamPort = opts.upstreamPort ?? CDP_PORT;
|
|
395
|
+
const isOperatorHost2 = opts.isOperatorHost ?? (() => false);
|
|
396
|
+
server2.on("upgrade", (req, clientSocket, head) => {
|
|
397
|
+
try {
|
|
398
|
+
handleCdpUpgrade(req, clientSocket, head, {
|
|
399
|
+
isPublicHost: opts.isPublicHost,
|
|
400
|
+
isOperatorHost: isOperatorHost2,
|
|
401
|
+
upstreamHost,
|
|
402
|
+
upstreamPort
|
|
403
|
+
});
|
|
404
|
+
} catch (err) {
|
|
405
|
+
screencastLog("gate", { decision: "reject-handler-exception", err: err.message });
|
|
406
|
+
clientSocket.destroy();
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
function handleCdpUpgrade(req, clientSocket, head, opts) {
|
|
411
|
+
const host = (req.headers.host ?? "").split(":")[0];
|
|
412
|
+
const decision = decideCdpUpgrade({
|
|
413
|
+
url: req.url ?? "",
|
|
414
|
+
host,
|
|
415
|
+
origin: headerString2(req.headers.origin),
|
|
416
|
+
cookieHeader: headerString2(req.headers.cookie),
|
|
417
|
+
remoteAddress: req.socket.remoteAddress,
|
|
418
|
+
xForwardedFor: headerString2(req.headers["x-forwarded-for"]),
|
|
419
|
+
isPublicHost: opts.isPublicHost,
|
|
420
|
+
isOperatorHost: opts.isOperatorHost,
|
|
421
|
+
canAccess: canAccessAdmin
|
|
422
|
+
});
|
|
423
|
+
if (!decision.allow && decision.reason === "wrong-path") return;
|
|
424
|
+
if (!decision.allow) {
|
|
425
|
+
screencastLog("gate", {
|
|
426
|
+
sid: decision.sid,
|
|
427
|
+
corrId: decision.corrId,
|
|
428
|
+
decision: `reject-${decision.reason}`,
|
|
429
|
+
host,
|
|
430
|
+
ip: req.socket.remoteAddress
|
|
431
|
+
});
|
|
432
|
+
writeStatusAndDestroy2(clientSocket, decision.status, statusText(decision.status));
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
const sid = decision.sid ?? decision.corrId;
|
|
436
|
+
screencastLog("gate", {
|
|
437
|
+
sid,
|
|
438
|
+
corrId: decision.corrId,
|
|
439
|
+
decision: "allow",
|
|
440
|
+
host,
|
|
441
|
+
cdpPort: opts.upstreamPort
|
|
442
|
+
});
|
|
443
|
+
const upstream = createConnection2({ host: opts.upstreamHost, port: opts.upstreamPort });
|
|
444
|
+
upstream.setTimeout(UPSTREAM_TIMEOUT_MS2);
|
|
445
|
+
const entry = {
|
|
446
|
+
sid,
|
|
447
|
+
client: clientSocket,
|
|
448
|
+
upstream
|
|
449
|
+
};
|
|
450
|
+
let bytesClientToUpstream = 0;
|
|
451
|
+
let bytesUpstreamToClient = 0;
|
|
452
|
+
let closedBy = null;
|
|
453
|
+
let proxyOpened = false;
|
|
454
|
+
const openedAt = Date.now();
|
|
455
|
+
const finish = (side, reason) => {
|
|
456
|
+
if (closedBy) return;
|
|
457
|
+
closedBy = side;
|
|
458
|
+
if (proxyOpened) {
|
|
459
|
+
unregisterCdpSocket(entry);
|
|
460
|
+
screencastLog("socket-closed", {
|
|
461
|
+
sid,
|
|
462
|
+
closedBy: side,
|
|
463
|
+
reason,
|
|
464
|
+
clientBytes: bytesClientToUpstream,
|
|
465
|
+
upstreamBytes: bytesUpstreamToClient,
|
|
466
|
+
durationMs: Date.now() - openedAt,
|
|
467
|
+
liveSockets: liveSockets.size
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
clientSocket.destroy();
|
|
471
|
+
upstream.destroy();
|
|
472
|
+
};
|
|
473
|
+
upstream.once("connect", () => {
|
|
474
|
+
upstream.setTimeout(0);
|
|
475
|
+
proxyOpened = true;
|
|
476
|
+
registerCdpSocket(entry);
|
|
477
|
+
screencastLog("cdp-connected", {
|
|
478
|
+
sid,
|
|
479
|
+
wsTarget: `/devtools/page/${decision.targetId}`,
|
|
480
|
+
liveSockets: liveSockets.size
|
|
481
|
+
});
|
|
482
|
+
upstream.write(
|
|
483
|
+
buildCdpUpstreamRequest({
|
|
484
|
+
method: req.method ?? "GET",
|
|
485
|
+
httpVersion: req.httpVersion,
|
|
486
|
+
headers: req.headers,
|
|
487
|
+
targetId: decision.targetId,
|
|
488
|
+
upstreamHost: opts.upstreamHost,
|
|
489
|
+
upstreamPort: opts.upstreamPort
|
|
490
|
+
})
|
|
491
|
+
);
|
|
492
|
+
if (head && head.length > 0) upstream.write(head);
|
|
493
|
+
clientSocket.on("data", (chunk) => {
|
|
494
|
+
bytesClientToUpstream += chunk.length;
|
|
495
|
+
});
|
|
496
|
+
upstream.on("data", (chunk) => {
|
|
497
|
+
bytesUpstreamToClient += chunk.length;
|
|
498
|
+
});
|
|
499
|
+
clientSocket.pipe(upstream);
|
|
500
|
+
upstream.pipe(clientSocket);
|
|
501
|
+
clientSocket.once("close", (hadError) => finish("client", hadError ? "error" : "normal"));
|
|
502
|
+
upstream.once("close", (hadError) => finish("upstream", hadError ? "error" : "normal"));
|
|
503
|
+
clientSocket.once("error", (err) => {
|
|
504
|
+
screencastLog("socket-error", { sid, side: "client", err: err.message });
|
|
505
|
+
finish("client", "error");
|
|
506
|
+
});
|
|
507
|
+
upstream.once("error", (err) => {
|
|
508
|
+
screencastLog("socket-error", { sid, side: "upstream", err: err.message });
|
|
509
|
+
finish("upstream", "error");
|
|
510
|
+
});
|
|
511
|
+
});
|
|
512
|
+
upstream.once("timeout", () => {
|
|
513
|
+
if (proxyOpened) return;
|
|
514
|
+
screencastLog("cdp-connect-failed", { sid, err: "timeout", timeoutMs: UPSTREAM_TIMEOUT_MS2 });
|
|
515
|
+
writeStatusAndDestroy2(clientSocket, 504, "Gateway Timeout");
|
|
516
|
+
upstream.destroy();
|
|
517
|
+
});
|
|
518
|
+
upstream.once("error", (err) => {
|
|
519
|
+
if (proxyOpened) return;
|
|
520
|
+
screencastLog("cdp-connect-failed", { sid, err: err.message });
|
|
521
|
+
writeStatusAndDestroy2(clientSocket, 502, "Bad Gateway");
|
|
522
|
+
upstream.destroy();
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
function headerString2(value) {
|
|
526
|
+
if (value == null) return void 0;
|
|
527
|
+
return Array.isArray(value) ? value[0] : value;
|
|
528
|
+
}
|
|
529
|
+
function statusText(status) {
|
|
530
|
+
if (status === 400) return "Bad Request";
|
|
531
|
+
if (status === 401) return "Unauthorized";
|
|
532
|
+
if (status === 404) return "Not Found";
|
|
533
|
+
return "Forbidden";
|
|
534
|
+
}
|
|
535
|
+
function writeStatusAndDestroy2(socket, status, text) {
|
|
536
|
+
try {
|
|
537
|
+
socket.write(`HTTP/1.1 ${status} ${text}\r
|
|
538
|
+
Connection: close\r
|
|
539
|
+
Content-Length: 0\r
|
|
540
|
+
\r
|
|
541
|
+
`);
|
|
542
|
+
} catch {
|
|
543
|
+
}
|
|
544
|
+
socket.destroy();
|
|
545
|
+
}
|
|
546
|
+
|
|
332
547
|
// server/routes/admin/version.ts
|
|
333
548
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
334
549
|
import { resolve, join as join2 } from "path";
|
|
@@ -764,7 +979,7 @@ function forwardHttp(clientReq, clientRes) {
|
|
|
764
979
|
clientReq.pipe(upstream);
|
|
765
980
|
}
|
|
766
981
|
function forwardUpgrade(req, clientSocket, head) {
|
|
767
|
-
const upstream =
|
|
982
|
+
const upstream = createConnection3({ host: UPSTREAM_HOST, port: UPSTREAM_PORT });
|
|
768
983
|
upstream.setTimeout(5e3);
|
|
769
984
|
upstream.once("connect", () => {
|
|
770
985
|
upstream.setTimeout(0);
|
|
@@ -838,16 +1053,21 @@ attachVncWsProxy(server, {
|
|
|
838
1053
|
upstreamPort: WEBSOCKIFY_PORT2,
|
|
839
1054
|
brand: BRAND.productName
|
|
840
1055
|
});
|
|
1056
|
+
attachCdpWsProxy(server, {
|
|
1057
|
+
isPublicHost,
|
|
1058
|
+
isOperatorHost: (h) => isOperatorHost(h, getOperatorDomains())
|
|
1059
|
+
});
|
|
841
1060
|
server.on("upgrade", (req, socket, head) => {
|
|
842
1061
|
const url = req.url ?? "";
|
|
843
1062
|
const qsIndex = url.indexOf("?");
|
|
844
1063
|
const pathname = qsIndex === -1 ? url : url.slice(0, qsIndex);
|
|
845
|
-
if (pathname === "/websockify") return;
|
|
1064
|
+
if (pathname === "/websockify" || pathname === CDP_WS_PATH) return;
|
|
846
1065
|
forwardUpgrade(req, socket, head);
|
|
847
1066
|
});
|
|
848
1067
|
server.listen(EDGE_PORT, EDGE_HOSTNAME, () => {
|
|
849
1068
|
console.log(`[edge] listening on http://${EDGE_HOSTNAME}:${EDGE_PORT}`);
|
|
850
1069
|
console.log(`[edge] brand=${BRAND.productName} holding-logo=${BRAND.logoDataUri ? "inlined" : "missing"} assets-dir=${BRAND_ASSETS_DIR || "(none)"}`);
|
|
851
1070
|
console.log(`[edge] /websockify \u2192 ${WEBSOCKIFY_HOST}:${WEBSOCKIFY_PORT2}`);
|
|
1071
|
+
console.log(`[edge] ${CDP_WS_PATH} \u2192 127.0.0.1:${CDP_PORT} (screencast)`);
|
|
852
1072
|
console.log(`[edge] everything else \u2192 ${UPSTREAM_HOST}:${UPSTREAM_PORT}`);
|
|
853
1073
|
});
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Activity — Maxy</title>
|
|
7
7
|
<link rel="icon" href="/favicon.ico">
|
|
8
|
-
<script type="module" crossorigin src="/assets/activity-
|
|
8
|
+
<script type="module" crossorigin src="/assets/activity-aVvbaVd4.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/chunk-CltuBf4Z.js">
|
|
10
|
-
<link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-
|
|
11
|
-
<link rel="modulepreload" crossorigin href="/assets/AdminShell-
|
|
12
|
-
<link rel="modulepreload" crossorigin href="/assets/triangle-alert
|
|
13
|
-
<link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-
|
|
10
|
+
<link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-BRHYXwGO.js">
|
|
11
|
+
<link rel="modulepreload" crossorigin href="/assets/AdminShell-MM3_yp3N.js">
|
|
12
|
+
<link rel="modulepreload" crossorigin href="/assets/triangle-alert-CpwrbdYq.js">
|
|
13
|
+
<link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-CJzJ9xV3.css">
|
|
14
14
|
<link rel="stylesheet" href="/brand-defaults.css">
|
|
15
15
|
</head>
|
|
16
16
|
<body>
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Agents — Maxy</title>
|
|
7
7
|
<link rel="icon" href="/favicon.ico">
|
|
8
|
-
<script type="module" crossorigin src="/assets/agents-
|
|
8
|
+
<script type="module" crossorigin src="/assets/agents-CrpVTPRG.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/assets/chunk-CltuBf4Z.js">
|
|
10
|
-
<link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-
|
|
11
|
-
<link rel="modulepreload" crossorigin href="/assets/AdminShell-
|
|
12
|
-
<link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-
|
|
10
|
+
<link rel="modulepreload" crossorigin href="/assets/useSubAccountSwitcher-BRHYXwGO.js">
|
|
11
|
+
<link rel="modulepreload" crossorigin href="/assets/AdminShell-MM3_yp3N.js">
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/assets/useSubAccountSwitcher-CJzJ9xV3.css">
|
|
13
13
|
<link rel="stylesheet" href="/brand-defaults.css">
|
|
14
14
|
</head>
|
|
15
15
|
<body>
|