@kubohiroya/turbowarp-extension-loader 0.0.0-stage → 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,373 @@
1
+ Mozilla Public License Version 2.0
2
+ ==================================
3
+
4
+ 1. Definitions
5
+ --------------
6
+
7
+ 1.1. "Contributor"
8
+ means each individual or legal entity that creates, contributes to
9
+ the creation of, or owns Covered Software.
10
+
11
+ 1.2. "Contributor Version"
12
+ means the combination of the Contributions of others (if any) used
13
+ by a Contributor and that particular Contributor's Contribution.
14
+
15
+ 1.3. "Contribution"
16
+ means Covered Software of a particular Contributor.
17
+
18
+ 1.4. "Covered Software"
19
+ means Source Code Form to which the initial Contributor has attached
20
+ the notice in Exhibit A, the Executable Form of such Source Code
21
+ Form, and Modifications of such Source Code Form, in each case
22
+ including portions thereof.
23
+
24
+ 1.5. "Incompatible With Secondary Licenses"
25
+ means
26
+
27
+ (a) that the initial Contributor has attached the notice described
28
+ in Exhibit B to the Covered Software; or
29
+
30
+ (b) that the Covered Software was made available under the terms of
31
+ version 1.1 or earlier of the License, but not also under the
32
+ terms of a Secondary License.
33
+
34
+ 1.6. "Executable Form"
35
+ means any form of the work other than Source Code Form.
36
+
37
+ 1.7. "Larger Work"
38
+ means a work that combines Covered Software with other material, in
39
+ a separate file or files, that is not Covered Software.
40
+
41
+ 1.8. "License"
42
+ means this document.
43
+
44
+ 1.9. "Licensable"
45
+ means having the right to grant, to the maximum extent possible,
46
+ whether at the time of the initial grant or subsequently, any and
47
+ all of the rights conveyed by this License.
48
+
49
+ 1.10. "Modifications"
50
+ means any of the following:
51
+
52
+ (a) any file in Source Code Form that results from an addition to,
53
+ deletion from, or modification of the contents of Covered
54
+ Software; or
55
+
56
+ (b) any new file in Source Code Form that contains any Covered
57
+ Software.
58
+
59
+ 1.11. "Patent Claims" of a Contributor
60
+ means any patent claim(s), including without limitation, method,
61
+ process, and apparatus claims, in any patent Licensable by such
62
+ Contributor that would be infringed, but for the grant of the
63
+ License, by the making, using, selling, offering for sale, having
64
+ made, import, or transfer of either its Contributions or its
65
+ Contributor Version.
66
+
67
+ 1.12. "Secondary License"
68
+ means either the GNU General Public License, Version 2.0, the GNU
69
+ Lesser General Public License, Version 2.1, the GNU Affero General
70
+ Public License, Version 3.0, or any later versions of those
71
+ licenses.
72
+
73
+ 1.13. "Source Code Form"
74
+ means the form of the work preferred for making modifications.
75
+
76
+ 1.14. "You" (or "Your")
77
+ means an individual or a legal entity exercising rights under this
78
+ License. For legal entities, "You" includes any entity that
79
+ controls, is controlled by, or is under common control with You. For
80
+ purposes of this definition, "control" means (a) the power, direct
81
+ or indirect, to cause the direction or management of such entity,
82
+ whether by contract or otherwise, or (b) ownership of more than
83
+ fifty percent (50%) of the outstanding shares or beneficial
84
+ ownership of such entity.
85
+
86
+ 2. License Grants and Conditions
87
+ --------------------------------
88
+
89
+ 2.1. Grants
90
+
91
+ Each Contributor hereby grants You a world-wide, royalty-free,
92
+ non-exclusive license:
93
+
94
+ (a) under intellectual property rights (other than patent or trademark)
95
+ Licensable by such Contributor to use, reproduce, make available,
96
+ modify, display, perform, distribute, and otherwise exploit its
97
+ Contributions, either on an unmodified basis, with Modifications, or
98
+ as part of a Larger Work; and
99
+
100
+ (b) under Patent Claims of such Contributor to make, use, sell, offer
101
+ for sale, have made, import, and otherwise transfer either its
102
+ Contributions or its Contributor Version.
103
+
104
+ 2.2. Effective Date
105
+
106
+ The licenses granted in Section 2.1 with respect to any Contribution
107
+ become effective for each Contribution on the date the Contributor first
108
+ distributes such Contribution.
109
+
110
+ 2.3. Limitations on Grant Scope
111
+
112
+ The licenses granted in this Section 2 are the only rights granted under
113
+ this License. No additional rights or licenses will be implied from the
114
+ distribution or licensing of Covered Software under this License.
115
+ Notwithstanding Section 2.1(b) above, no patent license is granted by a
116
+ Contributor:
117
+
118
+ (a) for any code that a Contributor has removed from Covered Software;
119
+ or
120
+
121
+ (b) for infringements caused by: (i) Your and any other third party's
122
+ modifications of Covered Software, or (ii) the combination of its
123
+ Contributions with other software (except as part of its Contributor
124
+ Version); or
125
+
126
+ (c) under Patent Claims infringed by Covered Software in the absence of
127
+ its Contributions.
128
+
129
+ This License does not grant any rights in the trademarks, service marks,
130
+ or logos of any Contributor (except as may be necessary to comply with
131
+ the notice requirements in Section 3.4).
132
+
133
+ 2.4. Subsequent Licenses
134
+
135
+ No Contributor makes additional grants as a result of Your choice to
136
+ distribute the Covered Software under a subsequent version of this
137
+ License (see Section 10.2) or under the terms of a Secondary License (if
138
+ permitted under the terms of Section 3.3).
139
+
140
+ 2.5. Representation
141
+
142
+ Each Contributor represents that the Contributor believes its
143
+ Contributions are its original creation(s) or it has sufficient rights
144
+ to grant the rights to its Contributions conveyed by this License.
145
+
146
+ 2.6. Fair Use
147
+
148
+ This License is not intended to limit any rights You have under
149
+ applicable copyright doctrines of fair use, fair dealing, or other
150
+ equivalents.
151
+
152
+ 2.7. Conditions
153
+
154
+ Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
155
+ in Section 2.1.
156
+
157
+ 3. Responsibilities
158
+ -------------------
159
+
160
+ 3.1. Distribution of Source Form
161
+
162
+ All distribution of Covered Software in Source Code Form, including any
163
+ Modifications that You create or to which You contribute, must be under
164
+ the terms of this License. You must inform recipients that the Source
165
+ Code Form of the Covered Software is governed by the terms of this
166
+ License, and how they can obtain a copy of this License. You may not
167
+ attempt to alter or restrict the recipients' rights in the Source Code
168
+ Form.
169
+
170
+ 3.2. Distribution of Executable Form
171
+
172
+ If You distribute Covered Software in Executable Form then:
173
+
174
+ (a) such Covered Software must also be made available in Source Code
175
+ Form, as described in Section 3.1, and You must inform recipients of
176
+ the Executable Form how they can obtain a copy of such Source Code
177
+ Form by reasonable means in a timely manner, at a charge no more
178
+ than the cost of distribution to the recipient; and
179
+
180
+ (b) You may distribute such Executable Form under the terms of this
181
+ License, or sublicense it under different terms, provided that the
182
+ license for the Executable Form does not attempt to limit or alter
183
+ the recipients' rights in the Source Code Form under this License.
184
+
185
+ 3.3. Distribution of a Larger Work
186
+
187
+ You may create and distribute a Larger Work under terms of Your choice,
188
+ provided that You also comply with the requirements of this License for
189
+ the Covered Software. If the Larger Work is a combination of Covered
190
+ Software with a work governed by one or more Secondary Licenses, and the
191
+ Covered Software is not Incompatible With Secondary Licenses, this
192
+ License permits You to additionally distribute such Covered Software
193
+ under the terms of such Secondary License(s), so that the recipient of
194
+ the Larger Work may, at their option, further distribute the Covered
195
+ Software under the terms of either this License or such Secondary
196
+ License(s).
197
+
198
+ 3.4. Notices
199
+
200
+ You may not remove or alter the substance of any license notices
201
+ (including copyright notices, patent notices, disclaimers of warranty,
202
+ or limitations of liability) contained within the Source Code Form of
203
+ the Covered Software, except that You may alter any license notices to
204
+ the extent required to remedy known factual inaccuracies.
205
+
206
+ 3.5. Application of Additional Terms
207
+
208
+ You may choose to offer, and to charge a fee for, warranty, support,
209
+ indemnity or liability obligations to one or more recipients of Covered
210
+ Software. However, You may do so only on Your own behalf, and not on
211
+ behalf of any Contributor. You must make it absolutely clear that any
212
+ such warranty, support, indemnity, or liability obligation is offered by
213
+ You alone, and You hereby agree to indemnify every Contributor for any
214
+ liability incurred by such Contributor as a result of warranty, support,
215
+ indemnity or liability terms You offer. You may include additional
216
+ disclaimers of warranty and limitations of liability specific to any
217
+ jurisdiction.
218
+
219
+ 4. Inability to Comply Due to Statute or Regulation
220
+ ---------------------------------------------------
221
+
222
+ If it is impossible for You to comply with any of the terms of this
223
+ License with respect to some or all of the Covered Software due to
224
+ statute, judicial order, or regulation then You must: (a) comply with
225
+ the terms of this License to the maximum extent possible; and (b)
226
+ describe the limitations and the code they affect. Such description must
227
+ be placed in a text file included with all distributions of the Covered
228
+ Software under this License. Except to the extent prohibited by statute
229
+ or regulation, such description must be sufficiently detailed for a
230
+ recipient of ordinary skill to be able to understand it.
231
+
232
+ 5. Termination
233
+ --------------
234
+
235
+ 5.1. The rights granted under this License will terminate automatically
236
+ if You fail to comply with any of its terms. However, if You become
237
+ compliant, then the rights granted under this License from a particular
238
+ Contributor are reinstated (a) provisionally, unless and until such
239
+ Contributor explicitly and finally terminates Your grants, and (b) on an
240
+ ongoing basis, if such Contributor fails to notify You of the
241
+ non-compliance by some reasonable means prior to 60 days after You have
242
+ come back into compliance. Moreover, Your grants from a particular
243
+ Contributor are reinstated on an ongoing basis if such Contributor
244
+ notifies You of the non-compliance by some reasonable means, this is the
245
+ first time You have received notice of non-compliance with this License
246
+ from such Contributor, and You become compliant prior to 30 days after
247
+ Your receipt of the notice.
248
+
249
+ 5.2. If You initiate litigation against any entity by asserting a patent
250
+ infringement claim (excluding declaratory judgment actions,
251
+ counter-claims, and cross-claims) alleging that a Contributor Version
252
+ directly or indirectly infringes any patent, then the rights granted to
253
+ You by any and all Contributors for the Covered Software under Section
254
+ 2.1 of this License shall terminate.
255
+
256
+ 5.3. In the event of termination under Sections 5.1 or 5.2 above, all
257
+ end user license agreements (excluding distributors and resellers) which
258
+ have been validly granted by You or Your distributors under this License
259
+ prior to termination shall survive termination.
260
+
261
+ ************************************************************************
262
+ * *
263
+ * 6. Disclaimer of Warranty *
264
+ * ------------------------- *
265
+ * *
266
+ * Covered Software is provided under this License on an "as is" *
267
+ * basis, without warranty of any kind, either expressed, implied, or *
268
+ * statutory, including, without limitation, warranties that the *
269
+ * Covered Software is free of defects, merchantable, fit for a *
270
+ * particular purpose or non-infringing. The entire risk as to the *
271
+ * quality and performance of the Covered Software is with You. *
272
+ * Should any Covered Software prove defective in any respect, You *
273
+ * (not any Contributor) assume the cost of any necessary servicing, *
274
+ * repair, or correction. This disclaimer of warranty constitutes an *
275
+ * essential part of this License. No use of any Covered Software is *
276
+ * authorized under this License except under this disclaimer. *
277
+ * *
278
+ ************************************************************************
279
+
280
+ ************************************************************************
281
+ * *
282
+ * 7. Limitation of Liability *
283
+ * -------------------------- *
284
+ * *
285
+ * Under no circumstances and under no legal theory, whether tort *
286
+ * (including negligence), contract, or otherwise, shall any *
287
+ * Contributor, or anyone who distributes Covered Software as *
288
+ * permitted above, be liable to You for any direct, indirect, *
289
+ * special, incidental, or consequential damages of any character *
290
+ * including, without limitation, damages for lost profits, loss of *
291
+ * goodwill, work stoppage, computer failure or malfunction, or any *
292
+ * and all other commercial damages or losses, even if such party *
293
+ * shall have been informed of the possibility of such damages. This *
294
+ * limitation of liability shall not apply to liability for death or *
295
+ * personal injury resulting from such party's negligence to the *
296
+ * extent applicable law prohibits such limitation. Some *
297
+ * jurisdictions do not allow the exclusion or limitation of *
298
+ * incidental or consequential damages, so this exclusion and *
299
+ * limitation may not apply to You. *
300
+ * *
301
+ ************************************************************************
302
+
303
+ 8. Litigation
304
+ -------------
305
+
306
+ Any litigation relating to this License may be brought only in the
307
+ courts of a jurisdiction where the defendant maintains its principal
308
+ place of business and such litigation shall be governed by laws of that
309
+ jurisdiction, without reference to its conflict-of-law provisions.
310
+ Nothing in this Section shall prevent a party's ability to bring
311
+ cross-claims or counter-claims.
312
+
313
+ 9. Miscellaneous
314
+ ----------------
315
+
316
+ This License represents the complete agreement concerning the subject
317
+ matter hereof. If any provision of this License is held to be
318
+ unenforceable, such provision shall be reformed only to the extent
319
+ necessary to make it enforceable. Any law or regulation which provides
320
+ that the language of a contract shall be construed against the drafter
321
+ shall not be used to construe this License against a Contributor.
322
+
323
+ 10. Versions of the License
324
+ ---------------------------
325
+
326
+ 10.1. New Versions
327
+
328
+ Mozilla Foundation is the license steward. Except as provided in Section
329
+ 10.3, no one other than the license steward has the right to modify or
330
+ publish new versions of this License. Each version will be given a
331
+ distinguishing version number.
332
+
333
+ 10.2. Effect of New Versions
334
+
335
+ You may distribute the Covered Software under the terms of the version
336
+ of the License under which You originally received the Covered Software,
337
+ or under the terms of any subsequent version published by the license
338
+ steward.
339
+
340
+ 10.3. Modified Versions
341
+
342
+ If you create software not governed by this License, and you want to
343
+ create a new license for such software, you may create and use a
344
+ modified version of this License if you rename the license and remove
345
+ any references to the name of the license steward (except to note that
346
+ such modified license differs from this License).
347
+
348
+ 10.4. Distributing Source Code Form that is Incompatible With Secondary
349
+ Licenses
350
+
351
+ If You choose to distribute Source Code Form that is Incompatible With
352
+ Secondary Licenses under the terms of this version of the License, the
353
+ notice described in Exhibit B of this License must be attached.
354
+
355
+ Exhibit A - Source Code Form License Notice
356
+ -------------------------------------------
357
+
358
+ This Source Code Form is subject to the terms of the Mozilla Public
359
+ License, v. 2.0. If a copy of the MPL was not distributed with this
360
+ file, You can obtain one at https://mozilla.org/MPL/2.0/.
361
+
362
+ If it is not possible or desirable to put the notice in a particular
363
+ file, then You may include the notice in a location (such as a LICENSE
364
+ file in a relevant directory) where a recipient would be likely to look
365
+ for such a notice.
366
+
367
+ You may add additional accurate notices of copyright ownership.
368
+
369
+ Exhibit B - "Incompatible With Secondary Licenses" Notice
370
+ ---------------------------------------------------------
371
+
372
+ This Source Code Form is "Incompatible With Secondary Licenses", as
373
+ defined by the Mozilla Public License, v. 2.0.
package/README.md CHANGED
@@ -1,3 +1,165 @@
1
- # Temporary Holding Version
1
+ # turbowarp-extension-loader
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ [Editor Issue #4](https://github.com/kubohiroya/turbowarp-plus-editor/issues/4) の GUI 非依存コアです。MPL-2.0 で npm(`@kubohiroya/turbowarp-extension-loader`)に公開します。既存の配布ライブラリや npm パッケージを置き換えません。
4
+
5
+ ## 実装範囲
6
+
7
+ - `project.json` の独自フィールド `turboWarpPlus` に schema v1 の Manifest を配置します。標準 SB3 仕様ではありません。
8
+ - Manifest の厳格検証、未知フィールド拒否、重複・標準拡張 ID 拒否、依存順、循環・欠落依存拒否。
9
+ - 拡張ごとの Embedded / Remote 解決、SHA-256 必須固定、UTF-8 検証、コードごと・全体のサイズ上限。
10
+ - SHA-256 キーのキャッシュポート。読み出すたびに exact bytes を再検証し、キャッシュ利用時もホストの認可を要求します。
11
+ - 明示的なホスト認可後、全拡張の検証・認可が揃ってから登録を始めます。登録 ID 不一致・登録失敗はホスト transaction の rollback を要求します。
12
+ - キャンセル、取得・認可のタイムアウト、重複ロード拒否、unload、診断イベント。
13
+
14
+ 標準拡張・汎用カスタム URL・従来の Data URL は読み替えません。Manifest がない作品ではホストポートを呼び出しません。作品内の `execution: "unsandboxed"` は要求値であり権限ではありません。`trusted` などの未知フィールドは拒否します。
15
+
16
+ ## ホスト側の接続
17
+
18
+ ```js
19
+ import {createExtensionLoader, createFetchPort} from '@kubohiroya/turbowarp-extension-loader';
20
+
21
+ const loader = createExtensionLoader({
22
+ embeddedReader: archiveReader,
23
+ fetcher: createFetchPort(),
24
+ trustProvider: {
25
+ async authorize(resolved, {signal}) {
26
+ const approved = await showHostPermissionDialog(resolved, signal);
27
+ return {allowed: approved, scope: 'digest', sha256: resolved.sha256};
28
+ }
29
+ },
30
+ registrar: hostTransactionalRegistrar,
31
+ diagnostics: event => displayDiagnostic(event)
32
+ });
33
+
34
+ await loader.loadProject(parsedProjectJSON);
35
+ // A new project must unload the prior project first.
36
+ await loader.unload();
37
+ ```
38
+
39
+ `trustProvider` はホストが所有します。要求 ID、バージョン、申告発行者、取得元、SHA-256、要求 capability を受け取り、承認 UI やホストの固定ポリシーを使って判断してください。作品内の名前・ドメイン・発行者文字列だけを承認の根拠にしません。SHA-256 は内容の一貫性を保証するだけで安全性や発行者の本人性は保証しません。ホストは承認履歴の保存・取消・有効期限を管理します。
40
+
41
+ 登録ポートは `begin({signal})` → `register(authorizedCode,{signal})` → `commit({signal})` を実装し、どの登録が失敗しても `rollback()` で登録状態を復旧できる必要があります。`register()` は実際の `getInfo().id` と対応する登録結果 `{id}` を返します。ホストは既存 VM 内の ID 競合も拒否してください。`unload(ids)` は依存の逆順で呼ばれます。契約は TypeScript の型(`dist/*.d.ts` として公開)に記載しています。
42
+
43
+ 実VMアダプターは `scratch-gui/src/lib/tw-plus-extension-registrar.js` が所有します。VMへ追加する `getExtensionServicePort()` と組み合わせ、同一VMの登録テーブル・dispatchサービスの所有権を追跡してrollback/unloadします。Editorと別バンドルのPackagerもVM内の同じサービスを利用します。標準VMを使用する同一バンドルではdispatch同一性を確認し、未対応の別バンドルでは拒否します。Loaderコア自身はVM private APIへ依存しません。
44
+
45
+ ## セキュリティ境界と制約
46
+
47
+ - core は JS を評価しません。評価権限と VM 内部 API はホストに限定します。
48
+ - ロールバックはホストの拡張登録状態の保証です。一度評価した特権 JS の DOM / ネットワーク等の副作用を巻き戻すことはできません。安全なコードの承認は別途必要です。
49
+ - 初期版は Remote の HTTP、資格情報付き URL、フラグメント、リダイレクトをすべて拒否します。HTTPS URL の正常取得だけで認可しません。
50
+ - `createFetchPort()` はリダイレクト無効、credentials 不送信、referrer 不送信、ストリームの実サイズ制限を適用します。CORS / CSP / offline の fetch 拒否は `LOAD_FAILED` の `cause` に保持します。ネットワーク層の詳細分類はcauseへ委ね、CORS/CSPはEditor側の実ブラウザーE2Eで検証します。
51
+ - injected fetch ポートは `finalURL` と明示的な空 `redirects` を返す必要があります。ポート自体は信頼済みホストが実装する境界です。
52
+ - 取得・認可は応答しないポートでもタイムアウトします。登録処理はキャンセル後も完了を待ってから rollback します。遅れて完了する登録と rollback の競合を避けるため、登録ポートが `AbortSignal` に応答しない場合、登録中の有限時間終了は保証できません。
53
+ - キャッシュの容量・失効・永続化・出所ログはホストのポートが担当します。壊れたキャッシュを暗黙に無視して Remote へ切り替えません。
54
+ - `./packager` はEmbedded / Remote変換、明示承認付きData URL移行、lock/license metadata保持、offline SB3準備を提供します。外部依存資源がある拡張は同梱を推測せず拒否します。署名・発行者鍵のpinningはホスト側で追加できる設計で、初期実装は内容・取得元に束縛したセッション承認です。
55
+ - ZIP の実装は `createProjectIO({zip: JSZip})` に注入します。core の codec が ZIP central directory を直接検査し、重複・経路・宣言容量を検証してから、ストリーム展開の実容量と CRC32 を検査します。外部実装の archive port を使う場合も同等の検証が必要です。
56
+
57
+ 既定値は最大64拡張、1拡張1 MiB、合計8 MiB、取得・認可30秒です。データURLやHTTPの開発モード例外はありません。標準 TurboWarp / 非対応エディターが独自 Manifest と ZIP エントリを破棄する可能性があるため、保持対応のないホストでの再保存は移行手段になりません。
58
+
59
+ ## IndexedDB 永続キャッシュ(ブラウザホスト用)
60
+
61
+ 固定された npm `name@exact-version` のCDN配信を想定し、**cache first** とします。ハッシュで固定されたキャッシュがあればオンライン・オフラインを問わずCDNへ問い合わせません。キャッシュミス時のみ既存Remote Fetch Portが取得します。URLに `latest`、semver範囲、バージョン省略等の可変指定を使わないことをホスト側で保証してください。キャッシュの保持にはTTLを設けず、容量超過時のLRU、明示消去、ブラウザのストレージ削除のみで削除します。gzip展開後のSHA-256照合とunsandboxed実行認可は毎回必要です。
62
+
63
+
64
+ `./indexeddb-cache` はリモートで取得・SHA-256 検証済みの JS バイト列を、ブラウザ再起動をまたいで再利用するための **任意の Cache Port アダプター**です。Loader コア側には IndexedDB 依存を持たせません。
65
+
66
+ ```js
67
+ import {createIndexedDBContentCache}
68
+ from '@kubohiroya/turbowarp-extension-loader/indexeddb-cache';
69
+
70
+ const cache = createIndexedDBContentCache({
71
+ databaseName: 'turbowarp-plus-extension-cache',
72
+ maxBytes: 32 * 1024 * 1024, // compressed storage quota
73
+ maxDecompressedBytes: 8 * 1024 * 1024
74
+ });
75
+ const loader = createExtensionLoader({...hostPorts, cache});
76
+ // 終了・ログアウトなどの明示操作で await cache.clear() / await cache.close()
77
+ ```
78
+
79
+ - キーは lowercase SHA-256 hex。**保存する値は生JSではなく gzip 圧縮されたバイト列**(format: `gzip-v1`、元サイズを併記)。取得時に展開して Loader に返します。既定32 MiB は**圧縮後の総保存容量**、展開後の最大サイズは8 MiB、有効期限なし。容量超過時は最終アクセス順LRUで削除します。旧形式の非圧縮エントリは読み込まず削除します。
80
+ - 展開は出力サイズを制限し、改ざん・gzip破損や展開超過を拒否します。ブラウザの `CompressionStream` / `DecompressionStream` が必要です。非対応環境で生JSへ黙って切り替えて保存することはありません。
81
+ - キャッシュを利用した際にも Loader コアが **取得バイト列の SHA-256 を再検証** し、毎回 trustProvider の権限判定を適用します。キャッシュが信頼判断を代行することはありません。
82
+ - キャッシュは IndexedDB を使用できるブラウザ origin に紐付き、ブラウザのストレージ削除・プライベートモード・容量不足等で消える場合があります。ブラウザからの永続化保証はありません。
83
+ - IndexedDB が利用できない環境では生成時に明示的に失敗します。ホストは必要に応じて `createMemoryContentCache` にフォールバックできます。ただしキャッシュ障害を無条件に無視してコード実行するのではなく、ホスト側で失敗方針を決めてください。
84
+ - 新たな Remote バイト列を取得し保存した場合も、権限承認は毎回別途必要です。コード内から追加取得される依存リソースや外部サービスはこのキャッシュの対象外です。
85
+ - Web/Editor はこのポートを初期化して注入するだけとし、`scratch-gui` と `turbowarp-plus-editor` に別のキャッシュロジックを実装しないでください。
86
+
87
+ ## ソースとビルド
88
+
89
+ ソースは `src/*.ts` の TypeScript です。`npm run build`(`tsc`)が ES2022 の ESM と型宣言を `dist/` に出力し、`exports`・`main`/`module`・webpack 4 用のルートファイル(`packager.js` など)はすべて `dist/` を指します。`dist/` は Git に含めず、Git 依存としてインストールされるときに `prepare` スクリプトがビルドします。npm パッケージにはビルド済みの `dist/` を含めます。webpack 4 では従来どおり `./webpack4` の Babel 設定が `dist/` を変換します。
90
+
91
+ ## 検証
92
+
93
+ ```sh
94
+ npm ci --ignore-scripts
95
+ npm run typecheck
96
+ npm test
97
+ ```
98
+
99
+ `npm test` は `dist/` をビルドしてから、パッケージ名経由(`exports` 解決)で公開APIを検証します。テストは型に反する不正入力も渡すため JavaScript のままです。Node.js >=26 の組み込み test runner / Web Crypto を使い、Loader 本体を実行時依存パッケージなしで headless 検証します。ZIP codec の fixture 検証には開発依存の `@turbowarp/jszip` を使います。`test/fixtures/extension.js` はホストに渡すバイト列の fixture で、テスト中に評価しません。実ネットワーク、CORS / CSP、VM の private API、ブラウザー拡張実行の検証とは区別します。
100
+
101
+ ## 導入と切戻し
102
+
103
+ ホストの起動時固定・既定 OFF のフィーチャーフラグの内側に接続します。フラグ OFF で Loader ポートを呼び出さず、従来の作品読込経路へ戻せる設計とします。未知の Manifest を保持できないホストでは有効化せず、公開前に SB3 保存→再読込の fixture を検証してください。
104
+
105
+
106
+ ## SB3 codec
107
+
108
+ `./project-codec` は `createProjectIO({zip: JSZip, ...limits})` と `inspectZip(bytes, limits)` を提供します。GUI は Manifest を解釈せず、`prepare` → `activate(context)` と `restoreJSON` / `restoreFiles` / `restoreArchive` を接続します。`embeddedReader` は同じインスタンスを Loader ports に渡します。
109
+
110
+ `prepare` は JSON object / string / UTF-8 bytes / ArrayBuffer / Blob と SB3 ZIP を受け取り、`{manifest, input, context}` を返します。Manifest があれば core で検証し、legacy input の Plus ID に対する `extensionURLs` を除去して自動 URL 実行を防ぎます。ID 自体は GUI の登録 hook 用に残します。保存時は Manifest・元の Plus URL metadata・embedded bytes・未知の ZIP entry・未知の top-level metadata を復元します。`restoreArchive` は GUI の `toJSON` hook が `project.json` を復元済みであることを前提とします。
111
+
112
+ 未対応形式は ZIP64、multidisk、暗号化、STORE/DEFLATE 以外、UTF-8 以外の非 ASCII entry 名、Unicode path extra field です。既定上限は archive と全展開量64 MiB、1 entry16 MiB、project.json 4 MiB、4096 entry、圧縮比1000です。上限はホスト起動設定で変更できます。Manifest のない ZIP もこの安全検査を受け、通過後は元 input をそのまま返します。このため、従来 VM が許していた未対応 ZIP もフラグ有効時には拒否されます。フラグ OFF では codec 自体を呼びません。
113
+
114
+ ## 追加のホスト向けAPI
115
+
116
+ - `isAuthorizedCode(value)` はコアが発行し現在登録中の認可証跡だけを識別します。コピー・作品データによる偽造を拒否し、transaction終了時に失効します。
117
+ - `./session-trust` の `createSessionTrustProvider` はid/digest/source/version/publisher/capabilities/dependenciesへ束縛した承認を保持します。明示された外部ホストのURL/execution方針をUI前に毎回適用し、判定できないEmbedded要求は拒否します。
118
+ - `./memory-cache` の `createMemoryContentCache` はコピー・容量・TTL・LRUを提供し、コアはヒット時にも内容を再検証します。
119
+ - `./webpack4` はGUI/Packager用の同一コアをwebpack 4でビルドするための構成補助です。
120
+
121
+ 実GUI、実Packager 3.14.0の生成HTML、Desktop 1.17.0の互換性はEditor側のE2Eが担当します。標準Desktopや標準WebへLoaderを無断インストールしません。標準Desktopの保存は独自Manifest/ZIPエントリを破棄することを実測しているため、保持対応エディターで保存してください。
122
+
123
+ ## JSファイル・URLからの作品追加API
124
+
125
+ `./project-authoring` の `prepareExtensionAddition` は、[Editor Issue #11](https://github.com/kubohiroya/turbowarp-plus-editor/issues/11) の専用UI(カスタム拡張画面)のために作りました。TurboWarp-Plus-Editor は2026-11-01にこの画面をやめ、拡張の入口を TurboWarp Plus の一覧(下の `./project-catalog`)だけにしたため、今は Editor から使っていません。UIはIDとファイルまたはURLを渡すだけで、Manifest編集・URLポリシー・SHA-256計算はこのコアが担当します。
126
+
127
+ ```js
128
+ import JSZip from '@turbowarp/jszip';
129
+ import {prepareExtensionAddition} from '@kubohiroya/turbowarp-extension-loader/project-authoring';
130
+
131
+ const candidate = await prepareExtensionAddition(currentSB3, {
132
+ id: 'myextension',
133
+ source: {type: 'embedded'},
134
+ bytes: selectedFile
135
+ }, {fetcher, trustProvider, cache, diagnostics}, {zip: JSZip, signal});
136
+ // For a Remote extension, use {id, source: {type: 'remote', url: httpsURL}}.
137
+ // Apply candidate.projectBytes only after the host checks that the project is still current.
138
+ ```
139
+
140
+ - JSファイルはEmbedded、HTTPS URLはRemoteとして追加します。Embeddedの既定パスは `extensions/<id>.js` です。RemoteはURLから実際に取得し、呼出側が渡したバイト列による代用を拒否します。
141
+ - IDは拡張作者の `getInfo().id` に合わせて入力します。取り込み時にJSを評価してIDを抽出しません。実行時のregistrarが最終的なID一致を検査します。
142
+ - 空・過大・非UTF-8のJS、予約済みID、既存ID、既存ZIPエントリへの上書きを拒否します。HTTPS・最終URL・リダイレクトは既存Loaderと同じ検証を適用します。
143
+ - SHA-256は取得したexact bytesから自動計算します。Remoteでは、その取得結果をスナップショットとして候補検証に使います。作品保存後の再取得時にも固定ハッシュを照合するため、サーバー側の差替えを自動で信頼しません。
144
+ - 候補作品の全拡張を既存Loaderで検証し、ホストの明示的承認を確認してから `{projectBytes, spec, manifest}` を返します。このAPIはJSを実行せず、元の作品・入力バイト列・実VMを変更しません。承認済みのセッションtrustProviderを実VMへの適用時にも共有すると、同じ内容・取得元への重複確認を避けられます。
145
+ - 標準拡張、通常のcustom URL、既存Plus Manifest、埋め込みコード、画像等のZIPエントリ、未知metadata、配布lockを保持します。生成候補は通常ロードと同じZIP制限で再検査します。
146
+ - VM適用はホストが所有します。プロジェクト切替・キャンセル・登録失敗の扱いと元作品の復元を実装し、UIを閉じた後や別作品に古い結果を適用しないでください。
147
+ - 返却したSB3は通常保存と `prepareOfflinePackage` にそのまま渡せます。Remoteの同梱・外部依存の宣言・受取人の承認境界は従来のPackager APIを再利用します。起動時フラグは引き続き既定OFFです。
148
+
149
+ ## 一覧からの一括設定API
150
+
151
+ `./project-catalog` の `prepareCatalogExtensionChanges(currentSB3, requests, ports, options)` は、カタログの選択をまとめてSB3候補へ反映します。requestは `{id, url, distribution: 'embedded' | 'remote', execution: 'sandboxed' | 'unsandboxed', dependencies?, version?}` です。JS取得・SHA-256計算・依存順・全件検証・ホスト承認を共通Loaderで行い、全件承認後に `{projectBytes, manifest}` を返します。実VMには触りません。
152
+
153
+ 既存Plus拡張の配布方式・実行モードを変える場合は、検証済みコードとSHA-256・発行者・バージョン・lockを保持します。Remote出力先が現在のコードを返さない場合、更新として勝手に追従せず拒否します。`readProjectAuthoringState(input, options)` は検証済みManifestを返し、UIの状態復元に使えます。これらの作品情報は実行許可ではありません。
154
+
155
+ Manifestの実行要求は `sandboxed` と `unsandboxed` の両方を扱います。ホストは要求された実行モードを守るregistrarを注入してください。ローカルで検証したEditor/Packager統合ではVM所有の隔離iframeまたは承認済みホスト実行へ分岐し、サンドボックスありをサンドボックスなしへ昇格しません。認可キーは実行モードも含み、外部host policyと一致しない要求は拒否します。`prepareExtensionAddition` でも任意の `execution` を渡せ、省略時だけ従来の `unsandboxed` です。
156
+
157
+ 複数パッケージの候補適用、実行中拡張の所有権移行、登録失敗時の元SB3復元はGUI/VMの責務です。既存legacy拡張の移行は、VMが一時detach/commit/rollbackの所有境界を提供する場合に限ります。元サービスのdispose後に復旧できない場合も、元SB3を回復用に保持してください。
158
+
159
+ ## 公開範囲
160
+
161
+ Loaderコアと型・ドキュメントを、MPL-2.0 で npm に公開します。タグ `v<version>` を push すると、`release.yml` が検証・pack・GitHub Releaseへの添付・npmへの公開(Trusted Publisher、provenance付き)を行います。初回の版だけは、npm にパッケージがまだないため Trusted Publisher を設定できません。手作業で公開してから、npmjs.com で `release.yml` を Trusted Publisher に設定します。Editor・GUI・VM・Packagerの統合実装は別のリポジトリで管理され、このコアの公開によってそれらが更新・配信されることはありません。導入時はホスト側の互換性検証と、起動時固定・既定OFFのフラグが必要です。
162
+
163
+ ## ライセンス
164
+
165
+ MPL-2.0。全文は [LICENSE](LICENSE) を参照してください。
@@ -0,0 +1,3 @@
1
+ /** Gzip utilities for persistent extension caches. The caller remains responsible for SHA-256 verification. */
2
+ export declare function gzipBytes(bytes: Uint8Array): Promise<Uint8Array<ArrayBuffer>>;
3
+ export declare function gunzipBytes(compressed: Uint8Array<ArrayBuffer>, maxOutputBytes: number): Promise<Uint8Array<ArrayBuffer>>;
@@ -0,0 +1,45 @@
1
+ /** Gzip utilities for persistent extension caches. The caller remains responsible for SHA-256 verification. */
2
+ export async function gzipBytes(bytes) {
3
+ if (!(bytes instanceof Uint8Array))
4
+ throw new TypeError('Expected Uint8Array');
5
+ if (typeof CompressionStream !== 'function')
6
+ throw new Error('CompressionStream gzip unavailable');
7
+ // BlobPart excludes shared-memory views; as in JavaScript, Blob itself decides what it accepts.
8
+ return new Uint8Array(await new Response(new Blob([bytes]).stream()
9
+ .pipeThrough(new CompressionStream('gzip'))).arrayBuffer());
10
+ }
11
+ export async function gunzipBytes(compressed, maxOutputBytes) {
12
+ if (!(compressed instanceof Uint8Array) || !Number.isSafeInteger(maxOutputBytes) || maxOutputBytes < 1) {
13
+ throw new TypeError('Invalid compressed bytes or output limit');
14
+ }
15
+ if (typeof DecompressionStream !== 'function')
16
+ throw new Error('DecompressionStream gzip unavailable');
17
+ const reader = new Blob([compressed]).stream().pipeThrough(new DecompressionStream('gzip')).getReader();
18
+ const chunks = [];
19
+ let size = 0;
20
+ try {
21
+ while (true) {
22
+ const { done, value } = await reader.read();
23
+ if (done)
24
+ break;
25
+ size += value.byteLength;
26
+ if (size > maxOutputBytes)
27
+ throw new Error('Decompressed cache exceeds byte limit');
28
+ chunks.push(value);
29
+ }
30
+ }
31
+ catch (error) {
32
+ await reader.cancel(error).catch(() => { });
33
+ throw error;
34
+ }
35
+ finally {
36
+ reader.releaseLock();
37
+ }
38
+ const result = new Uint8Array(size);
39
+ let offset = 0;
40
+ for (const chunk of chunks) {
41
+ result.set(chunk, offset);
42
+ offset += chunk.byteLength;
43
+ }
44
+ return result;
45
+ }