Named Data

TurboWarp カスタム拡張機能 · Composition API · v0.4.0

データはコピーせず、名前で共有する。

Named Data は、非サンドボックスで動く TurboWarp 拡張機能どうしが共有する データ契約と provider registry です。ある拡張機能が namespace と kind に対して provider を登録すると、別の拡張機能は namespace + name + kind + scope で参照を解決し、メタデータとバイト列またはストリームを受け取れます。 payload そのものが registry を経由することはありません。

参照
Registry
Provider
メタデータ + 本体

利用している拡張機能

ほかの拡張機能を支える基盤です。

Named Data 自体のブロックはほとんどありません。価値は、データを持つ拡張機能どうしが 共有する registry にあります。別々にバンドルされた拡張機能も、固定キー Symbol.for('@kubohiroya/turbowarp-named-data/registry') で同じ registry を見つけるため、読み込み順やバンドル構成によって registry が分裂しません。

Asset Cache

名前付きの画像・音声・テキスト素材を asset kind として公開します。

Structured Data

JSON・YAML の値を structured kind として公開します。schema 識別子も付けられます。

Document Data

HTML・Markdown 文書を document kind として公開します。

Binary Data

生のバイト列を binary kind として公開し、ほかの拡張機能がストリームで読めるようにします。

はじめに

有効にする、読み込む、確かめる。

registry は起動時に固定される機能で、既定では無効です。フラグは バンドルの起動時に一度だけ読まれるため、拡張機能を読み込む前に設定してください。

  1. 機能フラグを有効にする

    ホストページで、または動作確認ならエディタのブラウザコンソールで設定します。

    globalThis.__TW_NAMED_DATA_FEATURE_FLAGS__ = {
      NAMED_DATA_REGISTRY_MVP: true
    };
  2. 拡張機能を読み込む

    TurboWarp で 拡張機能を追加 → カスタム拡張機能 を選び、次のファイルを指定して サンドボックスなしで実行 を有効にします。

    https://cdn.jsdelivr.net/npm/@kubohiroya/turbowarp-named-data@0.4.0/dist/named-data.js
  3. 使えるか確かめる

    唯一の真偽ブロックで、共有 registry が導入されたことを確認できます。

    もし <named data registry available?> なら
      [ready] と言う

仕組み

registry は振り分けるだけ。データは provider が持つ。

registry が保持するのは、(namespace, kind) をキーにした provider の登録と、 現在開かれている本体の解放コールバックだけです。payload、保存、キャッシュはすべて 各 provider の中にとどまります。

参照を解決する流れ

利用側は参照、表現形式、ターゲットまたはプロジェクトのコンテキストを registry に渡します。 registry は参照の namespace と kind に登録された provider を選び、解決できるかを確認してから stat または openBody を呼びます。利用側はメタデータと借用した本体を受け取り、使い終えたら解放します。

参照に含まれるもの

フィールド値意味
namespace 英小文字で始まり、a-z 0-9 . - で最大 64 文字 論理的な所有ドメイン。kind が異なる provider は同じ namespace を共有できます。
name provider が定める文字列 namespace 内での値の名前。
kind structured、document、binary、asset データの種類。namespace と組み合わせて provider を選びます。
scope target、project target にはターゲット識別子、project にはプロジェクト識別子が必要です。互いに代用されることはありません。
schemaRef(任意) {id, version} structured 参照のみ。安定した schema ID と完全な SemVer で、schema 本体は含みません。

provider が返すもの

メタデータ

  • nativeRepresentation:provider が保存している形式
  • representation:今回の本体で選ばれた形式
  • mediaType、任意の byteLength と sha256- ダイジェスト
  • revision:不透明な文字列。解析や大小比較はしない
  • replayable:本体を再読できるか

本体

  • Uint8Array または ReadableStream<Uint8Array>
  • 利用側へ直接返され、registry には保存されない
  • 借用物なので、使い終えたら release(reason) を呼ぶ

Composition API

自作の拡張機能から提供・利用する。

ほかのパッケージは副作用のない ESM エントリポイントを import します。import しても TurboWarp 拡張機能は登録されず、契約、registry 関数、機能フラグの宣言だけが公開されます。

pnpm add --save-exact @kubohiroya/turbowarp-named-data@0.4.0

provider を登録する

import {
  installNamedDataRegistry,
  type NamedDataProvider
} from '@kubohiroya/turbowarp-named-data/composition';

const registry = installNamedDataRegistry(runtime);
const provider: NamedDataProvider = {
  namespace: 'com.example.notes',
  kind: 'document',
  canResolve: (ref, rep) => rep === 'markdown',
  stat: (ref, rep, ctx) => ({ /* メタデータ */ }),
  openBody: (ref, rep, ctx) => ({ /* メタデータ, body, release */ }),
  release: () => {}
};
const registration = registry.registerProvider(provider);

同じ (namespace, kind) に 2 つ目の provider を登録すると NAMED_DATA_PROVIDER_CONFLICT で失敗します。

参照を解決する

import {getNamedDataRegistry}
  from '@kubohiroya/turbowarp-named-data/composition';

const registry = getNamedDataRegistry(runtime);
const opened = await registry?.openBody(
  {namespace: 'com.example.notes', name: 'intro',
   kind: 'document', scope: 'project'},
  'markdown',
  {project: projectIdentity}
);
try {
  // opened.body を読む
} finally {
  await opened?.release('complete');
}

