Skip to content

Commit 57f5b29

Browse files
committed
improvement(links): make go/ and sim/ work on install with no setup
Chrome treats go/x as a search until it has seen the host. It counts a visit to an unfamiliar single-label host as typed, so the extension now visits both hosts once on install, in background tabs that close themselves. That removes the Browser shortcuts modal and its Enable buttons, and the Links header now just links to the store. Drop the managed bookmarks export with it. The /sim-links/<org>/<name> route stays so bookmarks already distributed keep opening.
1 parent 6eaca1c commit 57f5b29

21 files changed

Lines changed: 108 additions & 330 deletions

File tree

‎apps/docs/content/docs/browser-extension/index.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Change the binding in Chrome’s **Extensions → Keyboard shortcuts**. If Chrom
3333

3434
## Open team links
3535

36-
Open **Links → Browser shortcuts** in Sim and select **Enable go/ shortcuts**. Then type a shortcut such as `go/handbook` in Chrome’s address bar. You can enable `sim/handbook` there too.
36+
Type a shortcut such as `go/handbook` or `sim/handbook` in Chrome’s address bar. Both work as soon as the extension is installed.
3737

3838
For suggestions, type `sim`, press **Space**, and enter part of a link name. If Chrome searches instead of opening a shortcut, enable your search engine under the extension’s **+ → Browser shortcuts**. Other searches stay unchanged.
3939

‎apps/docs/content/docs/search/sim-links.mdx‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,17 @@ Names ignore case and punctuation, so `sim/Team-Handbook` and `sim/teamhandbook`
1515

1616
## Open links from the address bar
1717

