はじめに

Minds Connect SDK

あなたのアプリケーションをHello Mindsにつなぎます。ユーザーはMindsアカウントでサインインするか、その場でアカウントを作ります。アプリは彼らのマインドを見て、メッセージを送り、一緒に働けます。

Minds Connect SDK は、その接続を行うTypeScriptパッケージです。Webアプリに @animocabrands/minds-connect を追加します。ユーザーはHello Mindsでサインインします。ログインと同意画面はそちらにあり、初めてアカウントを作る人も含まれます。戻ってくると、 oauth.client は Mindsクライアントライブラリ で、彼らのマインドの一覧、メッセージ送信、許可されたその先の操作がすぐにできます。Connectは呼び出しの前にセッションを新しく保ちます。画面はあなたのままです。Connectがリダイレクト、保存されたセッション、アプリからのサインアウトを担当します。
BuilderコンソールでOAuthクライアントを登録し、クライアントIDをSDKにコピーし、登録したリダイレクトURIにコールバックのルートを追加します。以下の例はTypeScriptです。

インストール

型定義はパッケージに含まれます。実行場所はブラウザです。Vite、webpack、または他のバンドラーから読み込みます。Next.jsのApp Routerでは、Reactバインディングを "use client" の境界に置いてください。
npm install @animocabrands/minds-connect
Import用途
@animocabrands/minds-connectReactを使わないTypeScript
@animocabrands/minds-connect/reactReact。オプションのpeerとして react と react-dom 18以降が必要

OAuthクライアントを登録する

OAuthクライアント タブでクライアントを作成します。クライアントIDを clientId にコピーしてください。IDは公開情報です。保存するクライアントシークレットはありません。 リダイレクトURIは、サインインを完了するあなたのアプリのページです。認可オリジンは、サインインを開始してよいサイトです。どちらも、登録した値とスキーム、ホスト、ポートまで一致させます。 ユーザーは同じブラウザタブに留めてください。Connectはそのタブの sessionStorage に一度きりの確認を保存します。新しいタブ、ポップアップ、ブックマークしたコールバックURLではサインインを完了できません。 タブの 利用可能なスコープ が、このクライアントの許可リストです。そこで一覧は編集できません。その中から MindsScope で渡してください。一覧に無いスコープを求めると、サインインは失敗します。 MindsScope.Email はサインインしたユーザーのアカウントのメールで、許可リストに含まれます。 MindsScope.MindsEmail は別のスコープで、マインド自身のアドレスです。

React

ルーターを一度 MindsConnect で包み、ホームページとコールバックで同じクライアントを共有します。オプションはプロバイダのマウント時に読まれます。変えるときはページを再読み込みしてください。 LoginCallback は redirectUri と同じパスに置きます。 signIn() はユーザーをHello Mindsへ送ります。戻ったあとは oauth.client でBuilder APIを呼びます。
import { BrowserRouter, Route, Routes, useNavigate } from "react-router-dom";
import {
  LoginCallback,
  MindsConnect,
  MindsScope,
  useMindsConnect,
  type MindsOAuthOptions,
} from "@animocabrands/minds-connect/react";
 
const opts: MindsOAuthOptions = {
  clientId: "YOUR_CLIENT_ID",
  redirectUri: `${window.location.origin}/callback`,
  scopes: [MindsScope.Email, MindsScope.MindsList],
};
 
export function Root() {
  return (
    <BrowserRouter>
      <MindsConnect opts={opts}>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/callback" element={<Callback />} />
        </Routes>
      </MindsConnect>
    </BrowserRouter>
  );
}
 
function Home() {
  const { isInitialized, isAuthenticated, signIn, signOut, oauth } = useMindsConnect();
 
  if (!isInitialized || !oauth) return <p>Loading…</p>;
  if (!isAuthenticated) {
    return (
      <button type="button" onClick={() => signIn()}>
        Sign in with Minds
      </button>
    );
  }
 
  async function listMinds() {
    const minds = await oauth.client.listMinds();
    console.log(minds);
  }
 
  return (
    <>
      <button type="button" onClick={() => listMinds()}>
        List minds
      </button>
      <button type="button" onClick={() => signOut()}>
        Log out
      </button>
    </>
  );
}
 
function Callback() {
  const navigate = useNavigate();
  return (
    <LoginCallback
      onSuccess={() => navigate("/", { replace: true })}
      onError={(err) => console.error(err)}
    />
  );
}
LoginCallback に子要素を渡さないと、組み込みの状態表示が出ます。子要素を渡すと、それは常に描画されます。 onSuccess でユーザーをホームへ戻してください。 useMindsConnect() は hasScopes 、 tokens 、 getAccessToken も返します。

