@wcstack/fetch 1.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.
package/README.ja.md ADDED
@@ -0,0 +1,625 @@
1
+ # @wcstack/fetch
2
+
3
+ `@wcstack/fetch` は wcstack エコシステムのためのヘッドレス fetch コンポーネントです。
4
+
5
+ 視覚的な UI ウィジェットではありません。
6
+ HTTP リクエストとリアクティブな状態をつなぐ **I/O ノード** です。
7
+
8
+ `@wcstack/state` と組み合わせると、`<wcs-fetch>` はパス契約を通じて直接バインドできます:
9
+
10
+ - **入力 / コマンドサーフェス**: `url`, `body`, `trigger`
11
+ - **出力ステートサーフェス**: `value`, `loading`, `error`, `status`
12
+
13
+ つまり、非同期通信を HTML 内で宣言的に表現できます。UI レイヤーに `fetch()`、`async/await`、loading/error のグルーコードを書く必要はありません。
14
+
15
+ `@wcstack/fetch` は [HAWC](https://github.com/wc-bindable-protocol/wc-bindable-protocol/blob/main/docs/articles/HAWC.md) アーキテクチャに従います:
16
+
17
+ - **Core** (`FetchCore`) が HTTP、abort、非同期状態を処理
18
+ - **Shell** (`<wcs-fetch>`) がその状態を DOM に接続
19
+ - フレームワークやバインディングシステムは [wc-bindable-protocol](https://github.com/wc-bindable-protocol/wc-bindable-protocol) 経由で利用
20
+
21
+ ## なぜこれが存在するのか
22
+
23
+ 多くのフロントエンドアプリで、移行が最も困難なのはテンプレートではなく、非同期ロジックです。
24
+ HTTP リクエスト、ローディングフラグ、エラー処理、リトライ、ライフサイクルのクリーンアップ。
25
+
26
+ `@wcstack/fetch` はその非同期ロジックを再利用可能なコンポーネントに移し、結果をバインド可能な状態として公開します。
27
+
28
+ `@wcstack/state` と組み合わせたフローは:
29
+
30
+ 1. 状態が `url` を算出
31
+ 2. `<wcs-fetch>` がリクエストを実行
32
+ 3. 非同期の結果が `value`, `loading`, `error`, `status` として返る
33
+ 4. UI は `data-wcs` でそれらのパスにバインド
34
+
35
+ 非同期通信が命令的な UI コードではなく、**状態遷移**になります。
36
+
37
+ ## インストール
38
+
39
+ ```bash
40
+ npm install @wcstack/fetch
41
+ ```
42
+
43
+ ## クイックスタート
44
+
45
+ ### 1. 状態からのリアクティブ fetch
46
+
47
+ `url` が変わると、`<wcs-fetch>` は自動的に新しいリクエストを実行します。
48
+ 既にリクエストが進行中の場合、前のリクエストは abort されます。
49
+
50
+ ```html
51
+ <script type="module" src="https://esm.run/@wcstack/state/auto"></script>
52
+ <script type="module" src="https://esm.run/@wcstack/fetch/auto"></script>
53
+
54
+ <wcs-state>
55
+ <script type="module">
56
+ export default {
57
+ users: [],
58
+ get usersUrl() {
59
+ return "/api/users";
60
+ },
61
+ };
62
+ </script>
63
+
64
+ <wcs-fetch data-wcs="url: usersUrl; value: users"></wcs-fetch>
65
+
66
+ <ul>
67
+ <template data-wcs="for: users">
68
+ <li data-wcs="textContent: users.*.name"></li>
69
+ </template>
70
+ </ul>
71
+ </wcs-state>
72
+ ```
73
+
74
+ これがデフォルトモードです:
75
+
76
+ - `url` を接続
77
+ - `value` を受け取る
78
+ - 任意で `loading`、`error`、`status` もバインド
79
+
80
+ ### 2. リアクティブ URL の例
81
+
82
+ 算出 URL がデータ取得を自動的に駆動します:
83
+
84
+ ```html
85
+ <wcs-state>
86
+ <script type="module">
87
+ export default {
88
+ filterRole: "",
89
+ users: [],
90
+
91
+ get usersUrl() {
92
+ const role = this.filterRole;
93
+ return role ? "/api/users?role=" + role : "/api/users";
94
+ },
95
+ };
96
+ </script>
97
+
98
+ <select data-wcs="value: filterRole">
99
+ <option value="">すべて</option>
100
+ <option value="admin">Admin</option>
101
+ <option value="staff">Staff</option>
102
+ </select>
103
+
104
+ <wcs-fetch
105
+ data-wcs="url: usersUrl; value: users; loading: listLoading; error: listError">
106
+ </wcs-fetch>
107
+
108
+ <template data-wcs="if: listLoading">
109
+ <p>読み込み中...</p>
110
+ </template>
111
+ <template data-wcs="if: listError">
112
+ <p>ユーザーの読み込みに失敗しました。</p>
113
+ </template>
114
+
115
+ <ul>
116
+ <template data-wcs="for: users">
117
+ <li data-wcs="textContent: users.*.name"></li>
118
+ </template>
119
+ </ul>
120
+ </wcs-state>
121
+ ```
122
+
123
+ ### 3. `trigger` による手動実行
124
+
125
+ 入力を先に準備し、後から実行したい場合は `manual` を使います。
126
+
127
+ ```html
128
+ <wcs-state>
129
+ <script type="module">
130
+ export default {
131
+ users: [],
132
+ shouldRefresh: false,
133
+
134
+ reload() {
135
+ this.shouldRefresh = true;
136
+ },
137
+ };
138
+ </script>
139
+
140
+ <wcs-fetch
141
+ url="/api/users"
142
+ manual
143
+ data-wcs="trigger: shouldRefresh; value: users; loading: listLoading">
144
+ </wcs-fetch>
145
+
146
+ <button data-wcs="onclick: reload">更新</button>
147
+ </wcs-state>
148
+ ```
149
+
150
+ `trigger` は **単方向のコマンドサーフェス** です:
151
+
152
+ - `true` を書き込むと `fetch()` を開始
153
+ - 完了後に自動で `false` にリセット
154
+ - リセット時に `wcs-fetch:trigger-changed` を発火
155
+
156
+ ```
157
+ 外部からの書き込み: false → true イベントなし(fetch を開始)
158
+ 自動リセット: true → false wcs-fetch:trigger-changed を発火
159
+ ```
160
+
161
+ ### 4. リアクティブ body での POST
162
+
163
+ ```html
164
+ <wcs-state>
165
+ <script type="module">
166
+ export default {
167
+ newUser: {
168
+ name: "",
169
+ email: "",
170
+ },
171
+ submitRequest: false,
172
+ submitResult: null,
173
+ submitError: null,
174
+
175
+ submit() {
176
+ this.submitRequest = true;
177
+ },
178
+ };
179
+ </script>
180
+
181
+ <input data-wcs="value: newUser.name" placeholder="名前">
182
+ <input data-wcs="value: newUser.email" placeholder="メール">
183
+
184
+ <button data-wcs="onclick: submit">作成</button>
185
+
186
+ <wcs-fetch
187
+ url="/api/users"
188
+ method="POST"
189
+ manual
190
+ data-wcs="
191
+ body: newUser;
192
+ trigger: submitRequest;
193
+ value: submitResult;
194
+ error: submitError;
195
+ loading: submitLoading
196
+ ">
197
+ <wcs-fetch-header name="Content-Type" value="application/json"></wcs-fetch-header>
198
+ </wcs-fetch>
199
+
200
+ <template data-wcs="if: submitLoading">
201
+ <p>送信中...</p>
202
+ </template>
203
+ <template data-wcs="if: submitError">
204
+ <p>送信に失敗しました。</p>
205
+ </template>
206
+ </wcs-state>
207
+ ```
208
+
209
+ ## ステートサーフェス vs コマンドサーフェス
210
+
211
+ `<wcs-fetch>` は 2 種類のプロパティを公開します。
212
+
213
+ ### 出力ステート(バインド可能な非同期状態)
214
+
215
+ 現在のリクエストの結果を表し、HAWC のメインサーフェスです:
216
+
217
+ | プロパティ | 型 | 説明 |
218
+ |------------|------|------|
219
+ | `value` | `any` | レスポンスデータ |
220
+ | `loading` | `boolean` | リクエスト実行中は `true` |
221
+ | `error` | `WcsFetchHttpError \| Error \| null` | HTTP またはネットワークエラー |
222
+ | `status` | `number` | HTTP ステータスコード |
223
+
224
+ ### 入力 / コマンドサーフェス
225
+
226
+ HTML、JS、または `@wcstack/state` バインディングからリクエスト実行を制御します:
227
+
228
+ | プロパティ | 型 | 説明 |
229
+ |------------|------|------|
230
+ | `url` | `string` | リクエスト URL |
231
+ | `body` | `any` | リクエストボディ(`fetch()` 後に `null` にリセット) |
232
+ | `trigger` | `boolean` | 単方向の実行トリガー |
233
+ | `manual` | `boolean` | 接続時 / URL 変更時の自動実行を無効化 |
234
+
235
+ ## アーキテクチャ
236
+
237
+ `@wcstack/fetch` は HAWC アーキテクチャに従います。
238
+
239
+ ### Core: `FetchCore`
240
+
241
+ `FetchCore` は純粋な `EventTarget` クラスです。
242
+ 以下を内包します:
243
+
244
+ - HTTP 実行
245
+ - abort 制御
246
+ - 非同期状態遷移
247
+ - `wc-bindable-protocol` 宣言
248
+
249
+ `EventTarget` と `fetch` をサポートする任意のランタイムでヘッドレスに動作します。
250
+
251
+ ### Shell: `<wcs-fetch>`
252
+
253
+ `<wcs-fetch>` は `FetchCore` の薄い `HTMLElement` ラッパーです。
254
+ 以下を追加します:
255
+
256
+ - 属性 / プロパティマッピング
257
+ - DOM ライフサイクル統合
258
+ - `trigger` などの宣言的実行ヘルパー
259
+
260
+ この分離により、非同期ロジックのポータビリティを保ちながら、`@wcstack/state` のような DOM ベースのバインディングシステムとの自然な連携を可能にしています。
261
+
262
+ ### Target injection
263
+
264
+ Core は **target injection** により Shell 上で直接イベントを発火するため、イベントの再ディスパッチは不要です。
265
+
266
+ ## ヘッドレス利用(Core 単体)
267
+
268
+ `FetchCore` は DOM なしで単体利用できます。`static wcBindable` を宣言しているため、`@wc-bindable/core` の `bind()` で状態をサブスクライブできます — フレームワークアダプタと同じ仕組みです:
269
+
270
+ ```typescript
271
+ import { FetchCore } from "@wcstack/fetch";
272
+ import { bind } from "@wc-bindable/core";
273
+
274
+ const core = new FetchCore();
275
+
276
+ const unbind = bind(core, (name, value) => {
277
+ console.log(`${name}:`, value);
278
+ });
279
+
280
+ await core.fetch("/api/users");
281
+
282
+ unbind();
283
+ ```
284
+
285
+ Node.js、Deno、Cloudflare Workers など、`EventTarget` と `fetch` が利用可能な環境で動作します。
286
+
287
+ ## URL の監視
288
+
289
+ `<wcs-fetch>` はデフォルトで以下のタイミングに自動的にリクエストを実行します:
290
+
291
+ 1. DOM に接続され、`url` が設定されているとき
292
+ 2. `url` が変更されたとき
293
+
294
+ URL 変更時にリクエストが進行中の場合、前のリクエストは自動的に abort されてから新しいリクエストが開始されます。
295
+
296
+ `manual` 属性を設定すると自動実行が無効になり、`fetch()` メソッドや `trigger` プロパティで明示的に制御できます。
297
+
298
+ ## プログラムからの利用
299
+
300
+ ```javascript
301
+ const fetchEl = document.querySelector("wcs-fetch");
302
+
303
+ // JS API 経由で body を設定(<wcs-fetch-body> より優先)
304
+ fetchEl.body = { name: "田中" };
305
+ await fetchEl.fetch();
306
+ // 注意: body は fetch() 後に自動で null にリセットされます。
307
+ // 再度送信する場合は、毎回 body を設定してください。
308
+
309
+ console.log(fetchEl.value); // レスポンスデータ
310
+ console.log(fetchEl.status); // HTTP ステータスコード
311
+ console.log(fetchEl.loading); // boolean
312
+ console.log(fetchEl.error); // エラー情報 or null
313
+ console.log(fetchEl.body); // null(fetch 後にリセット済み)
314
+ ```
315
+
316
+ ## HTML リプレースモード
317
+
318
+ `target` を設定すると、`<wcs-fetch>` は対象要素の `innerHTML` を差し替えます。
319
+
320
+ ```html
321
+ <div id="content">初期コンテンツ</div>
322
+ <wcs-fetch url="/api/partial" target="content"></wcs-fetch>
323
+ ```
324
+
325
+ このモードはシンプルなフラグメント読み込みに便利ですが、`@wcstack/state` との**ステート駆動**な利用とは別の機能です。
326
+
327
+ ## オプションの DOM トリガー
328
+
329
+ `autoTrigger` が有効(デフォルト)の場合、`data-fetchtarget` 属性を持つ要素のクリックで対応する `<wcs-fetch>` が実行されます:
330
+
331
+ ```html
332
+ <button data-fetchtarget="user-fetch">ユーザー読み込み</button>
333
+ <wcs-fetch id="user-fetch" url="/api/users"></wcs-fetch>
334
+ ```
335
+
336
+ イベント委譲を使用しているため、動的に追加された要素でも動作します。`closest()` API により、ネストされた子要素(ボタン内のアイコン等)のクリックも検出します。
337
+
338
+ 指定した id に一致する要素が存在しない場合、または一致した要素が `<wcs-fetch>` でない場合、クリックは無視されます(エラーは発生しません)。
339
+
340
+ これは便利機能です。
341
+ wcstack アプリケーションでは、**`trigger` によるステート駆動のトリガー**が通常の主要パターンです。
342
+
343
+ ## 要素一覧
344
+
345
+ ### `<wcs-fetch>`
346
+
347
+ | 属性 | 型 | デフォルト | 説明 |
348
+ |------|------|------------|------|
349
+ | `url` | `string` | — | リクエスト URL |
350
+ | `method` | `string` | `GET` | HTTP メソッド |
351
+ | `target` | `string` | — | HTML リプレース対象の DOM 要素 id |
352
+ | `manual` | `boolean` | `false` | 自動実行を無効化 |
353
+
354
+ | プロパティ | 型 | 説明 |
355
+ |------------|------|------|
356
+ | `value` | `any` | レスポンスデータ |
357
+ | `loading` | `boolean` | リクエスト実行中は `true` |
358
+ | `error` | `WcsFetchHttpError \| Error \| null` | エラー情報 |
359
+ | `status` | `number` | HTTP ステータスコード |
360
+ | `body` | `any` | リクエストボディ(`fetch()` 後に `null` にリセット) |
361
+ | `trigger` | `boolean` | `true` を設定すると fetch を実行 |
362
+ | `manual` | `boolean` | 明示的実行モード |
363
+
364
+ | メソッド | 説明 |
365
+ |----------|------|
366
+ | `fetch()` | HTTP リクエストを実行 |
367
+ | `abort()` | 実行中のリクエストをキャンセル |
368
+
369
+ ### `<wcs-fetch-header>`
370
+
371
+ リクエストヘッダを定義。`<wcs-fetch>` の子要素として配置。
372
+
373
+ | 属性 | 型 | 説明 |
374
+ |------|------|------|
375
+ | `name` | `string` | ヘッダ名 |
376
+ | `value` | `string` | ヘッダ値 |
377
+
378
+ ### `<wcs-fetch-body>`
379
+
380
+ リクエストボディを定義。`<wcs-fetch>` の子要素として配置。
381
+
382
+ | 属性 | 型 | デフォルト | 説明 |
383
+ |------|------|------------|------|
384
+ | `type` | `string` | `application/json` | Content-Type |
385
+
386
+ 要素のテキストコンテンツがボディとして送信されます。
387
+
388
+ 例:
389
+
390
+ ```html
391
+ <wcs-fetch url="/api/users" method="POST">
392
+ <wcs-fetch-header name="Authorization" value="Bearer token123"></wcs-fetch-header>
393
+ <wcs-fetch-header name="Accept" value="application/json"></wcs-fetch-header>
394
+ <wcs-fetch-body type="application/json">
395
+ {"name": "田中", "email": "tanaka@example.com"}
396
+ </wcs-fetch-body>
397
+ </wcs-fetch>
398
+ ```
399
+
400
+ ## wc-bindable-protocol
401
+
402
+ `FetchCore` と `<wcs-fetch>` はどちらも wc-bindable-protocol に準拠しており、プロトコル対応の任意のフレームワークやコンポーネントと相互運用できます。
403
+
404
+ ### Core (`FetchCore`)
405
+
406
+ `FetchCore` は任意のランタイムからサブスクライブできるバインド可能な非同期状態を宣言します:
407
+
408
+ ```typescript
409
+ static wcBindable = {
410
+ protocol: "wc-bindable",
411
+ version: 1,
412
+ properties: [
413
+ { name: "value", event: "wcs-fetch:response",
414
+ getter: (e) => e.detail.value },
415
+ { name: "loading", event: "wcs-fetch:loading-changed" },
416
+ { name: "error", event: "wcs-fetch:error" },
417
+ { name: "status", event: "wcs-fetch:response",
418
+ getter: (e) => e.detail.status },
419
+ ],
420
+ };
421
+ ```
422
+
423
+ ヘッドレスの利用者は `core.fetch(url)` を直接呼ぶため、`trigger` は不要です。
424
+
425
+ ### Shell (`<wcs-fetch>`)
426
+
427
+ Shell は Core の宣言を拡張し、バインディングシステムから宣言的に fetch を実行できるようにします:
428
+
429
+ ```typescript
430
+ static wcBindable = {
431
+ ...FetchCore.wcBindable,
432
+ properties: [
433
+ ...FetchCore.wcBindable.properties,
434
+ { name: "trigger", event: "wcs-fetch:trigger-changed" },
435
+ ],
436
+ };
437
+ ```
438
+
439
+ ## TypeScript 型
440
+
441
+ ```typescript
442
+ import type {
443
+ WcsFetchHttpError, WcsFetchCoreValues, WcsFetchValues
444
+ } from "@wcstack/fetch";
445
+ ```
446
+
447
+ ```typescript
448
+ // HTTP エラー(status >= 400)
449
+ interface WcsFetchHttpError {
450
+ status: number;
451
+ statusText: string;
452
+ body: string;
453
+ }
454
+
455
+ // Core(ヘッドレス)— 4 つの非同期状態プロパティ
456
+ // T のデフォルトは unknown。型引数を渡すと value が型付けされる
457
+ interface WcsFetchCoreValues<T = unknown> {
458
+ value: T;
459
+ loading: boolean;
460
+ error: WcsFetchHttpError | Error | null;
461
+ status: number;
462
+ }
463
+
464
+ // Shell(<wcs-fetch>)— Core を拡張し trigger を追加
465
+ interface WcsFetchValues<T = unknown> extends WcsFetchCoreValues<T> {
466
+ trigger: boolean;
467
+ }
468
+ ```
469
+
470
+ ## なぜ `@wcstack/state` とうまく連携するのか
471
+
472
+ `@wcstack/state` は UI と状態の唯一の契約としてパス文字列を使います。
473
+ `<wcs-fetch>` はこのモデルに自然に適合します:
474
+
475
+ - 状態が `url` を算出
476
+ - `<wcs-fetch>` がリクエストを実行
477
+ - 非同期の結果が `value`, `loading`, `error`, `status` として返る
478
+ - UI は fetch のグルーコードを書かずにそれらのパスにバインド
479
+
480
+ 非同期処理が通常の状態更新と同じように見えるようになります。
481
+
482
+ ## フレームワーク連携
483
+
484
+ `<wcs-fetch>` は HAWC + `wc-bindable-protocol` なので、`@wc-bindable/*` の薄いアダプタを通じて任意のフレームワークで動作します。
485
+
486
+ ### React
487
+
488
+ ```tsx
489
+ import { useWcBindable } from "@wc-bindable/react";
490
+ import type { WcsFetchValues } from "@wcstack/fetch";
491
+
492
+ interface User { id: number; name: string; }
493
+
494
+ function UserList() {
495
+ const [ref, { value: users, loading, error }] =
496
+ useWcBindable<HTMLElement, WcsFetchValues<User[]>>();
497
+
498
+ return (
499
+ <>
500
+ <wcs-fetch ref={ref} url="/api/users" />
501
+ {loading && <p>読み込み中...</p>}
502
+ {error && <p>エラー</p>}
503
+ <ul>
504
+ {users?.map((user) => (
505
+ <li key={user.id}>{user.name}</li>
506
+ ))}
507
+ </ul>
508
+ </>
509
+ );
510
+ }
511
+ ```
512
+
513
+ ### Vue
514
+
515
+ ```vue
516
+ <script setup lang="ts">
517
+ import { useWcBindable } from "@wc-bindable/vue";
518
+ import type { WcsFetchValues } from "@wcstack/fetch";
519
+
520
+ interface User { id: number; name: string; }
521
+
522
+ const { ref, values } = useWcBindable<HTMLElement, WcsFetchValues<User[]>>();
523
+ </script>
524
+
525
+ <template>
526
+ <wcs-fetch :ref="ref" url="/api/users" />
527
+ <p v-if="values.loading">読み込み中...</p>
528
+ <p v-else-if="values.error">エラー</p>
529
+ <ul v-else>
530
+ <li v-for="user in values.value" :key="user.id">{{ user.name }}</li>
531
+ </ul>
532
+ </template>
533
+ ```
534
+
535
+ ### Svelte
536
+
537
+ ```svelte
538
+ <script>
539
+ import { wcBindable } from "@wc-bindable/svelte";
540
+
541
+ let users = $state(null);
542
+ let loading = $state(false);
543
+ </script>
544
+
545
+ <wcs-fetch url="/api/users"
546
+ use:wcBindable={{ onUpdate: (name, v) => {
547
+ if (name === "value") users = v;
548
+ if (name === "loading") loading = v;
549
+ }}} />
550
+
551
+ {#if loading}
552
+ <p>読み込み中...</p>
553
+ {:else if users}
554
+ <ul>
555
+ {#each users as user (user.id)}
556
+ <li>{user.name}</li>
557
+ {/each}
558
+ </ul>
559
+ {/if}
560
+ ```
561
+
562
+ ### Solid
563
+
564
+ ```tsx
565
+ import { createWcBindable } from "@wc-bindable/solid";
566
+ import type { WcsFetchValues } from "@wcstack/fetch";
567
+
568
+ interface User { id: number; name: string; }
569
+
570
+ function UserList() {
571
+ const [values, directive] = createWcBindable<WcsFetchValues<User[]>>();
572
+
573
+ return (
574
+ <>
575
+ <wcs-fetch ref={directive} url="/api/users" />
576
+ <Show when={!values.loading} fallback={<p>読み込み中...</p>}>
577
+ <ul>
578
+ <For each={values.value}>{(user) => <li>{user.name}</li>}</For>
579
+ </ul>
580
+ </Show>
581
+ </>
582
+ );
583
+ }
584
+ ```
585
+
586
+ ### Vanilla — `bind()` を直接利用
587
+
588
+ ```javascript
589
+ import { bind } from "@wc-bindable/core";
590
+
591
+ const fetchEl = document.querySelector("wcs-fetch");
592
+
593
+ bind(fetchEl, (name, value) => {
594
+ console.log(`${name} changed:`, value);
595
+ });
596
+ ```
597
+
598
+ ## 設定
599
+
600
+ ```javascript
601
+ import { bootstrapFetch } from "@wcstack/fetch";
602
+
603
+ bootstrapFetch({
604
+ autoTrigger: true,
605
+ triggerAttribute: "data-fetchtarget",
606
+ tagNames: {
607
+ fetch: "wcs-fetch",
608
+ fetchHeader: "wcs-fetch-header",
609
+ fetchBody: "wcs-fetch-body",
610
+ },
611
+ });
612
+ ```
613
+
614
+ ## 設計メモ
615
+
616
+ - `value`、`loading`、`error`、`status` は **出力ステート**
617
+ - `url`、`body`、`trigger` は **入力 / コマンドサーフェス**
618
+ - `trigger` は意図的に単方向: `true` を書き込むと実行、リセットで完了を通知
619
+ - `body` は `fetch()` 呼び出しごとに `null` にリセット — 再送信時は毎回設定が必要
620
+ - `manual` は実行タイミングを明示的に制御したい場合に有用
621
+ - HTML リプレースモードはオプション。wcstack の主要パターンはステート駆動バインディング
622
+
623
+ ## ライセンス
624
+
625
+ MIT