@kubohiroya/turbowarp-extension-security-dialog 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/NOTICE.md CHANGED
@@ -32,3 +32,9 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32
32
  `assets/screenshots/required-modes-{en,ja}-20261025.png` are unmodified browser captures of the public Editor on 25 October 2026, showing Camera Source 0.19.3, Asset Cache 0.3.1 and Bubble 0.13.4. Their origin, Editor revisions and hashes are recorded in `assets/screenshots/capture-20261025.json`. The captured UI, icons and banners retain their respective rights holders and applicable licenses; this package does not relicense those elements.
33
33
 
34
34
  `assets/screenshots/localized-descriptions-{en,ja}-20261025.png` are unmodified captures of the updated public Editor on 25 October 2026, showing localized descriptions for Camera Source 0.19.4, Asset Cache 0.3.2 and Bubble 0.13.5. Their origin, revisions and hashes are recorded in `assets/screenshots/localized-descriptions-20261025.json`. The captured UI, icons and banners retain their respective rights holders and applicable licenses.
35
+
36
+ `assets/screenshots/required-approval-{en,ja}-20261028.png` are unmodified captures of the public Editor on 28 October 2026 after the required-mode approval update, showing Camera Source 0.19.4, Asset Cache 0.3.2 and Bubble 0.13.5 with Deny and With sandbox disabled. Their origin, verified distribution hashes, Editor revisions and image hashes are recorded in `assets/screenshots/required-approval-20261028.json`. The captured UI, icons and banners retain their respective rights holders and applicable licenses.
37
+
38
+ `assets/screenshots/preselected-required-{en,ja}-20261028.png` are unmodified captures of the public Editor on 28 October 2026 after automatic preselection was added when all listed extensions require unsandboxed execution. Camera Source 0.19.4, Asset Cache 0.3.2 and Bubble 0.13.5 have Without sandbox preselected and still require OK before execution. Origin, verified distribution hashes, Editor revisions and image hashes are recorded in `assets/screenshots/preselected-required-20261028.json`. The captured UI, icons and banners retain their respective rights holders and applicable licenses.
39
+
40
+ `assets/screenshots/hidden-bulk-required-{en,ja}-20261028.png` are unmodified captures of the public Editor on 28 October 2026 with Without sandbox preselected for all three required extensions and the redundant bulk selection section hidden. Camera Source 0.19.4, Asset Cache 0.3.2 and Bubble 0.13.5 still require OK before execution. Origin, verified distribution hashes, Editor revisions and image hashes are recorded in `assets/screenshots/hidden-bulk-required-20261028.json`. The captured UI, icons and banners retain their respective rights holders and applicable licenses.
package/README.ja.md CHANGED
@@ -5,17 +5,111 @@
5
5
  TurboWarpの複数の機能拡張を、1つの一覧で確認するための共通パッケージです。