registry が導入されていなければ getNamedDataRegistry は undefined を返します。

エクスポート用途
installNamedDataRegistry(runtime)共有 registry を導入する。互換な registry が既にあればそれを返す。
getNamedDataRegistry(runtime)導入せずに共有 registry を取得する。
bindNamedDataRegistryLifecycle(runtime, registry)PROJECT_STOP_ALL でセッション状態を消去する。解除関数を返し、参照カウントで管理される。
NamedDataError、NAMED_DATA_ERROR_CODES安定した NAMED_DATA_* コードを投げる・判定する。
NAMED_DATA_KINDS、NAMED_DATA_SCOPES、NAMED_DATA_REPRESENTATIONS正規の一覧で入力を検証する。
FEATURE_FLAGSバンドル起動時に確定したフラグを読む。

型定義は dist/types/composition.d.ts から提供されます。通信で扱える参照の形は JSON Schema としても公開しています。

ライフサイクルと schema 識別子

停止で片付け、schema は名前で指定し推測しない。

プロジェクトを停止したとき

  1. 開いているすべての本体ハンドルが解放されます。
  2. セッション provider は登録解除され、解放されます。
  3. 永続 provider は登録を保ったまま clearSession() を実行します。

{lifetime: 'persistent'} を指定しない登録はセッション単位です。解放処理は 冪等なので、provider を複数回解放しても安全です。

任意の schema 参照

structured 参照には schemaRef: {id, version} を付けられます。例: {id: 'com.example.profile', version: '1.2.0'}。provider はメタデータで まったく同じ識別子を返す必要があります。registry が運ぶのは識別子だけで、schema 文書、 バリデータ、JSON 値は provider と利用側の責任です。provider が schema 参照を公開するのは、 別の起動時フラグ NAMED_DATA_SCHEMA_REF が有効なとき(既定は無効)だけです。

リファレンス

ブロック・フラグ・エラーコード

やりたいこと使うもの重要な挙動
registry があるかをスクリプトで確かめるnamed data registry available?NAMED_DATA_REGISTRY_MVP が有効な間だけ表示されます。
registry を有効にするNAMED_DATA_REGISTRY_MVP: trueバンドル起動時に一度だけ読まれます。既定は無効。
schema 識別子を公開するNAMED_DATA_SCHEMA_REF: trueprovider 向けのオプトイン。既定は無効。
データを登録・読み取りするComposition API拡張機能間の API のみで、本体を扱う値ブロックはありません。

ブロックの全仕様は英語版の完全なブロックリファレンスを参照してください。

エラーコード

コード意味
NAMED_DATA_INVALID_REF参照または provider の記述が不正です。
NAMED_DATA_INVALID_REGISTRY共有シンボルの位置に互換でないオブジェクトがあります。上書きはされません。
NAMED_DATA_PROVIDER_CONFLICTこの (namespace, kind) には既に provider が登録されています。
NAMED_DATA_PROVIDER_NOT_FOUNDこの namespace に provider が登録されていません。
NAMED_DATA_KIND_MISMATCHnamespace に provider はあるが、この kind のものはありません。
NAMED_DATA_NOT_FOUNDprovider にその名前の値がありません。
NAMED_DATA_SCOPE_MISMATCHscope が求めるターゲットまたはプロジェクトの識別子がコンテキストにありません。
NAMED_DATA_SCHEMA_NOT_FOUND / …_VERSION_MISMATCH / …_UNRESOLVEDschema 識別子がない、異なる、または解決できません。
NAMED_DATA_REPRESENTATION_UNSUPPORTEDprovider が要求された表現形式を生成できません。
NAMED_DATA_INVALID_METADATAprovider が返したメタデータまたは本体が検証に失敗しました。
NAMED_DATA_BODY_TOO_LARGE本体が provider または利用側の上限を超えています。
NAMED_DATA_ABORTEDコンテキストの AbortSignal が中断を通知しました。
NAMED_DATA_PROVIDER_RELEASED要求の前または途中で provider が解放されました。

トラブル対処

参照が解決できないとき

パレットにブロックが表示されない
バンドル起動時に NAMED_DATA_REGISTRY_MVP が true ではありませんでした。 先に globalThis.__TW_NAMED_DATA_FEATURE_FLAGS__ を設定し、エディタを再読み込みしてから 拡張機能を読み込み直してください。読み込み後にフラグを変えても効果はありません。
拡張機能が読み込めない
Named Data はサンドボックスなしで実行する必要があります。カスタム拡張機能ダイアログで サンドボックスなしで実行 を有効にしてください。信頼できる拡張機能コードだけを読み込んでください。
2 つの拡張機能が別々の registry を見ている
両方が同じ TurboWarp ランタイムに対して installNamedDataRegistry または getNamedDataRegistry を使う必要があります。拡張機能内で作った私的な registry は共有されません。 シンボルの位置に互換でないオブジェクトがある場合は NAMED_DATA_INVALID_REGISTRY で失敗します。
target scope の参照がプロジェクトのコンテキストで失敗する
target scope には context.target、project scope には context.project が必要です。 registry は一方を他方で代用せず、NAMED_DATA_SCOPE_MISMATCH を報告します。
停止ボタンを押すとデータが消える
セッション provider は PROJECT_STOP_ALL で解放されます。長く使う provider は {lifetime: 'persistent'} で登録し、clearSession() で実行ごとの状態だけを消去してください。