Reactを使わない場合

手順は同じです。オプションのモジュールを一つ共有し、ボタンからサインインを始め、コールバックページで終えます。コールバックは新しいページ読み込みなので、同じ clientId と redirectUri で MindsOAuth を再び作ります。 onTokensChanged は、このタブでConnectがセッションを書き込むときに動きます。サインアウト、更新、またはストアを消す失敗した更新です。新しいページ読み込みでは動きません。最初の画面を描くときは oauth.tokens を読んでください。
// oauth.ts
import { MindsOAuth, MindsScope, type MindsOAuthOptions } from "@animocabrands/minds-connect";
 
export const opts: MindsOAuthOptions = {
  clientId: "YOUR_CLIENT_ID",
  redirectUri: `${window.location.origin}/callback`,
  scopes: [MindsScope.Email, MindsScope.MindsList],
};
 
export const oauth = new MindsOAuth(opts);
// main.ts — home page
import { oauth } from "./oauth";
 
const connectBtn = document.getElementById("connect");
const listBtn = document.getElementById("list");
const logoutBtn = document.getElementById("logout");
 
oauth.onTokensChanged((tokens) => {
  const signedIn = Boolean(tokens);
  if (connectBtn) connectBtn.hidden = signedIn;
  if (listBtn) listBtn.hidden = !signedIn;
  if (logoutBtn) logoutBtn.hidden = !signedIn;
});
 
connectBtn?.addEventListener("click", async () => {
  await oauth.signIn();
});
 
listBtn?.addEventListener("click", async () => {
  const minds = await oauth.client.listMinds();
  console.log(minds);
});
 
logoutBtn?.addEventListener("click", async () => {
  await oauth.signOut();
});
// callback.ts — same path as redirectUri
import { OAuthRedirectError } from "@animocabrands/minds-connect";
import { oauth } from "./oauth";
 
try {
  await oauth.handleRedirect();
  window.location.replace("/");
} catch (err) {
  if (err instanceof OAuthRedirectError) {
    console.error(err.error, err.errorDescription);
  } else {
    console.error(err);
  }
}
handleRedirect() は返されたstateを確認し、コードを交換し、トークンを保存します。ユーザーが拒否した場合、またはstateが一致しない場合は OAuthRedirectError をスローします。

スコープ

スコープは、サインインしたユーザーがアプリに許すことです。SDKを作るとき、必要な一式を opts.scopes に置きます。 MindsScope は、そのIDのTypeScript定数です。両方のエントリからエクスポートされます。 あとから広げるときは、すでに許可されたスコープも含めた 完全な一覧 を signIn({ scopes }) に渡します。その操作が必要かどうかは hasScopes が知らせます。
import { MindsScope } from "@animocabrands/minds-connect";
 
const scopes = [MindsScope.MindsList, MindsScope.ConversationsList, MindsScope.MessagingSend];
 
if (oauth.tokens && !oauth.hasScopes(scopes)) {
  await oauth.signIn({ scopes });
}
Reactでは、同じ一覧を isAuthenticated 、 hasScopes 、 signIn に使います。 oauth.client が呼べるのは、その許可に含まれるものだけです。 listMinds() には MindsScope.MindsList が必要です。メッセージを送るには MindsScope.MessagingSend が必要です。メソッド一覧は クライアントライブラリ のページにあります。
MindsScopeScopeユーザーが許すこと
MindsScope.Emailemailメールアドレスを見る
MindsScope.MindsListminds:listマインドを見る
MindsScope.MindsStatusminds:statusマインドがオンかどうかを見る
MindsScope.MindsCognitionminds:cognitionマインドの認知を見る
MindsScope.MindsSkillsListminds:skills:listマインドのスキルを見る
MindsScope.MindsToolsListminds:tools:listマインドのツールを見る
MindsScope.MindsAppsListminds:apps:listマインドのアプリを見る
MindsScope.MindsEmailminds:emailマインドのメールを見る
MindsScope.MindsWalletsminds:walletsマインドのウォレットアドレスを見る
MindsScope.MindsAwakenminds:awakenマインドを目覚めさせる
MindsScope.MindsEnableminds:enableマインドをオンにする
MindsScope.MindsDisableminds:disableマインドをオフにする
MindsScope.MindsSkillsEquipminds:skills:equipマインドにスキルを装備する
MindsScope.MindsSkillsUnequipminds:skills:unequipマインドのスキルを外す
MindsScope.MindsToolsEquipminds:tools:equipマインドにツールを装備する
MindsScope.MindsToolsUnequipminds:tools:unequipマインドのツールを外す
MindsScope.MindsAppsEquipminds:apps:equipマインドにアプリを装備する
MindsScope.MindsAppsUnequipminds:apps:unequipマインドのアプリを外す
MindsScope.ConversationsCreateconversations:createマインドとのチャットを始める
MindsScope.ConversationsListconversations:listチャットを見る
MindsScope.ConversationsReadconversations:readマインドとのチャットを見る
MindsScope.MessagingSendmessaging:sendそのユーザーとしてメッセージを送る
MindsScope.MessagingBeaconmessaging:beaconマインドに声をかける
MindsScope.MessagingHistorymessaging:historyチャット履歴を見る
MindsScope.MessagingActivityStreammessaging:activity:stream一つのマインドの動きを見る
MindsScope.MessagingStreammessaging:streamマインド全体のメッセージイベントを見る

