본문으로 건너뛰기

SDK 참조

미니 프로그램 SDK는 모든 미니 프로그램 iframe에 주입되는 ~2 KB JavaScript 라이브러리입니다. 보안 postMessage 브리지를 통해 AISCouncil 플랫폼과 상호작용하는 메서드를 제공하는 window.ais 네임스페이스를 제공합니다.

SDK 작동 방식

SDK는 iframe의 srcdoc에서 앱의 HTML 이전에 <script> 태그로 주입됩니다. 직접 포함할 필요가 없습니다. 코드가 실행될 때 항상 window.ais로 사용할 수 있습니다.

모든 메서드 호출(platform.* 속성 제외)은 호스트 페이지로 메시지를 보내고 Promise를 반환합니다. 호스트는 권한을 검증하고 요청을 실행한 후 결과를 다시 보냅니다.

앱 코드                      SDK                    호스트 플랫폼
| | |
|-- ais.chat.send("hi")-->| |
| |-- postMessage({ |
| | method: "chat.send", |
| | args: {text: "hi"} |
| | }) ---------------------->|
| | |-- 권한 확인
| | |-- AIS.Chat.send() 실행
| |<-- postMessage({result}) --|
|<-- Promise 해결 --------| |
정보

모든 SDK 메서드는 함수 참조로 동기적으로 사용할 수 있지만, 비동기적으로 해결되는 Promise를 반환합니다. 결과를 얻으려면 항상 await 또는 .then()을 사용하세요.

TypeScript 지원

TypeScript 타입 정의는 sdk/ais.d.ts에서 사용할 수 있습니다. 프로젝트에 참조를 추가하세요:

/// <reference path="./ais.d.ts" />

ais.ready(async () => {
const history = await ais.chat.getHistory(10);
// history는 ais.ChatMessage[] 타입
});

또는 빌드 도구에서 매니페스트 검증을 위해 AisManifestAisPermission 타입을 복사하세요.


라이프사이클

ais.ready(callback)

플랫폼 브리지가 연결되고 준비되었을 때 발생하는 콜백을 등록합니다. 이것이 앱의 진입점입니다. 모든 초기화 로직을 이 콜백 안에 넣으세요.

매개변수타입설명
callback() => void브리지가 준비되었을 때 호출할 함수
ais.ready(async function () {
// 플랫폼이 연결됨, SDK 호출이 이제 작동함
const user = await ais.auth.getUser();
document.getElementById("greeting").textContent = "안녕하세요, " + user.name;
});
주의

ais.ready()가 발생하기 전에 다른 ais.* 메서드를 호출하지 마세요. postMessage 브리지가 아직 설정되지 않았을 수 있으며 호출이 무기한 대기할 수 있습니다.

ais.onShow(callback)

미니 프로그램이 표시될 때마다 발생하는 콜백을 등록합니다 (예: 사용자가 앱 탭으로 다시 전환).

매개변수타입설명
callback() => void표시 시 호출할 함수
ais.onShow(function () {
// 사용자가 앱으로 돌아왔을 때 데이터 새로고침
refreshDashboard();
});

ais.onHide(callback)

미니 프로그램이 숨겨질 때 발생하는 콜백을 등록합니다 (예: 사용자가 채팅이나 다른 앱으로 전환).

매개변수타입설명
callback() => void숨김 시 호출할 함수
ais.onHide(function () {
// 비용이 많이 드는 작업 일시 중지
stopPolling();
});

ais.close()

미니 프로그램을 닫고 채팅 화면으로 돌아갑니다. 이 호출 후 iframe이 제거됩니다.

반환값: Promise<boolean>

document.getElementById("done-btn").addEventListener("click", function () {
ais.close();
});

저장소

IndexedDB로 백업되는 앱별 격리 키-값 저장소. 키는 mp:{app-name}:로 자동 네임스페이스가 지정되어 앱이 서로의 데이터에 접근할 수 없습니다.

권한: 항상 허용됨 -- 권한 필요 없음.

ais.storage.get(key)

키로 값을 검색합니다. 키가 존재하지 않으면 undefined를 반환합니다.

매개변수타입설명
keystring저장소 키

반환값: Promise<unknown> -- 저장된 값 또는 undefined

const count = await ais.storage.get("visit-count");
console.log("방문:", count); // number, string, object, array, 또는 undefined

ais.storage.set(key, value)

키-값 쌍을 저장합니다. 값은 JSON 직렬화 가능한 타입(string, number, boolean, object, array, null)이어야 합니다.

매개변수타입설명
keystring저장소 키
valueunknown저장할 값 (JSON 직렬화 가능해야 함)

반환값: Promise<boolean> -- 성공 시 true

await ais.storage.set("visit-count", 42);
await ais.storage.set("preferences", { theme: "dark", fontSize: 16 });

