diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 600e583..b216b1f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -123,7 +123,7 @@ jobs: # usage-example applies three things from mavenLocal: packpack (through the plugin), the # toolchain plugin, and python-multiplatform's library and bindings plugin. Versions pinned in - # usage-example/gradle/libs.versions.toml (3.15.0-alpha01). + # usage-example/gradle/libs.versions.toml (3.15.0-alpha03). - name: Publish packpack, the toolchain plugin and python-multiplatform to mavenLocal run: | (cd .ci/pypackpack && ./gradlew :packpack:publishToMavenLocal --console=plain) diff --git a/README.md b/README.md index 0e1a225..4057a1a 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ plugins { } python { - compileSdk = "3.13" + compileSdk = "3.15.0" // the CPython python-multiplatform provides localLibraryPath = "src/commonMain/python" // a pypackpack package: pyproject.toml + src/main/ packaging { fileName = "usage-example" @@ -120,7 +120,8 @@ python { Python only? Skip Gradle builds entirely: ```shell -./gradlew :toolchain:runTcl --args="install pythonx-compose" +uv tool install toolchain-lite +tcl install pythonx-compose ``` ## 🧭 Architecture at a glance diff --git a/docs/guide/getting-started.html b/docs/guide/getting-started.html index 542960f..3da9e8c 100644 --- a/docs/guide/getting-started.html +++ b/docs/guide/getting-started.html @@ -56,7 +56,7 @@

