"ChromeEmbed v0.1이 manifest 28 줄과 script file 넷. Lesson 1이 manifest — 모든 field 정당화, 모든 선택이 이전 track 중 하나로 묶임."
28 줄
실제 ChromeEmbed manifest, end to end:
{
"manifest_version": 3,
"name": "Pippa ChromeEmbed",
"version": "0.1.0",
"description": "The household, present on the current page.",
"permissions": ["sidePanel", "activeTab", "storage", "tabs", "scripting"],
"host_permissions": [
"<all_urls>",
"http://localhost:5173/*",
"http://127.0.0.1:5173/*",
"http://100.x.x.x:5173/*"
],
"background": { "service_worker": "background.js" },
"side_panel": { "default_path": "sidepanel.html" },
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["content-script.js"],
"run_at": "document_idle",
"all_frames": true
}],
"action": { "default_popup": "popup.html" },
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'; frame-src http://localhost:5173 http://127.0.0.1:5173 http://100.x.x.x:5173;"
}
}
Permission — 각자 이유
sidePanel— chrome.sidePanel.* (Track 4) 위해 필수.activeTab— user-gesture-trigger 된 scripting 호출 cover, SW가 standing host access 없이 현재 page의 selection read (Track 6 Lesson 4).storage— 나중을 보고 적어 뒀어. v0.1은 SW 메모리의 Map 으로 버티고 있고. 그냥 두는 값은 거의 없으니까.tabs— background.js가 activeTab query 결과에서tab.url,tab.title,tab.favIconUrlread 해서 필요 (moderate 'browsing history' install 경고).scripting— background.js가 content script가 report 안 했을 때 selection read fallback 으로chrome.scripting.executeScript호출해서 필요 (all-frames 경로).
Host Permission — Localhost set
두 layer가 double duty:
host_permissions의<all_urls>와content_scripts.matches— 둘 다 필요해. ChromeEmbed는 정해진 사이트 몇 곳이 아니라 user가 가는 어느 페이지에서든 맥락을 건네주려고 하거든.- Localhost와 127.0.0.1 — development 위해. cwkPippa dev server가 localhost:5173에서 돔. side panel iframe이 거기서 load.
- 100.x.x.x (Tailscale의 CGNAT 대역이야 — 각자 자기 사설 VPN IP로 바꿔) — 같은 사설망에 있는 다른 기기에서도 dev server 에 닿게 해 줘. ChromeEmbed는 집 안의 Mac 어디서나 돌거든. 그때그때 cwkPippa를 띄워 둔 Mac의 Tailscale 주소로 찾아가면 돼.
이 localhost / Tailscale URL이 두 자리에 나타나는 거 주목: manifest의 host_permissions 배열 (network access 위해) AND extension_pages CSP의 frame-src directive (iframe specifically 위해). 어느 쪽에서든 제거하면 panel 깨짐. Track 4 Lesson 5가 CSP detail walk.
all_frames 선택
content script는 all_frames: true로 걸어 뒀어. user가 iframe 안에서 뭘 긁어도 — 끼워 넣은 YouTube 댓글이든 Notion embed 든 — 선택 영역과 화면 텍스트를 같이 담고 싶거든. 기본값인 all_frames: false로 두면 그런 건 다 놓쳐. 대신 치를 값이 있어. 모든 iframe이 content script를 올리게, 메모리 비용. Pippa-grade household extension 엔 받아들일 만.
action.default_popup 선택
Popup 존재 (popup.html 선언) 하지만 6-줄 doorway (Lesson 4). action.default_popup: "popup.html" 패턴이 popup 자체 chrome.sidePanel.open() + window.close()와 함께 의미: toolbar icon click → popup 잠깐 flash → side panel 열림 → popup 닫힘. User가 한 fluid 'click이 panel 엶' 동작 봄.
각 결정 만든 Track
- Track 1 — manifest_version 3, name, version, 기본.
- Track 2 — service_worker 선언.
- Track 3 — all_frames 가진 content_scripts.
- Track 4 — sidePanel permission + side_panel.default_path + extension_pages CSP frame-src.
- Track 5 — action.default_popup.
- Track 6 — narrow permission set (downloads 없음, notifications 없음). storage permission이 overhead 지만 v0.2 위해 예약.
이 중 novel 한 거 없음. 첫 여덟 track이 one working file로 composing 된 것.