ais.storage.remove(key)

저장소에서 키를 삭제합니다.

매개변수타입설명
keystring제거할 키

반환값: Promise<boolean> -- 성공 시 true

await ais.storage.remove("temporary-data");

ais.storage.keys()

이 미니 프로그램이 저장한 모든 키를 나열합니다 (내부 mp:{name}: 접두사 제외).

반환값: Promise<string[]>

const keys = await ais.storage.keys();
console.log("저장된 키:", keys); // ['visit-count', 'preferences']

채팅

활성 대화에서 채팅 기록 읽기, 메시지 보내기, 새 메시지 구독.

필요 권한: 읽기는 chat:read, 보내기는 chat:write.

ais.chat.getHistory(limit?)

활성 채팅 세션에서 최근 메시지를 가져옵니다.

매개변수타입기본값설명
limitnumber50반환할 최대 메시지 수

반환값: Promise<ChatMessage[]>

interface ChatMessage {
role: "user" | "assistant" | "system";
content: string;
timestamp?: number;
}
const messages = await ais.chat.getHistory(20);
messages.forEach(function (msg) {
console.log(msg.role + ": " + msg.content);
});

ais.chat.send(text)

사용자로서 메시지를 보냅니다. 활성 AI 모델이 응답을 생성하도록 트리거합니다.

매개변수타입설명
textstring보낼 메시지 텍스트

반환값: Promise<boolean> -- 성공 시 true

await ais.chat.send("마지막 5개 메시지 요약해 줘");
경고

ais.chat.send() 호출은 사용자의 구성된 AI 제공자에 대한 실제 API 호출을 트리거합니다. 토큰을 소비하고 비용이 발생할 수 있습니다. 책임감 있게 사용하고 프로그래밍 방식으로 메시지를 보내기 전에 항상 사용자에게 알리세요.

ais.chat.onMessage(callback)

새 채팅 메시지를 구독합니다. 콜백은 모든 새 메시지(사용자 및 어시스턴트 모두)에 대해 발생합니다.

매개변수타입설명
callback(msg: ChatMessage) => void들어오는 메시지 핸들러
ais.chat.onMessage(function (msg) {
if (msg.role === "assistant") {
// AI 모델이 응답함
updateResponseDisplay(msg.content);
}
});

설정

활성 봇의 설정(제공자, 모델, 시스템 프롬프트 등)을 읽습니다.

필요 권한: config:read

ais.config.get()

전체 봇 설정 객체를 가져옵니다.

반환값: Promise<BotConfig>

interface BotConfig {
n?: string; // 봇 이름
p?: string; // 제공자 ID (예: 'anthropic', 'openai', 'gemini')
m?: string; // 모델 ID (예: 'claude-sonnet-4-20250514')
s?: string; // 시스템 프롬프트
t?: number; // 온도 (0.0 - 2.0)
x?: number; // 최대 출력 토큰
[key: string]: unknown;
}
const config = await ais.config.get();
console.log("사용 중인 모델:", config.m);
console.log("시스템 프롬프트:", config.s);

ais.config.getProvider()

활성 제공자 ID를 가져옵니다.

반환값: Promise<string> -- 예: 'anthropic', 'openai', 'gemini', 'xai', 'openrouter', 'ollama'

const provider = await ais.config.getProvider();
if (provider === "ollama") {
showLocalModelBanner();
}

ais.config.getModel()

활성 모델 ID를 가져옵니다.

반환값: Promise<string> -- 예: 'claude-sonnet-4-20250514', 'gpt-4o', 'gemini-2.5-flash'

const model = await ais.config.getModel();
document.getElementById("model-name").textContent = model;

UI

알림, 확인 대화상자 표시 및 앱 패널 제목 업데이트.

ais.ui.toast(message, duration?)

플랫폼 UI에 임시 토스트 알림을 표시합니다.

매개변수타입기본값설명
messagestring--알림 텍스트 (최대 200자)
durationnumber3000밀리초 단위 지속 시간

반환값: Promise<boolean>

권한: ui:toast (권장되지만 엄격하게 강제되지 않음 -- 토스트는 영향이 적음)

await ais.ui.toast("파일이 저장되었습니다!");
await ais.ui.toast("처리 중...", 5000); // 5초 토스트

ais.ui.confirm(title, message)

확인 대화상자를 표시하고 사용자의 응답을 기다립니다.

매개변수타입설명
titlestring대화상자 제목 (최대 100자)
messagestring대화상자 본문 텍스트 (최대 500자)

반환값: Promise<boolean> -- 사용자가 확인을 클릭하면 true, 취소하면 false

필요 권한: ui:modal