3. Apply the plugin3. ν”Œ } python { - compileSdk = "3.13" + compileSdk = "3.15.0" localLibraryPath = "src/commonMain/python" packaging { fileName = "usage-example" diff --git a/docs/guide/guide-staging.html b/docs/guide/guide-staging.html index 8ec2862..a446939 100644 --- a/docs/guide/guide-staging.html +++ b/docs/guide/guide-staging.html @@ -60,6 +60,33 @@

iOS: the Xcode build phasei

After stagingμŠ€ν…Œμ΄μ§• 이후

Putting the staged python/ on sys.path when the app starts is the runtime's job: python-multiplatform's side of the boundary, not this plugin's.

앱이 μ‹œμž‘ν•  λ•Œ μŠ€ν…Œμ΄μ§•λœ python/ 을 sys.path 에 μ˜¬λ¦¬λŠ” 것은 λŸ°νƒ€μž„μ˜ μΌμž…λ‹ˆλ‹€: 이 ν”ŒλŸ¬κ·ΈμΈμ΄ μ•„λ‹ˆλΌ python-multiplatform μͺ½ κ²½κ³„μž…λ‹ˆλ‹€.

+ +
+

WASM: cross-origin isolation and its limitsWASM: ꡐ차 좜처 격리와 κ·Έ ν•œκ³„

+

WASM runs free-threaded CPython 3.15t with pthreads. WebAssembly threads require SharedArrayBuffer, which browsers only expose when self.crossOriginIsolated === true: Cross-Origin-Opener-Policy: same-origin together with Cross-Origin-Embedder-Policy: require-corp (or credentialless via -Ppython.wasm.coep=credentialless), plus Cross-Origin-Resource-Policy: same-origin on the app's own assets. Cross-origin isolation is on by default for every WASM app this plugin builds:

WASM 은 pthreads 기반 자유 μŠ€λ ˆλ“œ CPython 3.15t 둜 μ‹€ν–‰λ©λ‹ˆλ‹€. WebAssembly μŠ€λ ˆλ“œλŠ” SharedArrayBuffer κ°€ ν•„μš”ν•˜λ©°, λΈŒλΌμš°μ €λŠ” self.crossOriginIsolated === true 일 λ•Œλ§Œ 이λ₯Ό μ—΄μ–΄ μ€λ‹ˆλ‹€: Cross-Origin-Opener-Policy: same-origin κ³Ό Cross-Origin-Embedder-Policy: require-corp(λ˜λŠ” -Ppython.wasm.coep=credentialless 둜 κ³ λ₯΄λŠ” credentialless), 그리고 μ•± 자체 μžμ‚°μ˜ Cross-Origin-Resource-Policy: same-origin μž…λ‹ˆλ‹€. 이 ν”ŒλŸ¬κ·ΈμΈμ΄ λΉŒλ“œν•˜λŠ” λͺ¨λ“  WASM μ•±μ—λŠ” ꡐ차 좜처 격리가 기본으둜 μΌœμ§‘λ‹ˆλ‹€:

+
    +
  • Dev server headers: every wasmJs*Webpack task writes webpack.config.d/python-cross-origin-isolation.js so the local webpack dev server sends all three headers automatically.개발 μ„œλ²„ 헀더: λͺ¨λ“  wasmJs*Webpack νƒœμŠ€ν¬κ°€ webpack.config.d/python-cross-origin-isolation.js λ₯Ό 기둝해 둜컬 webpack 개발 μ„œλ²„κ°€ μ„Έ 헀더λ₯Ό μžλ™μœΌλ‘œ λ³΄λƒ…λ‹ˆλ‹€.
  • +
  • Static host headers (_headers): stageWasmCrossOriginIsolation emits a Cloudflare Pages and Netlify _headers file into the WASM browser distribution root.정적 호슀트 헀더(_headers): stageWasmCrossOriginIsolation 이 Cloudflare Pages 와 Netlify ν˜•μ‹μ˜ _headers νŒŒμΌμ„ WASM λΈŒλΌμš°μ € 배포 λ£¨νŠΈμ— μƒμ„±ν•©λ‹ˆλ‹€.
  • +
  • Service-worker fallback (coi-serviceworker.js) and check page (coi-check.html): for hosts that cannot set HTTP headers (such as GitHub Pages), coi-serviceworker.js intercepts fetches and re-serves responses with COOP, COEP and CORP. Its cost is one reload on the first visit, and it has no effect when service workers are unavailable (non-HTTPS origins other than localhost, or webviews with service workers disabled). At startup the runtime checks self.crossOriginIsolated and fails immediately rather than failing later inside a thread; coi-check.html tests the same invariant on its own.μ„œλΉ„μŠ€ μ›Œμ»€ 폴백(coi-serviceworker.js)κ³Ό 점검 νŽ˜μ΄μ§€(coi-check.html): GitHub Pages 처럼 HTTP 헀더λ₯Ό μ„€μ •ν•  수 μ—†λŠ” 호슀트λ₯Ό μœ„ν•΄, coi-serviceworker.js κ°€ μš”μ²­μ„ κ°€λ‘œμ±„ COOP, COEP, CORP 헀더λ₯Ό λΆ™μ—¬ μ‘λ‹΅ν•©λ‹ˆλ‹€. κ·Έ λΉ„μš©μ€ 첫 λ°©λ¬Έ μ‹œ 1회 μƒˆλ‘œκ³ μΉ¨μ΄λ©°, μ„œλΉ„μŠ€ μ›Œμ»€λ₯Ό μ“Έ 수 μ—†λŠ” ν™˜κ²½μ—μ„œλŠ” νš¨κ³Όκ°€ μ—†μŠ΅λ‹ˆλ‹€(localhost μ΄μ™Έμ˜ λΉ„-HTTPS μΆœμ²˜λ‚˜ μ„œλΉ„μŠ€ μ›Œμ»€κ°€ κΊΌμ§„ μ›Ήλ·°). μ‹œμž‘ μ‹œ λŸ°νƒ€μž„μ΄ self.crossOriginIsolated λ₯Ό 확인해 μŠ€λ ˆλ“œ μ•ˆμ—μ„œ λ’€λŠ¦κ²Œ μ£½λŠ” λŒ€μ‹  μ¦‰μ‹œ μ‹€νŒ¨ν•˜λ©°, coi-check.html λ‘œλ„ 같은 쑰건을 λ°”λ‘œ 점검할 수 μžˆμŠ΅λ‹ˆλ‹€.
  • +
+

Browser limits of cross-origin isolationꡐ차 좜처 격리의 λΈŒλΌμš°μ € μ œμ•½

+
Surfaceμ˜μ—­What cross-origin isolation changesꡐ차 좜처 격리둜 λ‹¬λΌμ§€λŠ” 점What to doλŒ€μ‘ 방법
Third-party <iframe>제3자 <iframe>Embedded cross-origin documents must opt in with CORP/COEP headers, or the browser refuses to load them.λ‚΄μž₯된 ꡐ차 좜처 λ¬Έμ„œκ°€ CORP/COEP ν—€λ”λ‘œ λ™μ˜ν•˜μ§€ μ•ŠμœΌλ©΄ λΈŒλΌμš°μ €κ°€ λ‘œλ“œλ₯Ό κ±°λΆ€ν•©λ‹ˆλ‹€.Serve the framed document with Cross-Origin-Embedder-Policy and Cross-Origin-Resource-Policy: cross-origin, or open it in a top-level navigation instead of an iframe.iframe λ¬Έμ„œμ— Cross-Origin-Embedder-Policy 와 Cross-Origin-Resource-Policy: cross-origin 을 μ„€μ •ν•˜κ±°λ‚˜, iframe λŒ€μ‹  μ΅œμƒμœ„ νƒμƒ‰μœΌλ‘œ μ—¬μ„Έμš”.
Popup OAuth and payment flowsνŒμ—… 기반 OAuth 및 결제 흐름Under Cross-Origin-Opener-Policy: same-origin, cross-origin popups lose window.opener (it becomes null), so postMessage handshakes back to the opener break.Cross-Origin-Opener-Policy: same-origin μ•„λž˜μ—μ„œλŠ” ꡐ차 좜처 νŒμ—…μ˜ window.opener κ°€ null 이 λ˜μ–΄, λΆ€λͺ¨ 창으둜의 postMessage ν•Έλ“œμ…°μ΄ν¬κ°€ λŠκΉλ‹ˆλ‹€.Use full-page redirect OAuth/payment flows, or configure the host with same-origin-allow-popups where the browser's isolation rules permit it.전체 νŽ˜μ΄μ§€ λ¦¬λ‹€μ΄λ ‰νŠΈ λ°©μ‹μ˜ OAuth/결제 흐름을 μ“°κ±°λ‚˜, λΈŒλΌμš°μ € 격리 κ·œμΉ™μ΄ ν—ˆμš©ν•˜λŠ” λ²”μœ„μ—μ„œ ν˜ΈμŠ€νŠΈμ— same-origin-allow-popups λ₯Ό μ„€μ •ν•˜μ„Έμš”.
External images, scripts, fonts and mediaμ™ΈλΆ€ 이미지, 슀크립트, κΈ€κΌ΄, λ―Έλ””μ–΄Under Cross-Origin-Embedder-Policy: require-corp, any cross-origin subresource without a Cross-Origin-Resource-Policy or CORS header is blocked.Cross-Origin-Embedder-Policy: require-corp μ•„λž˜μ—μ„œλŠ” Cross-Origin-Resource-Policy λ‚˜ CORS 헀더가 μ—†λŠ” ꡐ차 좜처 ν•˜μœ„ λ¦¬μ†ŒμŠ€κ°€ μ°¨λ‹¨λ©λ‹ˆλ‹€.Add crossorigin attributes and serve CORS/CORP headers on the asset host, or build with -Ppython.wasm.coep=credentialless so no-cookie cross-origin requests load without CORP.crossorigin 속성을 뢙이고 μžμ‚° ν˜ΈμŠ€νŠΈμ—μ„œ CORS/CORP 헀더λ₯Ό λ‚΄λ €μ£Όκ±°λ‚˜, μΏ ν‚€ μ—†λŠ” ꡐ차 좜처 μš”μ²­μ„ CORP 없이 λ‘œλ“œν•˜λ„λ‘ -Ppython.wasm.coep=credentialless 둜 λΉŒλ“œν•˜μ„Έμš”.
+

Header snippets for other hostsλ‹€λ₯Έ 호슀트λ₯Ό μœ„ν•œ 헀더 μ„€μ • μ˜ˆμ‹œ

+

Cloudflare Pages and Netlify read the generated _headers file directly. For nginx, Apache, Firebase Hosting or Vercel, add the same headers in the host configuration:

Cloudflare Pages 와 Netlify λŠ” μƒμ„±λœ _headers νŒŒμΌμ„ λ°”λ‘œ μ½μŠ΅λ‹ˆλ‹€. nginx, Apache, Firebase Hosting, Vercel μ—μ„œλŠ” 호슀트 섀정에 같은 헀더λ₯Ό μΆ”κ°€ν•˜μ„Έμš”:

+
# nginx
+add_header Cross-Origin-Opener-Policy "same-origin" always;
+add_header Cross-Origin-Embedder-Policy "require-corp" always;
+add_header Cross-Origin-Resource-Policy "same-origin" always;
+
+# Apache (.htaccess)
+Header always set Cross-Origin-Opener-Policy "same-origin"
+Header always set Cross-Origin-Embedder-Policy "require-corp"
+Header always set Cross-Origin-Resource-Policy "same-origin"
+
+# Firebase Hosting (firebase.json) / Vercel (vercel.json)
+# Set headers on "/(.*)" -> Cross-Origin-Opener-Policy: same-origin,
+# Cross-Origin-Embedder-Policy: require-corp, Cross-Origin-Resource-Policy: same-origin
+