Murasaki

Deep Link と File Association

URL scheme と document type を登録し、すべての open request を Node Main で処理します。

Murasaki は packaged macOS / Windows app の custom URL scheme と document extension を登録できます。cold launch と起動済み app への request は、どちらも同じ Node Main の openRequested() hook に届きます。

Handler を設定する

アプリが扱う scheme と extension を murasaki.config.ts に宣言します。

murasaki.config.ts
import { defineConfig } from 'murasaki'

export default defineConfig({
  appId: 'com.example.violet',
  productName: 'Violet',

  protocols: [
    { scheme: 'violet', name: 'Violet Link' },
  ],

  fileAssociations: [
    {
      extensions: ['vnote'],
      name: 'Violet Note',
      description: 'Violet で作成したノート',
      role: 'editor',
      mimeType: 'application/x-violet-note',
    },
  ],
})

extension は先頭のドットなしで指定します。scheme と extension は lowercase に 正規化されます。重複値、予約済みbrowser/OS scheme (blobfilehttphttpsjavascriptmailtoms-settingstelmurasakiなど)、 不正な scheme / extension / MIME type は build 時に拒否されます。全 field と default は 設定リファレンスを参照してください。

Open request を処理する

Node Main entry を作り、openRequested(context, event) を実装します。platform や transport ではなく、各 target の kind で分岐してください。

src/main.ts
import { defineMain } from 'murasaki/main'

export default defineMain({
  async ready({ paths }) {
    // 最初に DB や service を初期化する。
    console.log('data directory:', paths.data)
  },

  async openRequested(_context, event) {
    for (const target of event.targets) {
      if (target.kind === 'url') {
        const url = new URL(target.url)
        if (url.hostname !== 'open') continue

        // 実行前に route を検証し、認可する。
        console.log('open link:', url.pathname)
      } else {
        // file を読む前に所有範囲、size、内容を検証する。
        console.log('open document:', target.path)
      }
    }
  },
})

Murasaki は ready() の完了後に openRequested() を呼びます。DB などの長寿命 resource を一度初期化してから、cold-start と running-app request を同じ handler で 処理できます。

Event reference

type OpenTarget =
  | { kind: 'url'; url: string; scheme: string }
  | { kind: 'file'; path: string }

interface OpenRequestEvent {
  activation: 'cold-start' | 'second-instance' | 'os-event'
  transport: 'argv' | 'open-url' | 'open-file'
  targets: OpenTarget[]
  cwd?: string
}
Field意味
activation最初の launch に伴う request、2つ目の process から転送された request、native OS event のいずれか。
transportnative delivery mechanism。診断用であり、通常の app logic は target.kind を使います。
targets設定済み scheme / extension と一致した URL / file のみ。1 event に複数 file が入る場合があります。
cwdargv-based launch の working directory。native OS event ではありません。

2つ目の executable launch では、secondInstance() に raw argv / cwd が届き、 openRequested() には認識済み URL / file target が届きます。同じ open operation を 両方の hook で実行しないでください。一般的な activation behavior は secondInstance()、link / file の意味的な処理は openRequested() に置きます。

Packaging の動作

Artifact登録と delivery
macOS .appmurasaki bundle が URL / document metadata を app の Info.plist に書き込みます。Launch Services は起動済み app を含めて URL / file open を配送します。.dmg はこの .app を収録します。最終テスト前に Applications へ移動してください。
Windows NSIS .exeinstaller が installer.windows.installMode に従い per-user / per-machine の protocol / file association を登録します。起動された URL / file は argv から正規化されます。
Windows MSIMSI が per-machine の protocol / file association を登録します。起動された URL / file は argv から正規化されます。
Windows portable archiveregistry entry を作りません。protocols / fileAssociations を設定しても OS handler にはなりません。
Linuxprotocol / MIME registration は未実装です。Linux の Deep Link / file association 対応を告知しないでください。
murasaki devsystem handler metadata を install しません。OS integration は install/package 済み artifact でテストしてください。

Windows の登録は app を利用可能な handler に追加しますが、user の現在の default app を 勝手に変更しません。release 間で appId を維持し、installer ownership と association identifier を安定させてください。

Packaged handler をテストする

installer を実行するか packaged app を Applications へ移動した後、cold launch と 起動済み app の両方をテストします。

macOS
open 'violet://open/note-42'
open -a Violet ./example.vnote
Windows PowerShell
Start-Process 'violet://open/note-42'
Start-Process '.\example.vnote'

clean machine で NSIS / MSI の実際の uninstall / upgrade path もテストしてください。 実行ファイルへ argument を直接渡す方法は handler code の確認には使えますが、OS registration が正しく install されたことの確認にはなりません。

Security

URL、file path、launch argument はすべて信頼できない input です。任意の local process が 偽の URL / path で executable を起動できます。custom scheme は送信元を証明しません。

  • 期待する URL host、path、action、parameter shape を allowlist で検証する
  • bearer token や長期 credential を Deep Link URL に入れない。sign-in callback には one-time code、state、PKCE を使う
  • query string、fragment、機密性のある path を log / crash report から除外する
  • file parse 前に size、permission、format、content を確認する。期待した extension だけでは 安全性を証明できない
  • symlink と、検証から使用までの間に file が変化する可能性を考慮する
  • 処理は Node Main に置き、検証済みの最小限の data だけを renderer へ送る

次へ

On this page