const confirmed = await ais.ui.confirm(
"모든 데이터를 삭제하시겠습니까?",
"저장된 모든 항목이 영구적으로 제거됩니다. 이 작업은 되돌릴 수 없습니다.",
);
if (confirmed) {
await clearAllData();
}

ais.ui.setTitle(title)

앱 패널 제목 표시줄에 표시되는 텍스트를 설정합니다.

매개변수타입설명
titlestring제목 텍스트 (최대 100자)

반환값: Promise<boolean>

ais.ui.setTitle("단어 카운터 - 1,234 단어");

인증

현재 로그인한 사용자에 대한 정보를 읽습니다.

필요 권한: auth:read

ais.auth.getUser()

현재 사용자의 프로필 정보를 가져옵니다.

반환값: Promise<UserInfo | null> -- 로그인하지 않은 경우 null

interface UserInfo {
name: string; // 표시 이름
email: string; // 이메일 주소
picture: string; // 프로필 사진 URL
}
const user = await ais.auth.getUser();
if (user) {
document.getElementById("avatar").src = user.picture;
document.getElementById("name").textContent = user.name;
} else {
document.getElementById("name").textContent = "게스트";
}

ais.auth.getTier()

사용자의 구독 등급을 가져옵니다.

반환값: Promise<string> -- 예: 'free', 'pro', 'team'

const tier = await ais.auth.getTier();
if (tier === "free") {
showUpgradePrompt();
}

시크릿

기기 간 전송 시나리오를 위한 API 키 읽기 및 쓰기. 기기 동기화 같은 앱에서 사용되는 권한 있는 API입니다.

필요 권한: secrets:sync

주의

secrets:sync 권한은 사용자의 저장된 API 키에 접근 권한을 부여합니다. 앱이 실제로 자격 증명을 전송하거나 백업해야 하는 경우에만 이 권한을 요청하세요. 권한 대화상자에서 사용자에게 명확한 경고가 표시됩니다.

ais.secrets.list()

저장된 API 키가 있는 제공자 이름을 나열합니다.

반환값: Promise<string[]> -- 예: ['anthropic', 'openai', 'gemini']

ais.secrets.get(provider)

제공자 이름으로 API 키 값을 가져옵니다.

매개변수타입설명
providerstring제공자 이름 (예: 'anthropic', 'openai')

반환값: Promise<string | null>

ais.secrets.set(provider, value)

제공자에 대한 API 키를 저장합니다.

매개변수타입설명
providerstring제공자 이름
valuestringAPI 키 값 (최대 1024자)

반환값: Promise<boolean>


동기화

기기 간 전송을 위한 프로필, 설정, WebRTC 시그널링 동기화.

필요 권한: secrets:sync

ais.sync.getProfiles()

호스트 플랫폼에서 모든 사용자 프로필을 가져옵니다.

반환값: Promise<Profile[]>

ais.sync.setProfiles(profiles)

호스트 플랫폼에 프로필을 가져옵니다.

매개변수타입설명
profilesProfile[]가져올 프로필 객체 배열

반환값: Promise<number> -- 가져온 프로필 수

ais.sync.getSettings()

호스트에서 앱 설정(테마, 로캘 등)을 가져옵니다.

반환값: Promise<Record<string, string>>

ais.sync.setSettings(settings)

호스트에 앱 설정을 씁니다.

매개변수타입설명
settingsRecord<string, string>쓸 키-값 설정

반환값: Promise<boolean>

ais.sync.signal(code, type, sdp)

WebRTC 시그널링을 위해 API 릴레이에 SDP 제안/응답을 게시합니다.

매개변수타입설명
codestring페어링 코드
type'offer' | 'answer'SDP 타입
sdpRTCSessionDescriptionInitSDP 데이터

반환값: Promise<boolean>

ais.sync.pollSignal(code, type)

API 릴레이에서 SDP 제안/응답을 폴링합니다.

매개변수타입설명
codestring페어링 코드
type'offer' | 'answer'폴링할 SDP 타입

반환값: Promise<RTCSessionDescriptionInit | null>


플랫폼 동작을 확장하거나 앱 간 통신을 위해 커스텀 훅 이벤트를 등록하고 발생시킵니다.

필요 권한: 이벤트 발생은 hooks:action, 필터 핸들러 등록은 hooks:filter.

ais.hooks.on(hookName, handler)

명명된 훅 이벤트를 수신합니다.

매개변수타입설명
hookNamestring훅 이름 (예: 'chat:before-send')
handler(data: unknown) => void이벤트 핸들러

반환값: Promise<boolean>

ais.hooks.on("chat:before-send", function (data) {
console.log("메시지가 전송되려고 함:", data);
});

ais.hooks.fire(hookName, data?)

명명된 훅 이벤트를 발생시킵니다. 이 훅에 등록된 모든 핸들러가 호출됩니다.

