Skip to content

Commit 91479e6

Browse files
authored
feat(extension): open typed sim/ links through the Sim link resolver (#9486)
Typing sim/<name> in Chrome opens the organization's Sim link: one static declarativeNetRequest rule rewrites top-level navigations to http(s)://sim/* to <Sim origin>/sim/*, keeping the path and query. Adds declarativeNetRequestWithHostAccess and http(s)://sim/* host access used only by that rule.
1 parent 00e25a4 commit 91479e6

4 files changed

Lines changed: 41 additions & 4 deletions

File tree

‎apps/extension/DESIGN.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ other workspace resources or browser-control tools.
5555

5656
- Required browser capabilities: side panel, scripting, active tab, context menus,
5757
and short-lived session storage for selection handoff. Required host access is
58-
limited to the configured Sim origin.
58+
limited to the configured Sim origin and to `http(s)://sim/*`, which exists only so
59+
one static redirect rule can send a typed `sim/<name>` to the Sim link resolver.
5960
- Other HTTP(S) origins are optional grants requested for the current site from a
6061
user gesture. Each grant can be revoked. Keeping the panel open is not a grant
6162
to read every subsequently selected tab.

‎apps/extension/README.md‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ SIM_EXTENSION_DEV=1 SIM_EXTENSION_ORIGIN=http://localhost:3000 bun run --cwd app
2525

2626
## Data and permissions
2727

28-
- Required capabilities: `activeTab`, `scripting`, `sidePanel`, `storage`, `contextMenus`, and access to the configured Sim origin.
28+
- Required capabilities: `activeTab`, `scripting`, `sidePanel`, `storage`, `contextMenus`, `declarativeNetRequestWithHostAccess`, and access to the configured Sim origin and to `http(s)://sim/*`.
29+
- Typing `sim/<name>` in the address bar opens the organization's [Sim link](https://docs.sim.ai/search/sim-links). A single static redirect rule rewrites top-level navigations to `http(s)://sim/*` to `<Sim origin>/sim/*` with the path and query unchanged. The `sim` host permission exists only for that rule: every navigation to that host is redirected before it loads, and no other request is matched or observed. An organization that already serves an intranet host named `sim` should not install this build, since its links would be redirected to Sim.
2930
- Optional HTTP/HTTPS site access is requested only by a menu action naming that site. Chrome's `activeTab` access is temporary and does not follow arbitrary new sites.
3031
- Page capture runs on demand in Chrome's isolated world. It excludes editable fields, inputs, hidden elements, scripts, and embedded documents. It reads only the top frame. PDF viewers and canvas documents may have no accessible text.
3132
- Extraction stops at 50,000 text characters, 150,000 serialized UTF-8 bytes, 15,000 visited nodes, or 150ms. The composer exposes truncation.

‎apps/extension/scripts/build.ts‎

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,19 @@ for (const [size, file] of [
8888
] as const) {
8989
await cp(resolve(root, '../sim/public/favicon', file), resolve(dist, `icon-${size}.png`))
9090
}
91+
/**
92+
* Chrome navigates a typed `sim/<name>` to `http://sim/<name>`; this rewrites it to the Sim link
93+
* resolver on the configured origin, keeping the rest of the path and query verbatim.
94+
*/
95+
const simLinkRules = [
96+
{
97+
id: 1,
98+
priority: 1,
99+
action: { type: 'redirect', redirect: { regexSubstitution: `${origin.origin}/sim/\\1` } },
100+
condition: { regexFilter: '^https?://sim/(.*)$', resourceTypes: ['main_frame'] },
101+
},
102+
]
103+
await writeFile(resolve(dist, 'sim-links.json'), JSON.stringify(simLinkRules, null, 2))
91104
await writeFile(
92105
resolve(dist, 'manifest.json'),
93106
JSON.stringify(
@@ -98,8 +111,18 @@ await writeFile(
98111
description:
99112
'Ask Sim about the page you are reading, with your existing Sim conversations and tools.',
100113
minimum_chrome_version: '120',
101-
permissions: ['activeTab', 'scripting', 'sidePanel', 'storage', 'contextMenus'],
102-
host_permissions: [`${origin.origin}/*`],
114+
permissions: [
115+
'activeTab',
116+
'scripting',
117+
'sidePanel',
118+
'storage',
119+
'contextMenus',
120+
'declarativeNetRequestWithHostAccess',
121+
],
122+
host_permissions: [`${origin.origin}/*`, 'http://sim/*', 'https://sim/*'],
123+
declarative_net_request: {
124+
rule_resources: [{ id: 'sim_links', enabled: true, path: 'sim-links.json' }],
125+
},
103126
optional_host_permissions: ['https://*/*', 'http://*/*'],
104127
background: { service_worker: 'background.js' },
105128
side_panel: { default_path: 'sidepanel.html' },

‎apps/extension/scripts/test-e2e.ts‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,18 @@ try {
220220
await app.waitForFunction((id) => document.body.dataset.barrierId === id, barrierId)
221221
}
222222

223+
await check(
224+
'A typed sim/ link opens the Sim link resolver on the configured origin',
225+
async () => {
226+
const tab = await page.context().newPage()
227+
for (const path of ['handbook', 'jira/123?view=board']) {
228+
await tab.goto(`http://sim/${path}`)
229+
assert(tab.url() === `${origin}/sim/${path}`, `sim/${path} reached ${tab.url()}`)
230+
}
231+
await tab.close()
232+
}
233+
)
234+
223235
await check('Capture stays local until the trusted hosted frame is ready', async () => {
224236
await capture()
225237
await panel.getByRole('status').filter({ hasText: 'Waiting for Sim' }).waitFor()

0 commit comments

Comments
 (0)