시작하기

Minds Connect SDK

애플리케이션을 Hello Minds에 연결하세요. 사용자는 Minds 계정으로 로그인하거나 그 자리에서 계정을 만듭니다. 앱은 그들의 마인드를 보고, 메시지를 보내고, 함께 일할 수 있습니다.

Minds Connect SDK는 그 연결을 만드는 TypeScript 패키지입니다. 웹 앱에 @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마인드 전체의 메시징 이벤트를 봅니다

호출을 어디서 하나

백엔드가 없는 웹 앱은 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를 다시 내보냅니다.