매개변수타입설명
hookNamestring발생시킬 훅 이름
dataunknown선택적 데이터 페이로드

반환값: Promise<unknown>

await ais.hooks.fire("my-app:data-updated", { count: 42 });

페이지

커스텀 슬러그로 bcz.co에 웹 페이지를 게시합니다. 앱 빌더 미니 프로그램에서 사용됩니다.

필요 권한: pages:publish

ais.pages.getInfo()

사용자의 게시된 페이지에 대한 정보를 가져옵니다.

반환값: Promise<PageInfo>

interface PageInfo {
slug: string | null;
url: string | null;
title: string | null;
updatedAt: number | null;
hasPage: boolean;
}

ais.pages.claim(slug)

bcz.co/@slug를 위한 슬러그(사용자 이름)를 요청합니다.

매개변수타입설명
slugstring원하는 슬러그

반환값: Promise<{ slug: string; url: string }>

ais.pages.publish(specBase64, opts?)

페이지를 게시하거나 업데이트합니다. spec은 base64로 인코딩된 PDL 문서입니다.

매개변수타입설명
specBase64stringBase64로 인코딩된 페이지 스펙
opts{ title?: string; description?: string }선택적 메타데이터

반환값: Promise<PublishResult>

ais.pages.unpublish()

게시를 취소하고 슬러그를 해제합니다.

반환값: Promise<boolean>


플랫폼 정보

플랫폼 메타데이터가 포함된 읽기 전용 속성. 동기식입니다. Promise 없음, 권한 필요 없음.

ais.platform.version

플랫폼 버전 문자열 (semver).

타입: string -- 현재 '1.0.0'

ais.platform.abi

ABI 버전 번호. SDK와 호스트 플랫폼 간 호환성을 검증하는 데 사용됩니다.

타입: number -- 현재 1

if (ais.platform.abi !== 1) {
ais.ui.toast("이 앱은 ABI 버전 1이 필요합니다");
ais.close();
}

에러 처리

권한이 필요한 모든 SDK 호출은 앱에 필요한 권한이 없는 경우 PermissionDenied 에러와 함께 거부됩니다:

try {
const history = await ais.chat.getHistory();
} catch (err) {
if (err.message.includes("PermissionDenied")) {
console.log("앱에 chat:read 권한이 없습니다");
}
}

알 수 없는 메서드는 Unknown method: {method} 메시지와 함께 에러를 반환합니다.

호스트 플랫폼이 예기치 않은 에러를 만나면 Promise가 에러 메시지 문자열과 함께 거부됩니다.

특히 권한 게이팅 API의 경우 SDK 호출을 try/catch 블록으로 감싸세요. 이렇게 하면 사용자의 플랫폼 버전이 테스트한 것과 다르더라도 앱이 복원력을 가집니다.


전체 예시

여러 SDK 기능을 사용하는 최소 앱:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
body {
font-family: system-ui;
padding: 16px;
color: #e0e0e0;
background: #1a1a2e;
}
button {
min-height: 48px;
padding: 8px 16px;
font-size: 16px;
border: 1px solid #444;
border-radius: 6px;
background: #2a2a4e;
color: #e0e0e0;
cursor: pointer;
}
button:hover {
background: #3a3a5e;
}
pre {
background: #111;
padding: 12px;
border-radius: 6px;
overflow: auto;
}
</style>
</head>
<body>
<h2>채팅 인스펙터</h2>
<button id="load">기록 불러오기</button>
<button id="close">닫기</button>
<pre id="output">"기록 불러오기"를 클릭하여 시작하세요...</pre>

<script>
ais.ready(async function () {
// 활성 모델 표시
var model = await ais.config.getModel();
ais.ui.setTitle("채팅 인스펙터 - " + model);

document
.getElementById("load")
.addEventListener("click", async function () {
var messages = await ais.chat.getHistory(25);
var output = messages
.map(function (m) {
return "[" + m.role + "] " + m.content.slice(0, 100);
})
.join("\n");
document.getElementById("output").textContent =
output || "(메시지 없음)";
ais.ui.toast(messages.length + "개 메시지 로드됨");
});

document.getElementById("close").addEventListener("click", function () {
ais.close();
});

// 실시간으로 새 메시지 구독
ais.chat.onMessage(function (msg) {
var el = document.getElementById("output");
el.textContent += "\n[" + msg.role + "] " + msg.content.slice(0, 100);
});
});
</script>
</body>
</html>

이 예시의 매니페스트:

{
"name": "chat-inspector",
"version": "1.0.0",
"abi": 1,
"type": "mini-program",
"description": "채팅 기록 보기 및 모니터링",
"entry": "index.html",
"base_url": "https://your-cdn.com/chat-inspector/",
"permissions": ["chat:read", "config:read", "ui:toast"]
}