呼び出しをどこで行うか

バックエンドの無いWebアプリは、Connectだけで足ります。 oauth.client はクライアントライブラリで、サインインしたユーザーに向いています。Connectは @animocabrands/minds-client-lib に依存するので、ブラウザからの呼び出しのためにそのパッケージを自分で入れる必要はありません。
const minds = await oauth.client.listMinds();
バックエンドもあるときは、サインインとトークン更新はブラウザのConnectに残します。サーバーにはクライアントライブラリを入れ、ページから送られたアクセストークンを渡します。マインドの一覧、メッセージ送信、それより長い処理はそこで行えます。メソッドは同じです。説明は クライアントライブラリ のページにあります。
import { createMindsClient } from "@animocabrands/minds-client-lib";
 
const accessToken = req.headers.authorization?.replace(/^Bearer\s+/i, "");
const minds = await createMindsClient({ accessToken }).listMinds();
getAccessToken() は、まだ有効なトークンを返します。期限の60秒前になると更新します。セッションが無いときは null です。 oauth.tokens は保存されたスナップショットで、すでに期限切れのことがあります。バックエンドへ送るときは getAccessToken() を使ってください。

サインアウト

signOut() はアプリ内のセッションを消し、リフレッシュトークンを無効にします。Hello Mindsのアカウントはサインインしたままなので、次の訪問ではアカウントを作り直さずに続けられます。
await oauth.signOut();

セッション

セッションは localStorage に、 minds_oauth_session: とクライアントIDを繋げたキーで保存されます。再読み込みしても、このオリジンの他のタブでも残ります。ページ上のどのスクリプトも読めます。 別の保存先が要るときは storage を渡します。 TokenStore を拡張し、 get 、 set 、 clear を実装してください。 signOut() はそのストアを消します。
フィールド意味
accessTokenBuilder API呼び出し用のBearerトークン
refreshToken更新のたびに置き換わる。ストアは最新を保持する
expiresInストアを読んだ時点の残り秒数
scope許可されたスコープ。空白区切り。確認には hasScopes を使う

オプション

同じオブジェクトを new MindsOAuth(opts) と MindsConnect に渡します。
項目必須既定渡すもの
clientIdはい—OAuthクライアント タブの公開クライアントID
redirectUriはい—登録したコールバックURL。オリジンを含む
scopesはい—最初の signIn() に使う MindsScope の完全な一覧。空にはできない。アカウントのメールが要るときは MindsScope.Email を含める
storageいいえ"localStorage""localStorage"、または独自の TokenStore
signIn() には state (文字列またはオブジェクト。 handleRedirect から戻る)と scopes (その回だけ opts.scopes を置き換える完全な一覧)も渡せます。

メソッド

領域呼び出すもの
サインインsignIn, handleRedirect
セッションgetAccessToken, tokens, hasScopes, onTokensChanged, signOut
Builder APIclient — クライアントライブラリ( listMinds 、 sendMessage 、ほか)
ReactMindsConnect, useMindsConnect, LoginCallback
MindsOAuth 、 MindsScope 、 OAuthRedirectError 、 TokenStore 、および型 MindsOAuthOptions 、 TokenSuccess 、 SignInOptions 、 OAuthSession は @animocabrands/minds-connect からエクスポートされます。Reactエントリは MindsScope を再エクスポートします。