18-
[Install Sim for Chrome](https://chromewebstore.google.com/detail/sim/oanlcahddodnjpdoopcpjlcageejjpmg) in your work profile. In Sim, open **Links → Browser shortcuts** and select **Enable go/ shortcuts**. Type `go/handbook` in the address bar to open a link. Enable **sim/ shortcuts** there if you prefer `sim/handbook`.
18+
[Install Sim for Chrome](https://chromewebstore.google.com/detail/sim/oanlcahddodnjpdoopcpjlcageejjpmg) in your work profile, then type `go/handbook` or `sim/handbook` in the address bar. Both work as soon as it's installed.
1919

2020
For suggestions, type `sim`, press **Space**, and enter part of a name. Matching links appear with the most opened first. Unlisted links still open by name.
2121

2222
### If a shortcut opens search
2323

24-
Open the extension’s **+ → Browser shortcuts** and turn on your search engine. Approve Chrome’s site-access prompt if shown. Google (`google.com`), Bing, DuckDuckGo, and Yahoo are supported. Other searches and your default search engine stay unchanged.
24+
This can happen after you clear your browsing history. A trailing slash (`go/handbook/`) or `http://go/handbook` tells Chrome to navigate directly, and Chrome remembers it from then on.
2525

26-
This handles whole shortcuts such as `go/handbook` or `go/jira/123`. For spaces, query parameters, unsupported search sites, or blocked site access, use `sim` + **Space** or the full `https://www.sim.ai/sim/<name>` address. A trailing slash (`go/handbook/`) or `http://go/handbook` also tells Chrome to navigate directly.
26+
To catch these searches automatically, open the extension’s **+ → Browser shortcuts** and turn on your search engine. Approve Chrome’s site-access prompt if shown. Google (`google.com`), Bing, DuckDuckGo, and Yahoo are supported. Other searches and your default search engine stay unchanged.
27+
28+
This handles whole shortcuts such as `go/handbook` or `go/jira/123`. For spaces, query parameters, unsupported search sites, or blocked site access, use `sim` + **Space** or the full `https://www.sim.ai/sim/<name>` address.
2729

2830
Turning shortcuts off keeps site access. To remove it, open Chrome’s **Extensions → Manage extensions → Sim → Details**.
2931

@@ -45,9 +47,7 @@ Type `sim`, press **Space**, then type a link name and press **Enter**. For mana
4547

4648
### Show favorites in regular Chrome suggestions
4749

48-
In Sim, choose **Copy link** for a favorite. In Chrome’s bookmark manager (`chrome://bookmarks`), add a bookmark with that URL and name it after the shortcut, such as `sim/handbook`. Chrome can suggest that bookmark when you type `sim/handb` or `handbook` in the address bar. Administrators can distribute selected team favorites through Chrome’s [managed bookmarks policy](https://chromeenterprise.google/policies/managed-bookmarks/).
49-
50-
Organization admins can also open **Browser shortcuts → Team bookmarks**, choose listed links, and select **Export bookmarks**. The downloaded JSON contains a folder to merge into Chrome’s managed bookmarks policy. Its links resolve in the exporting organization, so a bookmark shared outside the team cannot open another team's same-name destination.
50+
In Sim, choose **Copy link** for a favorite. In Chrome’s bookmark manager (`chrome://bookmarks`), add a bookmark with that URL and name it after the shortcut, such as `sim/handbook`. Chrome can suggest that bookmark when you type `sim/handb` or `handbook` in the address bar.
5151

5252
## Create a link
5353

‎apps/extension/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ SIM_EXTENSION_DEV=1 SIM_EXTENSION_ORIGIN=http://localhost:3000 bun run --cwd app
3030
## Data and permissions
3131

3232
- Required capabilities: `activeTab`, `scripting`, `sidePanel`, `storage`, `contextMenus`, `declarativeNetRequestWithHostAccess`, and access to the configured Sim origin and to `http(s)://sim/*` and `http(s)://go/*`.
33-
- Type `sim`, press Space, enter the name, and press Enter to open an organization's [link](https://docs.sim.ai/search/sim-links). `go/<name>` opens the same link. Chrome can treat bare `go/<name>` or `sim/<name>` as a search before the redirect rule runs. Typing `http://go/<name>` once lets Chrome learn the short host in that profile. A trailing slash (`go/<name>/`) also selects navigation without relying on that history. A single static redirect rule rewrites top-level navigations to `http(s)://sim/*` and `http(s)://go/*` to `<Sim origin>/sim/*` with the path and query unchanged. The `sim` and `go` host permissions exist only for that rule: every navigation to those hosts is redirected before it loads, and no other request is matched or observed. An organization that already serves an intranet host named `sim` or `go` should not install this build, since its links would be redirected to Sim. When another extension (such as another go-links tool) also redirects `go/`, Chrome applies the most recently installed extension's rule.
33+
- Type `sim`, press Space, enter the name, and press Enter to open an organization's [link](https://docs.sim.ai/search/sim-links). `go/<name>` opens the same link. Chrome treats bare `go/<name>` or `sim/<name>` as a search until its history holds that short host, so on install the extension opens `http://go/` and `http://sim/` once in background tabs that close themselves. Chrome counts a visit to an unfamiliar single-label host as typed, which is what the address bar checks. If that history is cleared, a trailing slash (`go/<name>/`) selects navigation and teaches the host again. A single static redirect rule rewrites top-level navigations to `http(s)://sim/*` and `http(s)://go/*` to `<Sim origin>/sim/*` with the path and query unchanged. The `sim` and `go` host permissions exist only for that rule: every navigation to those hosts is redirected before it loads, and no other request is matched or observed. An organization that already serves an intranet host named `sim` or `go` should not install this build, since its links would be redirected to Sim. When another extension (such as another go-links tool) also redirects `go/`, Chrome applies the most recently installed extension's rule.
3434
- The `sim` address-bar keyword (`sim`, then Space) lists matching Sim links while you type and opens what you enter through the same resolver. For these suggestions, the background worker sends the text typed before the first `/` or `?`, and nothing else, unless that text contains a space (a search) or is longer than a link name can be, to `<Sim origin>/api/sim-links/suggestions` with the signed-in session, and the extension's content security policy allows connections to that origin alone. Unlisted links are never suggested.
3535
- **+ → Browser shortcuts** separately opts into recovery for exact Google, Bing, DuckDuckGo, or Yahoo HTTPS search hosts. After a direct Chrome permission grant, dynamic request rules redirect only top-level GET requests with one query parameter containing a whole `go/<name>` or `sim/<name>` shortcut. Only that value reaches `/sim-links/recover`, which validates it and redirects to the existing authenticated resolver. Ordinary search terms, additional search parameters, subframes, and unsupported inputs are not forwarded. Chrome applies these rules without an extension search-URL observer. Turning a provider off removes its rules while preserving site access; revoking access clears its recovery choice. This does not enable page reference or change the default search provider.
3636
- Optional HTTP/HTTPS access is requested together by **Allow across websites**, from a direct user action. Chrome's `activeTab` access is temporary and does not follow arbitrary new sites.

‎apps/extension/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sim/extension",
3-
"version": "0.1.4",
3+
"version": "0.1.5",
44
"private": true,
55
"type": "module",
66
"license": "Apache-2.0",

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,21 @@ try {
209209
const worker = context.serviceWorkers()[0] ?? (await context.waitForEvent('serviceworker'))
210210
context.setDefaultTimeout(15_000)
211211
const extensionId = worker.url().split('/')[2]
212+
await check('Installing visits each short host once in tabs that close themselves', async () => {
213+
await expect
214+
.poll(
215+
() =>
216+
worker.evaluate(
217+
async () => (await chrome.storage.local.get('shortHostsLearned')).shortHostsLearned
218+
),
219+
{ timeout: 30_000 }
220+
)
221+
.toBe(true)
222+
const leftBehind = await worker.evaluate(
223+
async () => (await chrome.tabs.query({ url: ['http://go/*', 'http://sim/*'] })).length
224+
)
225+
assert(leftBehind === 0, 'Short host tabs were left open')
226+
})
212227
const signIn = await context.newPage()
213228
await signIn.goto(`${origin}/sign-in`)
214229
await signIn.close()

‎apps/extension/src/background.ts‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
import { captureIntentSchema } from '@/intent'
1212
import { registerSimLinkOmnibox } from '@/omnibox'
1313
import { registerSearchRecovery } from '@/search-recovery'
14+
import { registerShortHostLearning } from '@/short-hosts'
1415
import { digestUrl } from '@/utils'
1516

1617
const logger = createLogger('BrowserExtension')
@@ -92,6 +93,7 @@ function open(tab: chrome.tabs.Tab, trigger: 'page' | 'selection' | 'keyboard')
9293

9394
registerSimLinkOmnibox()
9495
registerSearchRecovery()
96+
registerShortHostLearning()
9597
chrome.runtime.onInstalled.addListener(() => {
9698
void configure().catch(() => logger.warn('Could not initialize extension controls'))
9799
})

‎apps/extension/src/short-hosts.ts‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { SIM_LINK_HOSTS } from '@sim/browser-extension-protocol'
2+
import { createLogger } from '@sim/logger'
3+
import { SIM_ORIGIN } from '@/config'
4+
5+
const logger = createLogger('ShortHosts')
6+
const LEARNED_KEY = 'shortHostsLearned'
7+
const VISIT_TIMEOUT_MS = 15_000
8+
9+
/** Closes once Chrome has committed the visit, which is what records the host in its history. */
10+
async function visitInBackground(host: string) {
11+
const { id: tabId } = await chrome.tabs.create({ url: `http://${host}/`, active: false })
12+
if (tabId === undefined) return
13+
await new Promise<void>((resolve) => {
14+
const finish = () => {
15+
clearTimeout(timeout)
16+
chrome.tabs.onUpdated.removeListener(updated)
17+
resolve()
18+
}
19+
const updated = (id: number, change: chrome.tabs.OnUpdatedInfo, tab: chrome.tabs.Tab) => {
20+
if (id === tabId && (change.status === 'complete' || tab.url?.startsWith(SIM_ORIGIN))) {
21+
finish()
22+
}
23+
}
24+
const timeout = setTimeout(finish, VISIT_TIMEOUT_MS)
25+
chrome.tabs.onUpdated.addListener(updated)
26+
})
27+
await chrome.tabs.remove(tabId).catch(() => undefined)
28+
}
29+
30+
/**
31+
* Chrome searches for `go/handbook` until it has seen `go` as a host, so visiting each short host
32+
* once is what makes them work from the address bar. A visit to an unfamiliar single-label host
33+
* counts as typed in Chrome's history, so it teaches the address bar without asking the user to.
34+
*/
35+
async function learnShortHosts() {
36+
const stored = await chrome.storage.local.get(LEARNED_KEY)
37+
if (stored[LEARNED_KEY] === true) return
38+
await Promise.all(SIM_LINK_HOSTS.map(visitInBackground))
39+
await chrome.storage.local.set({ [LEARNED_KEY]: true })
40+
}
41+
42+
export function registerShortHostLearning() {
43+
const learn = () => {
44+
void learnShortHosts().catch(() => logger.warn('Could not visit the short link hosts'))
45+
}
46+
chrome.runtime.onInstalled.addListener(learn)
47+
// A managed install can run before any window exists, so it retries at the next browser start.
48+
chrome.runtime.onStartup.addListener(learn)
49+
}

‎apps/sim/app/(landing)/privacy/privacy-content.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,7 @@ export const PRIVACY_CONFIG: LegalPageConfig = {
848848
{
849849
kind: 'paragraph',
850850
content: richText(
851-
'Browser shortcuts can optionally recover an explicit sim/ or go/ shortcut that Chrome sends to a supported search engine. After You enable a provider and approve access to its listed sites, Chrome applies request rules that send only the matching shortcut name and path values to Sim’s normal link resolver. Other search parameters and ordinary search terms are not sent to Sim by this feature. The extension stores Your provider choices locally and does not change Your default search engine. These site permissions can also allow page attachment when You explicitly request it; enabling shortcut recovery does not enable Reference current page or background capture. Turning recovery off stops these redirects. Site access remains until You revoke or restrict it in Chrome settings.'
851+
'When installed, the extension opens sim/ and go/ once in background tabs that close themselves, so Chrome recognizes these shortcuts in the address bar. Those tabs load Sim’s link page with Your session and send no browsing data. Browser shortcuts can optionally recover an explicit sim/ or go/ shortcut that Chrome sends to a supported search engine. After You enable a provider and approve access to its listed sites, Chrome applies request rules that send only the matching shortcut name and path values to Sim’s normal link resolver. Other search parameters and ordinary search terms are not sent to Sim by this feature. The extension stores Your provider choices locally and does not change Your default search engine. These site permissions can also allow page attachment when You explicitly request it; enabling shortcut recovery does not enable Reference current page or background capture. Turning recovery off stops these redirects. Site access remains until You revoke or restrict it in Chrome settings.'
852852
),
853853
},
854854
{

‎apps/sim/app/api/organizations/[id]/sim-links/bookmarks/route.ts‎

Lines changed: 0 additions & 20 deletions
This file was deleted.

‎apps/sim/app/o/[organizationId]/links/browser-shortcuts-modal.tsx‎

Lines changed: 0 additions & 62 deletions
This file was deleted.

0 commit comments

Comments
 (0)