"Minimum 으로 install. 의도로 나머지 얻기. Track 6 가 end-to-end wire 된 opt-in flow 둘로 끝남: Export Clips 가 user click 시 downloads 요청, Enable on This Site 가 user 가 이전 excluded URL 에 ClipDeck 원할 때 host permission 요청."
두 flow
Track 5 가 ClipDeck 에 `downloads` 와 `optional_host_permissions` 선언만 했지 요청은 안 함. 이 lesson 이 둘 다 light:
- Export Clips — popup 이나 side-panel 버튼. Click 시 grant 안 됐으면
downloads요청, 다음 SW 통해 실제 export trigger. - Enable on This Site — content script 가 현재 tab 에 안 도는 경우만 (URL 이 content_scripts.matches 매칭 안 했거나 exclude_matches 에 있어서) 나타나는 popup 버튼. Click 시
https://<current-host>/*를 host permission 으로 요청, 다음 programmatic 으로 content script inject.
둘 다 같은 shape 따름: detect → ask → run → deny 시 graceful fallback. Shape 이 너무 consistent 해서 작은 helper 로 추상화 가치 있음.
ensurePermission helper
Popup 과 side panel 둘 다 쓸 수 있는 한 함수:
async function ensurePermission(req) {
const has = await chrome.permissions.contains(req);
if (has) return true;
return chrome.permissions.request(req);
}
Contains-then-request 춤을 한 호출로 collapse. Caller 가 boolean result 에만 branch.
'Enable on This Site' flow
이게 더 흥미로움 — runtime 에 extension 의 reach 를 바꿈. Flow:
- Popup 열림. 현재 tab 의 URL read.
- Content script 가 이미 inject 됐는지 확인: ping 메시지 보내고 listener 없으면 실패 catch.
- 도는 중이면 버튼이 "ClipDeck is active on this site" 읽음. 아니면 버튼이 "Enable ClipDeck on this site" 읽음.
- Click 시
https://<host>/*의 host permission 요청. - Grant 되면
chrome.scripting.executeScript({ target: { tabId }, files: ['content.js'] })통해 content script inject 하도록 SW 한테 요청. 이제 ClipDeck 이 이 tab 에서 동작. - Reload 너머 persistent injection 위해
chrome.scripting.registerContentScripts통해 dynamic content script 도 추가, 같은 host 의 future load 가 auto-inject.
Persistent dynamic content script
chrome.scripting.registerContentScripts (Chrome 96+) 가 SW eviction 과 browser restart 살아남는 content script 등록, host permission grant 한 URL 에 scoped. Shape:
await chrome.scripting.registerContentScripts([{
id: 'clipdeck-dynamic-acme',
matches: ['https://acme.com/*'],
js: ['content.js'],
runAt: 'document_idle',
}]);
기존 거 list 하려면 getRegisteredContentScripts; 제거하려면 unregisterContentScripts({ ids: ['...'] }). 'Disable on this site' 대응이 unregister 하고 AND chrome.permissions.remove({ origins: ['https://acme.com/*'] }) 호출.
Privacy 신뢰 이야기
이 lesson 끝에 ClipDeck 이 install 시 가짐:
- 한 install 경고 (좁힌 content_scripts.matches), 한 moderate 경고 (tabs), 한 silent set (storage / sidePanel / contextMenus / scripting / activeTab / alarms).
- Export / notification / "추가 site 에서 활성화" 모두 per-feature in-product prompt 뒤 gating.
- Privacy-minded user 가 downloads 나 추가 host grant 절대 안 하고 entire core feature set 사용 가능; 실제로 원하는 upgrade 에만 지불.
이게 Chrome Web Store reviewer 찾는 bar: "install 경고가 extension 이 install 시 실제로 하는 거에 비례해?" 모든 거 install 시 요청하는 extension 이 기술적으로 모든 거 쓸 거여도 bar 실패. 요청을 in-product 순간으로 defer 하는 extension 이 통과.
Track 6 마무리
여섯 track 끝. ClipDeck 이 가짐:
- 깔끔한 permission 카테고리 가진 MV3 manifest.
- Service worker / popup / side panel / content script / context menu / keyboard shortcut / omnibox / badge.
- Full CRUD-C (Track 3) 와 CRUD-R (Track 4).
- Per-tab pause (Track 5).
- Just-in-time downloads 와 host permission (이 track).
Track 7 이 CRUD 나머지 — Update 와 Delete — 와 사람들이 실제로 쓰는 messy, framework-heavy site 에서 기존 reach 가 동작하게 하는 더 큰 DOM-handling toolkit 추가.