@kubohiroya/turbowarp-structured-data 0.4.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.
@@ -0,0 +1,32 @@
1
+ # アーキテクチャ
2
+
3
+ [English](architecture.md)
4
+
5
+ 任意のNamed Data統合は、canonical契約とruntime共有registryを
6
+ `@kubohiroya/turbowarp-named-data/composition`からimportします。`structured` providerは
7
+ `kind: structured`、target scope、persistent登録として接続します。`PROJECT_STOP_ALL`では
8
+ target bindingとopen bodyをclearしますが、次のproject sessionでもprovider登録を維持します。
9
+
10
+ structured-data、document-data、binary-data、Asset Manager、HTTP Serverを名前付き参照とHTTP body供給契約で接続する段階計画は[Named Data統合計画](named-data-integration-plan.ja.md)を参照してください。
11
+
12
+ ## 名前付きデータmodel
13
+
14
+ 機能拡張は`WeakMap<Target, Map<Name, JsonValue>>`を所有します。nameはtrim済みの空でないstringです。spriteとstageは別namespaceです。parseはbindingをatomicに置換し、path更新は新しいJSON valueを構築して検証成功後だけbindingを置換します。`PROJECT_STOP_ALL`でregistryとiteration stackを交換するため、runtime stateはproject停止後に残りません。
15
+
16
+ JSON valueは`null`、boolean、有限number、string、array、own enumerable propertyだけを持つobjectです。opaqueな内部tokenを公開block境界へ渡しません。Scratch reporter型の制約により必要なparse、render、set value、get value、keys、current value境界だけでJSON/YAML textを使います。
17
+
18
+ ## codecと上限
19
+
20
+ `src/codecs.ts`はJSONを共有core、YAMLをYAML ASTでparseします。両方とも入力256 KiB、深さ64、50,000 nodeを上限とします。YAML alias、parser warning、duplicate key、unknown tag、string以外のkey、未対応scalarはnamespace binding変更前に失敗します。
21
+
22
+ canonical JSONはobject keyを再帰的にUnicodeコードポイント順へ揃えます。YAMLも同じ順序を使い、string scalarをquoteし、identifier形式のkeyだけをquoteなしで出力します。
23
+
24
+ ## pathと反復
25
+
26
+ `src/core.ts`は制限付きpathを型付きkey/index segmentへ変換し、不変get、has、set、delete、keys、length、iteration entry生成を実装します。loop entry snapshotは決定的です。active loop frameはTurboWarp threadをkeyとする別の`WeakMap`に保持し、nested loopはstackになります。
27
+
28
+ ## compiler manifest v3
29
+
30
+ manifestはtarget scope、project停止までのlifetime、`jsonValue`内容を持つnamed referenceを宣言します。各opcodeはargument、result型、effect(`pure`、`state`、`control`)、error、IR v2 operationを持ちます。server adapterは同等のtarget-local slot環境を提供し、未対応manifest versionを拒否します。
31
+
32
+ `tests/fixtures/semantic-parity.json`をnamespace、codec、path、結果、error意味論のbrowser/server共通契約とします。
@@ -0,0 +1,30 @@
1
+ # Architecture
2
+
3
+ [日本語](architecture.ja.md)
4
+
5
+ The optional Named Data integration imports its canonical contract and shared runtime registry from
6
+ `@kubohiroya/turbowarp-named-data/composition`. The `structured` provider is registered with
7
+ `kind: structured`, target scope, and persistent registration. `PROJECT_STOP_ALL` clears target
8
+ bindings and open bodies but retains the provider registration for the next project session.
9
+
10
+ ## Named data model
11
+
12
+ The extension owns a `WeakMap<Target, Map<Name, JsonValue>>`. Names are trimmed, non-empty strings. A sprite and the stage have separate namespaces. Parsing replaces a binding atomically; path updates construct a new JSON value and replace the binding only after validation succeeds. `PROJECT_STOP_ALL` replaces the registries and iteration stacks, so runtime state does not survive a project stop.
13
+
14
+ JSON values are `null`, booleans, finite numbers, strings, arrays, and objects with own enumerable properties. They never cross the public block boundary as opaque internal tokens. JSON/YAML text appears only at parse, render, set-value, get-value, keys, and current-value boundaries required by Scratch reporter types.
15
+
16
+ ## Codecs and limits
17
+
18
+ `src/codecs.ts` parses JSON through the shared core and YAML through the YAML AST. Both enforce 256 KiB input, depth 64, and 50,000 nodes. YAML aliases, parser warnings, duplicate keys, unknown tags, non-string keys, and unsupported scalars fail before a namespace binding changes.
19
+
20
+ Canonical JSON recursively sorts object keys by Unicode code point. YAML uses the same ordering, quotes string scalars, and only leaves identifier-like keys unquoted.
21
+
22
+ ## Paths and iteration
23
+
24
+ `src/core.ts` converts restricted string paths to typed key/index segments and implements immutable get, has, set, delete, keys, length, and iteration entry generation. Loop entry snapshots are deterministic. Active loop frames are held in a separate `WeakMap` keyed by TurboWarp thread; nested loops form a stack.
25
+
26
+ ## Compiler manifest v3
27
+
28
+ The manifest declares a named reference with target scope, lifetime until project stop, and `jsonValue` contents. Each opcode provides arguments, result type, effect (`pure`, `state`, or `control`), possible errors, and its IR v2 operation. Server adapters must provide an equivalent target-local slot environment and reject unsupported manifest versions.
29
+
30
+ `tests/fixtures/semantic-parity.json` is the portable browser/server contract for namespace, codec, path, result, and error semantics.
@@ -0,0 +1,26 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <title>Structured Data documentation</title>
7
+ <style>
8
+ body{font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;max-width:900px;margin:0 auto;padding:2rem;line-height:1.6;color:#222}
9
+ code{background:#f3f3f3;padding:.1em .3em;border-radius:.25em}
10
+ pre{background:#f6f8fa;padding:1rem;overflow:auto;border-radius:.5rem}
11
+ </style>
12
+ </head>
13
+ <body>
14
+ <h1>Structured Data</h1>
15
+ <p>Named structured data with safe JSON/YAML codecs and deterministic path operations.</p>
16
+
17
+ <h2>Blocks</h2>
18
+ <p>Parse JSON or YAML into a target-local name, update it with restricted paths, iterate with an explicit bound, and render it back to JSON or YAML.</p>
19
+
20
+ <h2>Enable the MVP</h2>
21
+ <p>Set <code>globalThis.STRUCTURED_DATA_MVP = true</code> in the TurboWarp page, then load <code>structured-data.js</code> with <strong>Run extension without sandbox</strong> enabled. Start with <code>parse JSON ... as ...</code> or <code>parse YAML ... as ...</code>.</p>
22
+
23
+ <h2>Development</h2>
24
+ <p>See the repository README and architecture documentation for build, test, release, and compatibility details.</p>
25
+ </body>
26
+ </html>
@@ -0,0 +1,375 @@
1
+ # Named Data統合計画
2
+
3
+ ## 目的
4
+
5
+ structured-data、将来のdocument-dataとbinary-data、既存のAsset Manager、HTTP Serverを、名前付きデータ参照とHTTP body供給契約で接続する。
6
+
7
+ 共通化する対象は各データ型の内部表現や編集APIではない。HTTPレスポンスへ安全に変換できる名前付きresourceの識別、metadata、解決、lifetime、error意味論を共通化する。HTTP ServerはJSON、YAML、HTML、Markdown、画像、音声その他のbinaryを、各providerのprivate stateへ依存せずresponse bodyとして利用できるようにする。
8
+
9
+ ## 現状と課題
10
+
11
+ ### structured-data
12
+
13
+ - targetごとの名前付きregistryにJSON valueを保持する
14
+ - JSON/YAMLのparseとserialize、path操作、反復を提供する
15
+ - registryは機能拡張内部に閉じており、別の機能拡張から名前を解決できない
16
+ - valueはproject停止時に破棄され、project fileへ永続化しない
17
+
18
+ ### Asset Manager
19
+
20
+ - 名前付きasset registryで画像、音声、text、project assetを扱う
21
+ - APIではArrayBufferまたはUint8Arrayを名前付きassetとして登録できる
22
+ - composition APIにはnamespaceとnameを使うbinary bundle storeがある
23
+ - Asset Manager固有のasset操作と汎用binary resourceの責務が一部重なる
24
+
25
+ ### HTTP Server
26
+
27
+ - `/@assets/<name>`で外部capabilityが提供する名前付きresourceを配信できる
28
+ - handler blockのresponse bodyは主にtext、HTML、JSON文字列を受け取る
29
+ - IR v2には再利用可能なbinary-refと、一回だけ消費できるbinary-bodyがある
30
+ - structured-dataやdocument-dataの名前を共通response bodyとして解決する契約がない
31
+
32
+ 各機能拡張が独自registryとHTTP連携を実装すると、名前のscope、MIME type、byte上限、stream ownership、error code、停止時の解放が重複して不整合になる。
33
+
34
+ ## 設計原則
35
+
36
+ 1. 名前付き参照をbyte列やdata URLとしてScratch reporterへ埋め込まない。
37
+ 2. JSON/YAML、HTML/Markdown、binaryの保存形式と編集意味論は各providerが所有する。
38
+ 3. HTTP Serverはproviderの内部表現を参照せず、共通body resolverだけを利用する。
39
+ 4. 暗黙変換を避け、representationとMIME typeを明示またはproviderの既定値から決定する。
40
+ 5. requestのstream bodyと、保存済みnamed dataを別の型として扱う。
41
+ 6. size、depth、node count、byte count、stream消費回数に上限を設ける。
42
+ 7. 段階導入は既定OFFの起動時feature flagで行う。
43
+ 8. browser runtimeとserver compilerで参照、error、lifetime意味論を一致させる。
44
+
45
+ ## 対象モデル
46
+
47
+ | provider | 入出力形式 | 内部表現 | provider固有の操作 |
48
+ |---|---|---|---|
49
+ | structured-data | JSON、YAML | JSON value | path参照、更新、削除、key列挙、反復 |
50
+ | document-data | HTML、Markdown | kindを保持するdocument treeまたはAST | selector、属性、text、子node、render |
51
+ | binary-data | 任意のMIME | bytesまたはstream backing | size、digest、range、import、export |
52
+ | Asset Manager | 画像、音声、costume、backdrop、runtime text | asset binding | render、play、sprite/stage適用 |
53
+
54
+ Asset Managerはbinary-dataの置き換えではない。汎用binaryを画像や音声として利用するconsumer兼specialized providerとする。
55
+
56
+ ### 共通参照
57
+
58
+ 共通参照は次の論理fieldを持つ。
59
+
60
+ | field | 意味 |
61
+ |---|---|
62
+ | namespace | providerまたは用途の衝突を避ける安定ID |
63
+ | name | namespace内の論理名 |
64
+ | kind | structured、document、binary、asset |
65
+ | scope | targetまたはproject |
66
+
67
+ target scopeはsprite/stageごとに分離し、project scopeはHTTP公開resourceや共有assetに使用する。Scratch blockでは当面namespaceとnameを別argumentとして渡す。未検証のJSON文字列や区切り文字入りtokenを参照形式にしない。
68
+
69
+ 初期namespaceはstructured、document、binary、assetを予約する。providerの二重登録、unknown namespace、kind不一致、scope不一致は安定errorとして拒否する。
70
+
71
+ ### 共通metadata
72
+
73
+ | field | 規則 |
74
+ |---|---|
75
+ | mediaType | parameterを含む正規化済みMIME type |
76
+ | byteLength | encode前に確定できない場合は省略可能 |
77
+ | digest | 利用可能ならsha256とlowercase hexadecimal |
78
+ | revision | atomic replacementを識別し、ETag生成に利用可能 |
79
+ | replayable | 保存済みnamed dataでは原則true |
80
+
81
+ ### HTTP body供給契約
82
+
83
+ providerはstatとopenBodyを提供する。openBodyは次を返す。
84
+
85
+ - mediaType
86
+ - 任意のbyteLength、digest
87
+ - revision
88
+ - Uint8ArrayまたはReadableStream
89
+ - 必要な場合のrelease callback
90
+
91
+ HTTP Serverはこの結果からContent-Type、可能ならContent-LengthとETagを設定する。client切断時はAbortSignalを伝播し、完了または失敗時にreleaseを高々一回呼ぶ。
92
+
93
+ | kind | representation | MIME type |
94
+ |---|---|---|
95
+ | structured | json | application/json; charset=utf-8 |
96
+ | structured | yaml | application/yaml; charset=utf-8 |
97
+ | document | html | text/html; charset=utf-8 |
98
+ | document | markdown | text/markdown; charset=utf-8 |
99
+ | binary | raw | 登録時のMIME type |
100
+ | asset | raw | assetのMIME type |
101
+
102
+ structured-dataとdocument-dataのencode結果はUTF-8 bytesとして渡す。binary-dataとAsset Managerはbase64やJavaScript stringへ変換せずbytesまたはstreamを渡す。
103
+
104
+ ## Block API案
105
+
106
+ ### 共通namespace操作
107
+
108
+ providerごとにblock色と専門用語は維持しつつ、次の表層を揃える。
109
+
110
+ - named dataが存在するか
111
+ - named dataを削除
112
+ - named dataを別名へcopy
113
+ - named dataのMIME type
114
+ - named dataのsize
115
+
116
+ copyやsizeを提供できないproviderは初期versionでblockを公開せず、偽の値を返さない。
117
+
118
+ ### HTTP response
119
+
120
+ HTTP Serverに次の共通操作を追加する。
121
+
122
+ - set response body from NAMESPACE named NAME as REPRESENTATION
123
+ - respond with NAMESPACE data NAME as REPRESENTATION
124
+
125
+ 既存のJSON、HTML等のresponse blockを維持する期間は、内部で同じresponse builderへloweringするcompatibility wrapperとする。新規compiler IRでは共通operationをcanonical formとする。
126
+
127
+ ### HTTP request
128
+
129
+ request bodyは保存済み参照と同一視しない。
130
+
131
+ - current request bodyをbinary data NAMEとして保存
132
+ - current request bodyをJSONまたはYAMLとしてparseしNAMEへ登録
133
+ - current request bodyをHTMLまたはMarkdown documentとしてparseしNAMEへ登録
134
+
135
+ IRのbinary-bodyはaffine resourceとして最大一回consumeする。保存またはparseが成功した後に、再利用可能なnamed dataをatomicに登録する。失敗時に既存bindingを変更しない。
136
+
137
+ ## Registryとprovider境界
138
+
139
+ 共通registryは特定format拡張のprivate fieldには置かない。小さなruntime-neutral packageとして定義し、TurboWarp runtimeごとに一つのserviceを生成する。候補package名は @kubohiroya/turbowarp-named-data とする。
140
+
141
+ 共通packageの責務:
142
+
143
+ - provider登録と解除
144
+ - namespace衝突検査
145
+ - target/project scopeの解決
146
+ - project停止時の一括release
147
+ - metadataとbody resolverの型
148
+ - stable error codeと上限policyの共通部分
149
+
150
+ 共通packageはJSON path、DOM、Markdown、codec、binary永続化、HTTP routingを所有しない。
151
+
152
+ ### lifetime
153
+
154
+ - target scopeはtarget identityに結び付ける
155
+ - project scopeはruntime identityに結び付ける
156
+ - PROJECT_STOP_ALLでsession-only bindingとopen bodyを解放する
157
+ - persistent binary backingはbindingと分離し、明示deleteまたはretention policyで管理する
158
+ - provider交換時は新規解決を停止し、open済みbodyのrelease完了後に解除する
159
+
160
+ ## Compiler/IR統合
161
+
162
+ IR v2のbinary-refをbinary専用の例外として増殖させず、named data参照を表現できるdescriptorへ一般化する。descriptorはnamespace、name、kind、scopeと、任意のmediaType、byteLength、digestを持つ。byte payloadはIR JSONへ格納しない。
163
+
164
+ 既存binary-refはkindがbinaryまたはassetのdescriptorとして読めるmigration adapterを設ける。binary-bodyはstream resourceなのでvalue descriptorへ統合しない。
165
+
166
+ target adapterはnamespace provider、representation、stream response、response size、binary-read effect、scopeの対応状況を検査する。未対応時にtextやbase64へ暗黙fallbackしない。
167
+
168
+ ## Errorと安全性
169
+
170
+ 共通層では少なくとも次の安定errorを定義する。
171
+
172
+ | code | 条件 |
173
+ |---|---|
174
+ | NAMED_DATA_INVALID_REF | namespace、name、kind、scopeが不正 |
175
+ | NAMED_DATA_PROVIDER_NOT_FOUND | namespace providerが未登録 |
176
+ | NAMED_DATA_NOT_FOUND | bindingが存在しない |
177
+ | NAMED_DATA_KIND_MISMATCH | requested kindと登録kindが異なる |
178
+ | NAMED_DATA_SCOPE_MISMATCH | target/project scopeが不一致 |
179
+ | NAMED_DATA_REPRESENTATION_UNSUPPORTED | requested representationをencodeできない |
180
+ | NAMED_DATA_BODY_TOO_LARGE | encodeまたはrequest保存上限を超えた |
181
+ | NAMED_DATA_ABORTED | client切断等で処理を中止した |
182
+ | NAMED_DATA_PROVIDER_RELEASED | 解放済みproviderを参照した |
183
+
184
+ 安全要件:
185
+
186
+ - HTML出力を自動sanitize済みとみなさない
187
+ - MarkdownからHTMLへの変換はactive content policyを明記する
188
+ - MIME sniffingに依存せずproviderがMIME typeを確定する
189
+ - active contentを配信するrouteへauthorizationとCSPを設定可能にする
190
+ - request body、encode結果、binary rangeに個別上限を持たせる
191
+ - logへbody bytesや機密document内容を記録しない
192
+
193
+ ## 段階的な実装計画
194
+
195
+ 各項目は別Issue/小粒PRとし、依存、受け入れ基準、rollback、feature flagをIssue本文へ記載する。
196
+
197
+ ### Phase 0: 契約の固定
198
+
199
+ 推奨branch: docs/named-data/body-provider-contract
200
+
201
+ - common type、scope、lifetime、error、representationをschemaまたはTypeScript declarationとして固定
202
+ - 各repositoryのcompatibility matrixを作成
203
+ - browser/server共通contract fixtureを作成
204
+
205
+ 受け入れ基準:
206
+
207
+ - payloadを含まない参照schemaをvalidationできる
208
+ - target/project scopeと全representationのfixtureがある
209
+ - duplicate provider、unknown namespace、unsupported representationのerror期待値がある
210
+
211
+ rollback: documentationと未使用typeだけを除けばruntime挙動が変わらない。
212
+
213
+ ### Phase 1: 共通registry MVP
214
+
215
+ 推奨branch: feat/named-data/registry-mvp
216
+
217
+ 依存: Phase 0
218
+
219
+ - runtime単位のprovider registryとscope resolverを実装
220
+ - provider登録、stat、openBody、releaseを実装
221
+ - NAMED_DATA_REGISTRY_MVPを起動時固定、既定OFFで追加
222
+
223
+ 受け入れ基準:
224
+
225
+ - private objectをScratch reporterへ返さず名前から解決できる
226
+ - project停止後にsession bindingとopen resourceが残らない
227
+ - provider失敗時にもstateが部分更新されない
228
+ - flag OFFで既存extensionの挙動が変わらない
229
+
230
+ rollback: flag OFFでcommon registryへの登録と解決を完全に迂回する。
231
+
232
+ ### Phase 2: structured-data provider
233
+
234
+ 推奨branch: feat/structured-data/named-body-provider
235
+
236
+ 依存: Phase 1
237
+
238
+ - 現在のtarget-local bindingをstructured providerから参照可能にする
239
+ - jsonとyamlをUTF-8 bodyとして公開
240
+ - canonical encode、上限、atomic replacementを既存実装と共有
241
+
242
+ 受け入れ基準:
243
+
244
+ - 既存serialize blockとbody resolverの結果が一致する
245
+ - 別targetのtarget-local bindingを参照できない
246
+ - encode失敗時にHTTP responseを部分送信しない
247
+ - browser/server parity testが通る
248
+
249
+ rollback: provider登録flagをOFFにし、既存blockだけを維持する。
250
+
251
+ ### Phase 3: binary-data providerとAsset Manager adapter
252
+
253
+ 推奨branch: feat/binary-data/provider-mvp
254
+
255
+ 依存: Phase 1
256
+
257
+ - session-only named byte/stream registryを実装
258
+ - MIME type、byte length、digest、revisionを保持
259
+ - Asset Managerのassetをasset namespaceからread-only bodyとして公開
260
+ - persistent backingは別feature flagでadapter
261
+
262
+ 受け入れ基準:
263
+
264
+ - base64やstringへ変換せずHTTP bodyへ渡せる
265
+ - asset replacement後にrevisionが変わる
266
+ - open中のsnapshotはreplacementの影響を受けない
267
+ - unsupported kindをempty bodyとして返さない
268
+
269
+ rollback: provider/adapter flagをOFFにし、既存asset registryを維持する。
270
+
271
+ ### Phase 4: HTTP Server response統合
272
+
273
+ 推奨branch: feat/http-server/named-response-body
274
+
275
+ 依存: Phase 2、Phase 3
276
+
277
+ - named body resolverをhandlerとcompiler adapterへ注入
278
+ - 共通response blockとIR operationを追加
279
+ - Content-Type、Content-Length、ETag、abort、releaseを接続
280
+ - 既存format別response blockを共通builderへlowering
281
+ - NAMED_RESPONSE_BODYを既定OFFで追加
282
+
283
+ 受け入れ基準:
284
+
285
+ - structured JSON/YAMLとbinary assetを同じ共通blockから返せる
286
+ - HEADはGETと同じmetadataをbodyなしで返す
287
+ - client切断時にabortが伝播する
288
+ - body bytesをlogへ記録しない
289
+
290
+ rollback: flag OFFで新block/IRを拒否し、既存response pathへ戻す。
291
+
292
+ ### Phase 5: document-data MVP
293
+
294
+ 推奨branch: feat/document-data/html-markdown-mvp
295
+
296
+ 依存: Phase 1。HTTP統合検証はPhase 4にも依存する。
297
+
298
+ - HTMLとMarkdownのkindを保持するnamed document registryを実装
299
+ - parse、node操作、serializeの最小集合を定義
300
+ - htmlとmarkdown representationをbody providerとして公開
301
+ - lossy変換を明示し、既定では元kindと同じrepresentationを使う
302
+
303
+ 受け入れ基準:
304
+
305
+ - 文字列連結ではなくnamed documentとして段階編集できる
306
+ - parse、node、serialize上限がある
307
+ - format変換が行われたか判別できる
308
+ - HTMLを自動的にsafeと表示しない
309
+
310
+ rollback: document provider flagをOFFにし、既存text responseを維持する。
311
+
312
+ ### Phase 6: request body import
313
+
314
+ 推奨branch: feat/http-server/named-request-import
315
+
316
+ 依存: Phase 2、Phase 3、Phase 5
317
+
318
+ - affineなbinary-bodyからbinary-dataへ保存するconsumerを追加
319
+ - 明示的JSON、YAML、HTML、Markdown parse blockを追加
320
+ - consume、abort、limit、atomic registrationをruntimeとcompilerで一致させる
321
+
322
+ 受け入れ基準:
323
+
324
+ - request bodyを最大一回だけconsumeできる
325
+ - parse/保存失敗時に既存bindingを置換しない
326
+ - Content-Typeを暗黙推測しない
327
+ - compilerが二重consumeとscope外利用を拒否する
328
+
329
+ rollback: import flagをOFFにし、既存text request body reporterを維持する。
330
+
331
+ ### Phase 7: compatibility API整理
332
+
333
+ 推奨branch: refactor/http-server/body-api-convergence
334
+
335
+ 依存: Phase 4からPhase 6の利用実績と回帰試験
336
+
337
+ - format固有blockをwrapperとして維持するものとdeprecatedにするものへ分類
338
+ - manifestとdocumentationでcanonical operationを一本化
339
+ - default ON条件と削除versionを別Issueで承認
340
+
341
+ 受け入れ基準:
342
+
343
+ - 既存projectのmigration手順と互換性表がある
344
+ - default ON前に全providerの回帰、負荷、abort testが通る
345
+ - flag OFFによる切戻し手順をrelease noteで確認できる
346
+
347
+ rollback: compatibility wrapperと旧IR loweringを一つ以上の移行期間保持する。
348
+
349
+ ## 依存関係
350
+
351
+ Phase 0からPhase 1を直列に実施する。Phase 1完了後、Phase 2、Phase 3、Phase 5は並列化できる。Phase 4は最低限Phase 2とPhase 3のfixtureを使って統合検証する。Phase 6は各providerの完成後、Phase 7は運用実績取得後に着手する。
352
+
353
+ ## 共通Definition of Done
354
+
355
+ - GitHub Issueにbranch、依存、受け入れ基準、rollback、feature flagを記載
356
+ - public type、manifest、schema、block definition、実装を一致
357
+ - unit、semantic parity、browser integration、server compiler testを追加
358
+ - repository既定のlint、format、typecheck、testを通過
359
+ - size、abort、lifetime、atomicity、二重consumeのnegative testを追加
360
+ - bodyまたは機密値をlogへ出さないことを検証
361
+ - scope、lifetime、MIME type、上限、error、migrationを文書化
362
+ - feature flag OFFで従来挙動へ戻せることを確認
363
+
364
+ ## Phase 0で決める未決事項
365
+
366
+ 1. common registryを独立packageにするか共有workspace packageとして開始するか
367
+ 2. project scopeの名前がsprite clone間でどのように見えるか
368
+ 3. namespaceとnameをScratch block上でmenuにするか自由入力にするか
369
+ 4. structured/documentを事前bufferする最大sizeとstreaming開始条件
370
+ 5. ETagへdigestとrevisionのどちらを使うか
371
+ 6. binary range responseをMVPへ含めるか
372
+ 7. persistent backingのretention、quota、project exportとの関係
373
+ 8. HTML sanitizerをdocument-dataの別operationとするか別providerとするか
374
+
375
+ これらを暗黙の実装判断にせず、contract fixtureとIssueの受け入れ基準へ反映してからruntime変更へ進む。
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "@kubohiroya/turbowarp-structured-data",
3
+ "version": "0.4.0",
4
+ "description": "Named structured data with JSON/YAML codecs and deterministic path operations for TurboWarp.",
5
+ "author": "Hiroya Kubo <hiroya@cuc.ac.jp>",
6
+ "license": "MPL-2.0",
7
+ "homepage": "https://github.com/kubohiroya/turbowarp-structured-data#readme",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/kubohiroya/turbowarp-structured-data.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/kubohiroya/turbowarp-structured-data/issues"
14
+ },
15
+ "keywords": [
16
+ "turbowarp",
17
+ "scratch",
18
+ "extension",
19
+ "structured-data",
20
+ "json",
21
+ "yaml",
22
+ "vite",
23
+ "typescript"
24
+ ],
25
+ "type": "module",
26
+ "files": [
27
+ "dist/",
28
+ "docs/",
29
+ "schemas/",
30
+ "src/",
31
+ "templates/",
32
+ "README.md",
33
+ "README.ja.md",
34
+ "THIRD_PARTY_NOTICES.md",
35
+ "LICENSE"
36
+ ],
37
+ "publishConfig": {
38
+ "access": "public",
39
+ "registry": "https://registry.npmjs.org/"
40
+ },
41
+ "packageManager": "pnpm@11.11.0",
42
+ "engines": {
43
+ "node": ">=22.18.0"
44
+ },
45
+ "scripts": {
46
+ "dev": "vite build --watch",
47
+ "typecheck": "tsc --noEmit",
48
+ "build": "vite build",
49
+ "lint": "eslint src tests scripts vite.config.ts eslint.config.ts",
50
+ "test": "vitest run",
51
+ "docs": "node scripts/generate-readme.ts",
52
+ "docs:check": "node scripts/generate-readme.ts --check",
53
+ "template:readme": "node scripts/apply-readme-template.ts",
54
+ "repo:check": "node scripts/check-repo.ts",
55
+ "pack:check": "npm pack --dry-run --ignore-scripts",
56
+ "check": "pnpm run typecheck && pnpm run lint && pnpm run test && pnpm run docs:check && pnpm run check:dist && pnpm run repo:check && pnpm run pack:check",
57
+ "check:dist": "pnpm run build && node scripts/check-dist.ts"
58
+ },
59
+ "devDependencies": {
60
+ "@eslint/js": "^9.39.5",
61
+ "@kubohiroya/turbowarp-named-data": "github:kubohiroya/turbowarp-named-data#bc3be0e669f501479ef45877e5d06e27714184d2",
62
+ "@kubohiroya/vite-plugin-turbowarp-extension": "0.3.0",
63
+ "@types/node": "^24.13.3",
64
+ "eslint": "^9.39.5",
65
+ "jiti": "^2.7.0",
66
+ "typescript": "^5.9.3",
67
+ "typescript-eslint": "^8.66.0",
68
+ "vite": "^8.2.2",
69
+ "vitest": "^5.0.0"
70
+ },
71
+ "dependencies": {
72
+ "yaml": "^2.9.1"
73
+ },
74
+ "peerDependencies": {
75
+ "@kubohiroya/turbowarp-named-data": "^0.1.0"
76
+ }
77
+ }
@@ -0,0 +1,103 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/kubohiroya/turbowarp-structured-data/main/schemas/extension-manifest.schema.json",
4
+ "title": "TurboWarp Structured Data Compiler Manifest",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["formatVersion", "id", "pathSegmentType", "dataReferenceType", "blocks"],
8
+ "properties": {
9
+ "formatVersion": {"const": 3},
10
+ "id": {"type": "string", "pattern": "^[a-z0-9]+$"},
11
+ "pathSegmentType": {
12
+ "type": "object",
13
+ "additionalProperties": false,
14
+ "required": ["kind", "variants"],
15
+ "properties": {
16
+ "kind": {"const": "discriminatedUnion"},
17
+ "variants": {
18
+ "type": "array",
19
+ "prefixItems": [
20
+ {"$ref": "#/$defs/keyPathSegment"},
21
+ {"$ref": "#/$defs/indexPathSegment"}
22
+ ],
23
+ "items": false,
24
+ "minItems": 2,
25
+ "maxItems": 2
26
+ }
27
+ }
28
+ },
29
+ "dataReferenceType": {
30
+ "type": "object",
31
+ "additionalProperties": false,
32
+ "required": ["kind", "scope", "lifetime", "valueType"],
33
+ "properties": {
34
+ "kind": {"const": "named"},
35
+ "scope": {"const": "target"},
36
+ "lifetime": {"const": "untilProjectStop"},
37
+ "valueType": {"const": "jsonValue"}
38
+ }
39
+ },
40
+ "blocks": {
41
+ "type": "array",
42
+ "minItems": 1,
43
+ "items": {"$ref": "#/$defs/block"}
44
+ }
45
+ },
46
+ "$defs": {
47
+ "keyPathSegment": {
48
+ "type": "object",
49
+ "additionalProperties": false,
50
+ "required": ["kind", "valueType"],
51
+ "properties": {"kind": {"const": "key"}, "valueType": {"const": "string"}}
52
+ },
53
+ "indexPathSegment": {
54
+ "type": "object",
55
+ "additionalProperties": false,
56
+ "required": ["kind", "valueType"],
57
+ "properties": {"kind": {"const": "index"}, "valueType": {"const": "nonNegativeInteger"}}
58
+ },
59
+ "argument": {
60
+ "type": "object",
61
+ "additionalProperties": false,
62
+ "required": ["id", "type"],
63
+ "properties": {
64
+ "id": {"type": "string", "minLength": 1},
65
+ "type": {"enum": ["STRING", "NUMBER", "BOOLEAN"]},
66
+ "normalizesTo": {"const": "pathSegments"},
67
+ "staticLiteral": {"type": "boolean"},
68
+ "minimum": {"type": "number"},
69
+ "maximum": {"type": "number"}
70
+ }
71
+ },
72
+ "server": {
73
+ "type": "object",
74
+ "additionalProperties": false,
75
+ "required": ["supported", "irOperation"],
76
+ "properties": {
77
+ "supported": {"type": "boolean"},
78
+ "irOperation": {"type": "string", "pattern": "^structuredData\\.[A-Za-z][A-Za-z0-9]*$"}
79
+ }
80
+ },
81
+ "block": {
82
+ "type": "object",
83
+ "additionalProperties": false,
84
+ "required": ["opcode", "blockType", "arguments", "resultType", "effect", "immutable", "errors", "server"],
85
+ "properties": {
86
+ "opcode": {"type": "string", "minLength": 1},
87
+ "blockType": {"enum": ["COMMAND", "REPORTER", "BOOLEAN", "LOOP"]},
88
+ "arguments": {"type": "array", "items": {"$ref": "#/$defs/argument"}},
89
+ "resultType": {"enum": ["json", "jsonText", "yamlText", "boolean", "number", "string", "void"]},
90
+ "effect": {"enum": ["pure", "immutable", "state", "control"]},
91
+ "immutable": {"type": "boolean"},
92
+ "errors": {
93
+ "type": "array",
94
+ "uniqueItems": true,
95
+ "items": {
96
+ "enum": ["INVALID_JSON", "INVALID_YAML", "INVALID_NAME", "DATA_NOT_FOUND", "INVALID_PATH", "PATH_NOT_FOUND", "TYPE_MISMATCH", "INDEX_OUT_OF_RANGE", "ITERATION_LIMIT_EXCEEDED", "ITERATION_CONTEXT_REQUIRED", "PARSE_LIMIT_EXCEEDED"]
97
+ }
98
+ },
99
+ "server": {"$ref": "#/$defs/server"}
100
+ }
101
+ }
102
+ }
103
+ }