C.W.K.
Stream
Lesson 01 of 08 · published

Anchor 1 — Manifest 해부

~10 min · manifest, case-study, chromeembed

Level 0Extension 입덕
0 XP0/54 lessons0/13 achievements
0/100 XP to next level100 XP to go0% complete
"ChromeEmbed v0.1 이 manifest 28 줄과 script file 넷. Lesson 1 이 manifest — 모든 field 정당화, 모든 선택이 이전 track 중 하나로 묶임."
동작 중인 Pippa ChromeEmbed v0.1 — Chrome window 오른쪽 가장자리에 docked 된 Pippa chat panel, 메인 뷰포트에 host page 보임
Pippa ChromeEmbed v0.1 — 이 Track 9 가 file by file walk 하는 working prototype.

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 — future 사용 위해 선언; v0.1 이 SW 의 in-memory Map 에 의존. 유지 저렴.
  • tabs — background.js 가 activeTab query 결과에서 tab.url, tab.title, tab.favIconUrl read 해서 필요 (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> AND content_scripts.matches — ChromeEmbed 가 특정 origin 만 아닌 user 방문하는 어떤 page 든 context 제공 원해서 필요.
  • Localhost 와 127.0.0.1 — development 위해. cwkPippa dev server 가 localhost:5173 에서 돔; side panel iframe 이 거기서 load.
  • 100.x.x.x (Tailscale CGNAT host — 자기 private VPN IP 로 교체) — 같은 private network 의 다른 device 가 dev server 닿게 해 줘. ChromeEmbed 가 household 의 모든 Mac 에서 돔; 어느 시점에 cwkPippa host 하는 Mac 이든 그것의 Tailscale IP 로 닿음.

이 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 로 선언. ChromeEmbed 가 user 가 iframe 안에서 (embedded YouTube 댓글, Notion embed) 뭔가 highlight 할 때도 selection 과 viewport 텍스트 capture 원함. Default all_frames: false 는 그것들 놓침. Trade-off: 모든 iframe 이 content script load, 메모리 비용; 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 된 것.

Manifest 가 계약. 모든 field 가 feature 로 정당화, 모든 permission 이 feature 가 허용하는 만큼 narrow. ChromeEmbed 의 28 줄이 여덟 track concrete 된 것.
왜 1.0.0 아닌 0.1.0? ChromeEmbed 가 자기 v0.1 이름 일부러 — larger framework story (PIPPA-EMBEDS.md) 의 첫 concrete embed surface. v1 이 downstream embed (Adobe, Mail, Calendar) 가 상속할 API surface 표시; ChromeEmbed 가 shape 증명하고 그 계약 calcify 전 gap 노출.

Code

embeds/chrome/manifest.json — 실제 ChromeEmbed v0.1 manifest·json
{
  "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;"
  }
}

External links

Exercise

cwkPippa/embeds/chrome/manifest.json (그 repo access 있으면) 의 실제 ChromeEmbed manifest 열거나 code block 을 시작점으로 복사. 각 field walk 하고 도입한 track 으로 label. 한 가지 수정 시도: host_permissions 에서 localhost entry 와 매칭 frame-src 제거, 다음 extension load 하고 side panel 열기 시도 — iframe 이 panel DevTools console 에 CSP error 와 함께 실패하는 거 확인. Entry 복원해서 fix. Lesson: manifest 의 모든 field 가 work 하고, 어느 거든 제거하면 해당 feature 쓰려 할 때 즉시 surface.
Hint
Localhost entry 제거 후에도 panel 여전히 load 하면, production cwkPippa URL 이 다른 데 있을 수도 — sidepanel.html 의 iframe src 가 localhost 가리키는지 다른 데인지도 확인. cwkPippa repo access 없으면, manifest 를 작성된 대로 받아들이기; lesson 이 snippet 만으로 동작. Track 9 lesson 이 load-and-run 아닌 read-and-reason exercise; 목표가 다른 사람의 prototype 의 local re-deployment 아닌 mental-model alignment.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.