6
6
  関連タスクと受け入れ基準は [scratch-gui #33](https://github.com/kubohiroya/scratch-gui/issues/33) に記録しています。
7
7
 
8
+ ## Pagesのカタログから機能拡張を選択する
9
+
10
+ `ExtensionSelectionList` は既存のバナー・メタデータを共有し、各行の右端へチェックボックスを1つ表示します。
11
+ TurboWarp Plus一覧の対応範囲は [#28](https://github.com/kubohiroya/turbowarp-extension-security-dialog/issues/28) に記録しています。
12
+ ホスト側でGitHub PagesのJSONをHTTPS取得し、このコンポーネントへ渡します。
13
+
14
+ ```jsx
15
+ import {loadExtensionCatalog} from '@kubohiroya/turbowarp-extension-security-dialog';
16
+ import {ExtensionSelectionList} from '@kubohiroya/turbowarp-extension-security-dialog/react';
17
+
18
+ const controller = new AbortController();
19
+ const entries = await loadExtensionCatalog(
20
+ 'https://kubohiroya.github.io/turbowarp-plus-packages/extensions-v1.json',
21
+ controller.signal
22
+ );
23
+
24
+ const list = <ExtensionSelectionList entries={entries} locale="ja"
25
+ filterQuery={searchText} loadedIds={loadedExtensionIds} busy={loading}
26
+ onCancel={closeLibrary}
27
+ onComplete={ordered => host.reviewAndLoadInOrder(ordered)} />;
28
+ ```
29
+
30
+ 例の `host.reviewAndLoadInOrder` はホスト側で実装する実行許可確認・VM読み込み処理です。
31
+ `onComplete` は依存先を先に並べた重複のない配列を返し、`loadedIds` は除外します。
32
+ ある拡張を選ぶと推移的な依存先すべてがchecked・disabledになります。
33
+ 親を解除すると依存関係を再計算し、ほかの選択やユーザー自身の明示選択が必要としている拡張は選択を保ちます。
34
+ 読み込み済みの行はchecked・disabledです。検索と表示言語を切り替えても選択を保ちます。
35
+ `busy` で選択・フッター操作を無効にします。取得失敗・再試行・カタログの取得中止・VMエラーの表示と、
36
+ 読み込み成功に応じた `loadedIds` 更新はホスト側の担当です。
37
+
38
+ 各行は「手動で選択」(青)・「依存関係で自動選択」(紫)・「未選択」(中立色)を、背景・左枠・
39
+ アイコン・状態名で区別します。「読み込み済み」も独立した表示です。一覧の上部には凡例を表示します。
40
+ 自動選択した行には「Bubble、Sprite に必要」のように、必要としている明示選択元すべてを表示します。
41
+ 手動で選んだ拡張がほかの選択元の依存先になった場合も、「手動で選択」を維持し、依存元を併記して
42
+ チェックボックスを解除不可にします。DOMの `data-selection-state` は順に `selected` / `dependency` /
43
+ `unselected` / `loaded` です。
44
+
45
+ 任意のカテゴリ定義がある場合、ダッシュボードと同じ順序でカテゴリ見出し(`h2`)を表示します。
46
+ 日本語は `titleJa` があれば使用し、なければ `title` にフォールバックします。
47
+ 検索で空になったカテゴリは非表示になりますが、選択状態は維持します。
48
+ カテゴリのない旧JSONは従来の平坦な一覧です。カテゴリ付きと未指定の項目が混在する場合、未指定分は
49
+ 末尾の「その他の機能拡張」へ表示します。配色はホストのモーダル背景色・文字色に従います。
50
+ 強調色は `--twextsec-manual-accent` / `--twextsec-dependency-accent` /
51
+ `--twextsec-unselected-accent` / `--twextsec-loaded-accent` で調整できます。
52
+
53
+ 一覧の表示・選択だけでは機能拡張のコードを読み込み・実行しません。
54
+ JSONのメタデータを直ちに表示し、選択一覧には「詳細」やJS配布URLを表示しません。
55
+ 選択状態と依存元の説明はアイコン画像の下へ表示します。名前の行は「Bubble v0.15.1 (ID: kubohiroyabubble) GitHub/npmアイコン」の順で、名前に続く項目は通常の太さ・名前より2pt小さい書体です。狭い幅では必要に応じて折り返します。
56
+ ドキュメントの `docsURL`(確認済みGitHub Pages)を表示し、GitHubのOctocat・npmのアイコンから
57
+ `repository` と `package` のページを開きます。URLがない項目にリンクを推測して付けることはしません。
58
+ 製作者は `author` を表示し、公開版package.jsonの `author.url` を収録した `authorURL` があれば名前をリンクにします。
59
+ 各行には「サンドボックスなし:必要/任意/不要/未確認」を表示し、必要な場合は警告アイコンを付けます。
60
+ 実行許可確認には `ExtensionSecurityDialog context="catalog"` を使用でき、キャンセル文言が選択一覧へ戻る案内になります。
61
+ 既定の `context="project"` はプロジェクト読み込み用の文言を維持します。
62
+ ホストは確定された実行モードと独自のセキュリティ方針を尊重して読み込んでください。
63
+
64
+ 共通化した画像・サービスリンク・実行条件には `entry.metadata` と取得したソースのメタデータを使用します。
65
+ どちらか一方でも `unsandboxed: required` なら必要条件を維持し、バッジ・選択可能なモード・非対応選択の解除・
66
+ 一括初期選択で同じ判断をします。セキュリティ確認のOKは、従来どおりソースのメタデータ取得の成功/失敗が確定するまで待ちます。
67
+ それ以外の表示は今回変更せず、セキュリティ確認はソースヘッダーのバージョン・リンクのない製作者名・出所URLを維持し、
68
+ 選択一覧はカタログのバージョン・明示された製作者リンク・ドキュメントURLを維持します。
69
+ `entry.category` があれば両画面で同じ順序・日英見出しにし、カテゴリのないプロジェクトでは取得や推測をせず平坦な一覧を維持します。
70
+
71
+
72
+ JSON契約は `schemaVersion: 1` と `extensions` 配列です。各要素の必須項目は次のとおりです。
73
+
74
+ | 項目 | 内容 |
75
+ | --- | --- |
76
+ | `id` | ASCII英数字の機能拡張ID |
77
+ | `name` | 表示名 |
78
+ | `version` | 配布バージョン |
79
+ | `url` | バージョン固定の公開済み機能拡張JSへのHTTPS URL |
80
+ | `dependencies` | 同じJSONに含まれる依存先の機能拡張ID配列。npmパッケージ名ではない |
81
+
82
+ `package`・`description`・`descriptions`(`ja`等の小文字言語タグをキーとする説明)・`author`・`license`・
83
+ `banner`・`repository`・`docsURL`・`authorURL`・`unsandboxed`(例: `required`)は任意のメタデータです。
84
+ 完全なJSON例は[英語版のAPI例](README.md#selecting-extensions-from-a-pages-catalog)を参照してください。
85
+ 生成側でパッケージ依存を拡張IDへ変換し、ビルド専用パッケージを除外します。
86
+
87
+ カテゴリはトップレベルの任意項目 `categories: [{id, title, titleJa?}]` としてダッシュボード順に定義し、
88
+ 各 `extensions[].category` にそのIDを指定します。カテゴリIDの重複・不正な定義・未定義IDの参照は拒否します。
89
+ `parseExtensionCatalog` の返り値は従来どおり配列で、カテゴリ参照は各要素の
90
+ `category: {id, title, titleJa?, order}` へ解決します。`order` は定義の配列順です。
91
+
92
+ `parseExtensionCatalog` は未対応schema、ID/URL重複、存在しない依存先、循環依存、HTTPS以外や認証情報付きのURLを拒否します(製作者の `authorURL` だけはHTTPも許可します)。
93
+ `resolveExtensionSelection(entries, explicitIds, loadedIds)` はReactなしでも同じ選択集合・依存順を計算します。
94
+ 返り値の `requiredBy` は依存先IDをキー、必要としている明示選択元IDの集合を値とするMapです。
95
+ 推移的依存・共有依存を含め、選択を解除すると依存元の集合も再計算します。
96
+ `loadExtensionCatalog` は任意のAbortSignalを受け付け、認証情報・Refererを送らずに取得し、HTTP失敗や不正なJSON契約を例外として返します。
97
+
98
+ 切り戻しはホストの起動時固定・既定OFFのフラグをOFFにして再読み込みするか、カタログ接続差分をrevertします。
99
+ 既存の3つの実行モードを持つセキュリティ確認は、そのまま利用できます。
100
+
8
101
  ## 公開Editorのスクリーンショット
9
102
 
10
103
  [英語版](./README.md)と日本語版は、同じダイアログの表示言語を切り替え、ラベルと拡張の説明文を各言語で表示しています。
11
- 2026年10月25日の[公開Editor](https://kubohiroya.github.io/turbowarp-extension-data-editor/editor.html?lang=ja)で、
12
- Camera Source 0.19.4・Asset Cache 0.3.2・Bubble 0.13.5を開いた実画面です。
104
+ 全件必須時の自動選択と一括選択欄の非表示に対応した[公開Editor](https://kubohiroya.github.io/turbowarp-extension-data-editor/editor.html?lang=ja)で、
105
+ 2026年10月28日にCamera Source 0.19.4・Asset Cache 0.3.2・Bubble 0.13.5を開いた実画面です。
13
106
 
14
- ![Camera Source・Asset Cache・Bubbleの説明が日本語で表示された確認画面。サンドボックスありは非対応で無効、サンドボックスなしは動作に必要。サンドボックス内では動作しない理由を表示](https://raw.githubusercontent.com/kubohiroya/turbowarp-extension-security-dialog/main/assets/screenshots/localized-descriptions-ja-20261025.png)
107
+ ![Camera Source・Asset Cache・Bubbleの説明が日本語で表示された修正後の確認画面。拒否とサンドボックスありは無効、サンドボックスなしを選択済みで動作に必要と表示。一括選択欄は非表示。OKで読み込むかキャンセルで中止できる](https://raw.githubusercontent.com/kubohiroya/turbowarp-extension-security-dialog/main/assets/screenshots/hidden-bulk-required-ja-20261028.png)
15
108
 
16
- 3拡張とも`Unsandboxed: required`を宣言しています。「サンドボックスあり」は無効化され、
17
- 「この拡張はサンドボックス内では動作しません。」と理由が表示されます。
18
- 「サンドボックスなし」には「動作に必要」と表示します。拒否は選択でき、実行には自分での選択とOKが必要です。
109
+ 3拡張とも`Unsandboxed: required`を宣言しています。「拒否」と「サンドボックスあり」は無効化され、
110
+ 理由が表示されます。「サンドボックスなし」だけが有効で、「動作に必要」と表示します。
111
+ 全拡張がこのモードを必要とする場合、全件のメタデータ取得後に選択済みになり、一括選択欄は非表示になります。
112
+ 「OK」で続行するか、「キャンセル」でプロジェクトの読み込みを中止します。
19
113
  必要なモードの表示は、安全性や配布元の信頼性の認定ではありません。
20
114
 
21
115
  | 機能拡張 | サンドボックスなしが必要な理由 |
@@ -25,7 +119,7 @@ Camera Source 0.19.4・Asset Cache 0.3.2・Bubble 0.13.5を開いた実画面で
25
119
  | Bubble | ホストの実行環境と描画機能へ直接アクセスして、ステージ上に重ねた吹き出しや立ち絵を描画・更新します。 |
26
120
 
27
121
  画像はダイアログ部分をブラウザーで直接撮影したもので、加工していません。
28
- 取得元の版・Editor build・画像hashは[撮影台帳](./assets/screenshots/localized-descriptions-20261025.json)に記録しています。
122
+ 取得元の版・Editor build・画像hashは[撮影台帳](./assets/screenshots/hidden-bulk-required-20261028.json)に記録しています。
29
123
 
30
124
  ## 連動するパッケージ
31
125
 
@@ -79,35 +173,19 @@ flowchart TB
79
173
  1回のプロジェクト読み込みにつき1つのダイアログで、読み込み待ちの拡張URLをすべて並べます。
80
174
  各行には「拒否」「サンドボックスあり」「サンドボックスなし」の3択があり、一括選択は対応する
81
175
  拡張すべてに同じ選択を適用します。見出し・一括選択・OK/キャンセルは常に見えたままで、
82
- 一覧だけがスクロールします。下図では列見出しを「あり」「なし」と省略していますが、
83
- 実際は「サンドボックスあり」「サンドボックスなし」と表示します。
176
+ 一覧だけがスクロールします。
84
177
 
85
- ```
86
- +--------------------------------------------------------------------------+
87
- | 機能拡張セキュリティ |
88
- | 実行方法を選んでください(取得中でも選択できます) |
89
- | 機能拡張の情報:2/3 件を確認 |
90
- | |
91
- | 表示中のすべてに適用: [(x) 拒否] [(o) あり] [(!) なし] |
92
- | そのモードに対応する拡張だけに適用します。 |
93
- | +----------------------------------------------------------------------+ |
94
- | | 機能拡張 | (x) 拒否 | (o) あり | (!) なし | | <- この領域だけが
95
- | +----------------------------------------------------------------------+ | スクロールする
96
- | | [バナー] Fetch | ( ) | 非対応 | (*) | |
97
- | | 作者 ... | ID: fetch | ライセンス: MIT | 更新日時 ... | |
98
- | | (!) この拡張はサンドボックス内では動作しません。 | |
99
- | | サンドボックスなし: 動作に必要 [ 詳細 ] | |
100
- | +----------------------------------------------------------------------+ |
101
- | | [バナー] Storage | (*) | ( ) | ( ) | |
102
- | | メタデータを取得中… [ 詳細 ] | |
103
- | +----------------------------------------------------------------------+ |
104
- | メタデータは作者の自己申告です。 |
105
- | サンドボックスなしの拡張は、プロジェクトやブラウザーの |
106
- | 情報にアクセスできます。 |
107
- | 拒否 1 · あり 0 · なし 1 · 未指定 1 |
108
- | [ キャンセル ] [ OK ] |
109
- +--------------------------------------------------------------------------+
110
- ```
178
+ セキュリティ確認と選択一覧は、内部のパッケージ説明コンポーネントとカテゴリ見出しの処理を共有します。
179
+ 画像を元の縦横比のまま切り取らずに表示し、GitHub/npmリンク・実行要件バッジ・渡されたカテゴリ見出しを共通化しています。
180
+ 両画面とも「詳細」ボタン・ソースコードの一覧内表示はありません。ラジオボタンとチェックボックスは説明の外側、
181
+ 選択状態バッジは共通コンポーネントのスロットに配置します。
182
+
183
+ セキュリティ確認の上部には次の案内を1回表示し、その下にメタデータ取得状況を表示します。
184
+
185
+ > ⚠️マークの表示されている拡張を制作者の意図どおりに動作させるためには『サンドボックスなし』を選択してください。
186
+
187
+ `context="catalog"` の場合だけ、フッター内のボタンより上の独立した行に「『キャンセル』で選択一覧に戻ります。」と表示します。
188
+ プロジェクト読み込みのキャンセル確認は従来の戻り先を維持し、この案内を表示しません。
111
189
 
112
190
  続いて、2種類の確認ダイアログが出ることがあります。
113
191
 
@@ -118,7 +196,7 @@ flowchart TB
118
196
  できない可能性があります。続行しますか?」「いいえ」なら一覧に戻り、何も保存しません。
119
197
 
120
198
  バナーはホバーまたはキーボードフォーカスで原寸プレビューを表示します。画面より大きい画像は
121
- プレビュー枠内をスクロールして確認できます。ソースコードを一覧内に表示するのは「詳細」だけです。
199
+ プレビュー枠内をスクロールして確認できます。両画面のサムネイルは同じ方法で、画像を切り取らずに表示します。
122
200
 
123
201
  ```mermaid
124
202
  sequenceDiagram
@@ -135,7 +213,7 @@ sequenceDiagram
135
213
  A->>A: 保存済みの既定値を読み出す
136
214
  V->>A: 包まれた_loadExtensions
137
215
  A->>D: 読み込み待ちの全件と復元した選択
138
- D-->>U: 1つの一覧、個別と一括の3択、詳細
216
+ D-->>U: 1つの一覧、個別と一括の3択
139
217
  D->>D: メタデータとバナーを非同期に取得
140
218
  U->>D: OK
141
219
  D-->>U: 拒否があるときだけ続行確認
@@ -161,9 +239,9 @@ sequenceDiagram
161
239
 
162
240
  ## 責務
163
241
 
164
- - 一覧比較UI、個別・一括の3択、確認ダイアログ、ソースの詳細表示
242
+ - 一覧比較UI、個別・一括の3択、確認ダイアログ
165
243
  - コードを実行しないメタデータ取得、実バナー/GitHub画像の候補選択、共通バナーへの切替
166
- - 画像・メタデータの非同期更新と独立した選択・詳細の状態保持
244
+ - 画像・メタデータの非同期更新と選択状態の保持
167
245
  - プロジェクト別のIndexedDB保存と初期選択の復元
168
246
  - `./turbowarp` に分離したVM互換アダプター
169
247
 
@@ -172,19 +250,20 @@ ReactとReact DOMは任意のpeer dependencyです。React UIの利用時は両
172
250
  coreとVMアダプターの利用にReact/React DOMは必要ありません。
173
251
 
174
252
  ダイアログ全体の高さをビューポート内に制限し、見出し・一括選択・OK/キャンセルを維持したまま、
175
- 一覧(詳細と注意書きを含む)だけをスクロールします。短い画面高では余白を詰めます。
253
+ 一覧(注意書きを含む)だけをスクロールします。短い画面高では余白を詰めます。
176
254
 
177
255
  ## メタデータとプレビュー
178
256
 
179
- HTTP/HTTPSの出所URLは完全なURLを表示し、別タブで開きます。埋め込み拡張や他のスキームはリンクにしません。
257
+ セキュリティ確認ではHTTP/HTTPSの出所URLを別行に完全なURLで表示し、別タブで開きます。
258
+ 埋め込み拡張や他のスキームはリンクにしません。選択一覧は従来どおりドキュメントURLを表示し、JS配布URLは表示しません。
180
259
  ソース先頭の宣言コメントに `// Updated: 2026-10-19T10:30:00+09:00` などの更新日時がある場合、
181
260
  記載値をそのまま表示します。`Updated at` / `Updated-at` / `UpdatedAt` / `Last updated` / `Last-updated` /
182
261
  `Last modified` / `Last-modified` も同じ項目です。カスタム `loadInfo` は `metadata.updatedAt` を返せます。
183
262
  記載がなければ日時は表示せず、HTTPの取得日時やファイル時刻で補いません。
184
263
 
185
264
  バナーはホバーまたはキーボードフォーカスで原寸プレビューを表示します。画面より大きい画像は
186
- プレビュー枠内をスクロールして確認できます。ポインターを外すかEscapeで閉じ、選択や詳細状態を保持します。
187
- メタデータの非同期取得中も実行方法を選べます。ソースの一覧内表示は引き続き「詳細」を押したときだけです。
265
+ プレビュー枠内をスクロールして確認できます。ポインターを外すかEscapeで閉じ、選択状態を保持します。
266
+ メタデータの非同期取得中も実行方法を選べます。取得処理は宣言コメントの確認に使用し、コードを実行しません。
188
267
 
189
268
  ### 機能拡張の説明文の言語
190
269
 
@@ -207,12 +286,15 @@ HTTP/HTTPSの出所URLは完全なURLを表示し、別タブで開きます。
207
286
  個別選択・一括選択・一覧の見出しは、禁止アイコンの「拒否」、盾の「サンドボックスあり」、
208
287
  警告の「サンドボックスなし」の順です。アイコンと色は文字ラベルを補助し、安全性の認定には使いません。
209
288
 
210
- 先頭の宣言コメントに `// Unsandboxed: required` があれば、「サンドボックスあり」を無効化して
211
- 動作しない理由を表示し、「サンドボックスなし」に「動作に必要」を付けます。拒否は選択できます。
289
+ 先頭の宣言コメントに `// Unsandboxed: required` があれば、「拒否」と「サンドボックスあり」を無効化して
290
+ 理由を表示し、選択できる唯一のモード「サンドボックスなし」に「動作に必要」を付けます。
291
+ 選択したモードを「OK」で承認するか、「キャンセル」でプロジェクトの読み込みを中止します。
212
292
  この宣言は作者の自己申告であり、未宣言・取得失敗から必須モードを推測しません。
213
293
 
214
- 実行する選択の確定はメタデータ取得の完了または失敗後です。遅れて取得した宣言に対応しない選択は、
215
- 保存済みの復元値も含めて解除し、選び直しを案内します。権限の広いモードへ自動で変更しません。
294
+ 「拒否」を含む選択の確定はメタデータ取得の完了または失敗後です。全拡張の取得が成功し、すべてが
295
+ この必須モードを宣言していれば、非対応の保存済み選択も含めて「サンドボックスなし」を選択済みにします。
296
+ 「OK」を押すまで拡張は実行せず、「キャンセル」で中止できます。取得中・未宣言・任意指定・取得失敗が
297
+ 1件でもあれば、この一括初期選択は行いません。混在する一覧では、非対応の選択を解除して選び直しを案内します。
216
298
  一括選択は対応する拡張だけに適用し、全件が非対応の一括ボタンは無効化します。
217
299
 
218
300
  ## 接続例
package/README.md CHANGED
@@ -12,14 +12,15 @@ Related tasks and acceptance criteria are tracked in
12
12
  [English](./README.md) and [Japanese](./README.ja.md) use the same dialog with localized labels and extension descriptions.
13
13
  This capture shows Camera Source 0.19.4, Asset Cache 0.3.2 and Bubble 0.13.5 in the
14
14
  [public Editor](https://kubohiroya.github.io/turbowarp-extension-data-editor/editor.html?lang=en)
15
- on 25 October 2026.
15
+ on 28 October 2026, with **Without sandbox** already selected for all three extensions and the unnecessary bulk selection section hidden.
16
16
 
17
- ![English descriptions for Camera Source, Asset Cache and Bubble: With sandbox is disabled as Unsupported for all three extensions; Without sandbox is marked Required to run, with the reason This extension cannot run inside the sandbox.](https://raw.githubusercontent.com/kubohiroya/turbowarp-extension-security-dialog/main/assets/screenshots/localized-descriptions-en-20261025.png)
17
+ ![English descriptions for Camera Source, Asset Cache and Bubble: Deny and With sandbox are disabled for all three extensions; Without sandbox is preselected and marked Required to run. The bulk selection section is hidden. Choose OK to load the project or Cancel to stop.](https://raw.githubusercontent.com/kubohiroya/turbowarp-extension-security-dialog/main/assets/screenshots/hidden-bulk-required-en-20261028.png)
18
18
 
19
- All three extensions declare `Unsandboxed: required`. **With sandbox** is disabled, with
20
- **This extension cannot run inside the sandbox.** shown as the reason. **Without sandbox**
21
- is marked **Required to run**. Deny remains available, and running still requires an explicit
22
- choice and OK. These labels describe execution requirements, not a safety certification.
19
+ All three extensions declare `Unsandboxed: required`. **Deny** and **With sandbox** are
20
+ disabled, with the reason shown. **Without sandbox** is enabled and marked **Required to run**.
21
+ When every listed extension requires this mode, it is preselected after all metadata loads, and the bulk selection section is hidden.
22
+ Press OK to continue, or **Cancel** to stop loading the project.
23
+ These labels describe execution requirements, not a safety certification.
23
24
 
24
25
  | Extension | Why it needs to run without a sandbox |
25
26
  | --- | --- |
@@ -28,7 +29,7 @@ choice and OK. These labels describe execution requirements, not a safety certif
28
29
  | Bubble | Accesses the host runtime and renderer directly to draw and update layered speech bubbles and portraits on the stage. |
29
30
 
30
31
  The PNG is an unmodified, modal-only browser capture. Source versions, Editor build and image
31
- hashes are recorded in [the capture manifest](./assets/screenshots/localized-descriptions-20261025.json).
32
+ hashes are recorded in [the capture manifest](./assets/screenshots/hidden-bulk-required-20261028.json).
32
33
 
33
34
  ## How it fits together
34
35
 
@@ -84,32 +85,17 @@ three choices — **Deny**, **With sandbox**, **Without sandbox** — and a bulk
84
85
  one choice to every listed extension that supports it. The heading, the bulk row and the
85
86
  OK/Cancel buttons stay visible; only the list scrolls, so the dialog always fits the viewport.
86
87
 
87
- ```
88
- +--------------------------------------------------------------------+
89
- | Extension Security |
90
- | Choose how to run each extension (you can choose while metadata |
91
- | loads). Extension information: 2/3 |
92
- | |
93
- | Apply to all listed: [(x) Deny] [(o) With sandbox] [(!) Without] |
94
- | Applies only to extensions that support this mode. |
95
- | +----------------------------------------------------------------+ |
96
- | | Extension | (x) Deny | (o) With | (!) Without | | <- only this
97
- | +----------------------------------------------------------------+ | area scrolls
98
- | | [banner] Fetch | ( ) | Unsupported | (*) | |
99
- | | Author: ... | ID: fetch | License: MIT | Updated: ... | |
100
- | | (!) This extension cannot run inside the sandbox. | |
101
- | | Without sandbox: Required to run [ Details ] | |
102
- | +----------------------------------------------------------------+ |
103
- | | [banner] Storage | (*) | ( ) | ( ) | |
104
- | | Getting metadata... [ Details ] | |
105
- | +----------------------------------------------------------------+ |
106
- | Metadata is provided by the author. |
107
- | Extensions without a sandbox can access your project and browser |
108
- | information. |
109
- | Deny 1 · With 0 · Without 1 · Unselected 1 |
110
- | [ Cancel ] [ OK ] |
111
- +--------------------------------------------------------------------+
112
- ```
88
+ The security dialog and selection list use the same internal package-description renderer
89
+ and category-section helper. They share uncropped images at their original aspect ratio,
90
+ GitHub/npm service links, execution-requirement badges and supplied category headings.
91
+ Neither view includes a Details button or inline source code. Radio buttons and checkboxes
92
+ remain outside the description; selection-state badges use a slot in the shared renderer.
93
+
94
+ The security dialog explains the warning badge once above the list: “To make extensions
95
+ marked ⚠️ work as their creators intended, choose Without sandbox.” Metadata progress
96
+ appears below it. With `context="catalog"`, a separate footer row above the buttons says
97
+ “Choose Cancel to return to the selection list.” Project context retains its own cancellation
98
+ confirmation and does not show that destination.
113
99
 
114
100
  Two confirmation dialogs can follow:
115
101
 
@@ -120,8 +106,7 @@ Two confirmation dialogs can follow:
120
106
  when it runs. Continue?" Answering *No* returns to the list and saves nothing.
121
107
 
122
108
  Hovering or keyboard-focusing a banner opens a full-size preview; images larger than the
123
- screen scroll inside the preview frame. *Details* is the only thing that shows extension
124
- source code inline.
109
+ screen scroll inside the preview frame. Thumbnails use the same uncropped display in both views.
125
110
 
126
111
  ```mermaid
127
112
  sequenceDiagram
@@ -138,7 +123,7 @@ sequenceDiagram
138
123
  A->>A: read saved per-project defaults
139
124
  V->>A: wrapped _loadExtensions with ids and urls
140
125
  A->>D: all pending entries plus restored choices
141
- D-->>U: one list, per-row and bulk choices, Details
126
+ D-->>U: one list, per-row and bulk choices
142
127
  D->>D: metadata and banners arrive asynchronously
143
128
  U->>D: OK
144
129
  D-->>U: continue-with-denied confirmation, only if anything is denied
@@ -164,10 +149,10 @@ implementation. The author would be glad to see it made redundant by TurboWarp E
164
149
 
165
150
  ## Responsibilities
166
151
 
167
- - Comparison list UI, per-row and bulk three-way choice, confirmation dialogs, source detail view
152
+ - Comparison list UI, per-row and bulk three-way choice, confirmation dialogs
168
153
  - Metadata retrieval that never executes extension code, candidate selection between the real
169
154
  banner and GitHub images, fallback to a common banner
170
- - Asynchronous image and metadata updates that keep selection and detail state independent
155
+ - Asynchronous image and metadata updates that preserve selection
171
156
  - Per-project IndexedDB storage and restoration of initial choices
172
157
  - A VM compatibility adapter, isolated in `./turbowarp`
173
158
 
@@ -176,13 +161,14 @@ after a cancel. React and React DOM are optional peer dependencies; supply both
176
161
  the React UI. Neither is needed for the core or the VM adapter.
177
162
 
178
163
  The dialog's total height is constrained to the viewport. The heading, bulk choice and
179
- OK/Cancel stay in place while only the list — including details and notices — scrolls.
164
+ OK/Cancel stay in place while only the list — including notices — scrolls.
180
165
  Spacing tightens on short viewports.
181
166
 
182
167
  ## Metadata and previews
183
168
 
184
- HTTP/HTTPS origin URLs are shown in full and open in a new tab. Embedded extensions and other
185
- schemes are not linked.
169
+ The security dialog retains its HTTP/HTTPS source-origin URL as a separate provenance line,
170
+ opening in a new tab. Embedded extensions and other schemes are not linked. The selection
171
+ list keeps its documentation URL instead; it never displays the JavaScript distribution URL.
186
172
 
187
173
  If the leading declaration comment in the source carries an update timestamp such as
188
174
  `// Updated: 2026-10-19T10:30:00+09:00`, the written value is displayed verbatim.
@@ -222,15 +208,19 @@ Per-row choices, the bulk choices and the list heading are ordered: **Deny** (pr
222
208
  icon), **With sandbox** (shield), **Without sandbox** (warning). Icons and colour support the
223
209
  text labels; they are not a safety certification.
224
210
 
225
- If the leading declaration comment contains `// Unsandboxed: required`, *With sandbox* is
226
- disabled with the reason shown, and *Without sandbox* is marked *Required to run*. Deny stays
227
- selectable. This declaration is the author's own claim; a required mode is never inferred from
211
+ If the leading declaration comment contains `// Unsandboxed: required`, *Deny* and *With sandbox*
212
+ are disabled with the reason shown, and *Without sandbox* is the only available mode, marked
213
+ *Required to run*. Press OK to approve the selected modes, or Cancel to stop loading
214
+ the project. This declaration is the author's own claim; a required mode is never inferred from
228
215
  a missing declaration or a failed fetch.
229
216
 
230
- A choice to run is only committed once metadata has loaded or failed. A selection that
231
- contradicts a late-arriving declaration is cleared — including a restored saved value — and
232
- the user is asked to choose again. The mode is never silently widened. A bulk choice applies
233
- only to extensions that support it, and a bulk button is disabled when no listed extension does.
217
+ A choice, including Deny, is only committed once metadata has loaded or failed. When every
218
+ listed extension has loaded metadata declaring this requirement, *Without sandbox* is
219
+ preselected for all entries, including entries with incompatible saved choices. Nothing runs
220
+ until the user presses OK; Cancel still stops loading the project. Pending, missing, optional
221
+ or failed declarations prevent this batch default. In mixed batches, incompatible choices
222
+ are cleared and the user is asked to choose again. A bulk choice applies only to extensions
223
+ that support it, and a bulk button is disabled when no listed extension does.
234
224
 
235
225
  ## Wiring it up
236
226
 
@@ -251,6 +241,124 @@ surfacing as a VM error is identified with `isExtensionSecurityCancelled(error)`
251
241
  Under Webpack 4 with CSS Modules, load `webpack4.css` instead of `styles.css`; root-level
252
242
  compatibility entries resolve for older Webpack 4 setups that do not read package exports.
253
243
 
244
+ ## Selecting extensions from a Pages catalog
245
+
246
+ `ExtensionSelectionList` shares the security dialog's banners and metadata,
247
+ with one checkbox at the right of each row. This API supports the TurboWarp Plus library
248
+ tracked in [#28](https://github.com/kubohiroya/turbowarp-extension-security-dialog/issues/28).
249
+ The host fetches a versioned JSON catalog over HTTPS:
250
+
251
+ ```jsx
252
+ import {loadExtensionCatalog} from '@kubohiroya/turbowarp-extension-security-dialog';
253
+ import {ExtensionSelectionList} from '@kubohiroya/turbowarp-extension-security-dialog/react';
254
+
255
+ const controller = new AbortController();
256
+ const entries = await loadExtensionCatalog(
257
+ 'https://kubohiroya.github.io/turbowarp-plus-packages/extensions-v1.json',
258
+ controller.signal
259
+ );
260
+
261
+ const list = <ExtensionSelectionList entries={entries} locale="en"
262
+ filterQuery={searchText} loadedIds={loadedExtensionIds} busy={loading}
263
+ onCancel={closeLibrary}
264
+ onComplete={ordered => host.reviewAndLoadInOrder(ordered)} />;
265
+ ```
266
+
267
+ `host.reviewAndLoadInOrder` represents the host's permission review and VM loading path.
268
+ The callback receives dependencies before their dependants, each once, excluding
269
+ `loadedIds`. Selecting an extension checks and disables all transitive dependencies.
270
+ Removing its selection recomputes the closure; dependencies remain checked if another
271
+ selection needs them or the user selected them explicitly. Loaded rows are checked and
272
+ disabled. Search and locale changes preserve selection. `busy` disables selection and the
273
+ footer controls. The host owns fetch errors, retry, catalog cancellation, VM errors, and
274
+ updating `loadedIds` after each successful load.
275
+
276
+ Rows distinguish **Selected by you** (blue), **Selected automatically** (purple), and
277
+ **Not selected** (neutral), using a background, left border, icon and label together.
278
+ Already loaded rows have their own label and accent. A legend explains the states above
279
+ the list. Automatically selected dependencies name every selected root that needs them,
280
+ for example “Required by Bubble, Sprite”. An explicitly selected dependency keeps its
281
+ “Selected by you” state while another root requires it; its checkbox stays disabled and
282
+ the dependency reason is also shown. The row's `data-selection-state` is `selected`,
283
+ `dependency`, `unselected` or `loaded`.
284
+
285
+ Optional catalog categories render as semantic `h2` sections in dashboard order. Japanese
286
+ uses `titleJa` when available, otherwise `title`; other locales use `title`. Search hides
287
+ empty sections without changing selection. Catalogs without categories
288
+ keep a flat list. If categorized and uncategorized entries are mixed, the latter appear
289
+ under “Other extensions” at the end. Theme colors use the host's modal background and
290
+ foreground; accent overrides are `--twextsec-manual-accent`, `--twextsec-dependency-accent`,
291
+ `--twextsec-unselected-accent`, and `--twextsec-loaded-accent`.
292
+
293
+ Package selection states and dependency reasons appear below the preview image. The heading places the name, version, parenthesized ID and GitHub/npm icons in that order. Items after the name use regular weight and a font size 2pt smaller than the name, wrapping as needed.
294
+
295
+ The selection list never loads or runs extension code. Catalog metadata renders immediately.
296
+ It shows the verified GitHub Pages `docsURL`, and GitHub/ npm icon links to the repository
297
+ and package page. Neither screen has a Details control or inline source; the JavaScript
298
+ distribution URL remains confined to the security dialog’s provenance line.
299
+ Creator names use `authorURL` only when explicitly supplied by the published package.json
300
+ `author.url`. Every row discloses its unsandboxed requirement as required, optional, not needed
301
+ or not confirmed; required mode includes a warning icon. `ExtensionSecurityDialog context="catalog"` provides permission review with cancel
302
+ wording that returns to this list; its default `context="project"` retains project wording.
303
+ The host must respect the committed execution modes and its own security policy.
304
+
305
+ For shared images, service links and execution requirements, optional `entry.metadata`
306
+ complements the fetched source metadata. If either declares `unsandboxed: required`, the
307
+ shared badge, allowed choices, invalidation and batch defaults all honor that requirement.
308
+ Security still waits for source metadata to settle (success or failure) before accepting OK;
309
+ fetching declarations never executes the code. Its source-header version, plain creator
310
+ label and source provenance stay as before. Selection keeps catalog versions, explicit
311
+ creator links and documentation links. Those unrequested presentation differences are not
312
+ changed by the shared renderer. Supplied `entry.category` is rendered in either view;
313
+ category-free project entries stay flat without any catalog lookup or inferred category.
314
+
315
+
316
+ The Pages document has the following contract (`schemaVersion: 1`):
317
+
318
+ ```json
319
+ {
320
+ "schemaVersion": 1,
321
+ "categories": [{"id": "camera", "title": "Camera", "titleJa": "カメラ"}],
322
+ "extensions": [
323
+ {
324
+ "id": "cameraSource",
325
+ "name": "Camera Source",
326
+ "category": "camera",
327
+ "version": "1.2.3",
328
+ "package": "@example/camera-source",
329
+ "url": "https://cdn.jsdelivr.net/npm/@example/camera-source@1.2.3/dist/extension.js",
330
+ "description": "Share a camera stream.",
331
+ "descriptions": {"ja": "カメラ映像を共有します。"},
332
+ "repository": "https://github.com/example/camera-source",
333
+ "banner": "https://example.com/camera-source.svg",
334
+ "unsandboxed": "required",
335
+ "dependencies": []
336
+ }
337
+ ]
338
+ }
339
+ ```
340
+
341
+ IDs contain ASCII letters and digits. `name`, `version`, `url`, and `dependencies` are
342
+ required. Dependencies are extension IDs in this document, not npm package names;
343
+ the generator resolves package dependencies to these IDs. `package`, descriptions, author,
344
+ license, banner, repository and execution requirement are optional metadata. The generator
345
+ uses version-pinned, published distribution URLs and excludes build-only packages.
346
+ `parseExtensionCatalog` rejects unsupported schemas, duplicate IDs/URLs, missing dependencies,
347
+ cycles, and non-HTTPS or credential-bearing URLs before the UI or VM receives entries.
348
+ `resolveExtensionSelection(entries, explicitIds, loadedIds)` exposes the same closure and
349
+ load order independently of React. Its `requiredBy` map associates each dependency ID with
350
+ a set of the explicit root IDs that require it, including transitive and shared dependencies.
351
+ Optional `categories: [{id, title, titleJa?}]` are declared once, in dashboard order;
352
+ `extensions[].category` references one of those IDs. Duplicate category IDs, invalid
353
+ definitions and unknown references are rejected. `parseExtensionCatalog` retains its array
354
+ return type and resolves each reference to `entry.category: {id, title, titleJa?, order}`.
355
+ `loadExtensionCatalog` accepts an optional AbortSignal,
356
+ omits credentials/referrers, and rejects failed HTTP responses or invalid JSON contracts.
357
+
358
+ To roll back catalog integration, turn off the host's startup flag (off by default) and
359
+ reload, or revert the catalog wiring. The existing three-way security dialog remains
360
+ available without the catalog API.
361
+
254
362
  ## Stored preferences
255
363
 
256
364
  Preferences are saved only when OK was pressed **and** the project then opened successfully.