開發登入 Mini App 尚未發布
從零做出一個 Mini App:用這個人的 Micromeet 帳號讓他登入,再從它自己的後端以這個人的身分呼叫 Micromeet。每個函式的說明請見登入,打包請見打包與簽章,封裝的全部規則請見封裝規範。
整體流程
從第一次建置到使用者開啟 Mini App,誰做什麼:
Cowork 每次開啟都驗證簽章,頁面每讀一個檔案都核對;檔案被改過就關閉這個 Mini App。
使用者點了你的登入按鈕之後:
頁面始終拿不到密碼、token 和 client secret。下面的步驟逐一做出每個部分。
1. 請 Micromeet 登記這個 Mini App
無法自助登記。把這些資料寄給 Micromeet:
| 內容 | 範例 |
|---|---|
| AppID:小寫反向網域 | ai.example.app |
| 名稱(英文;中文選填)和開發方 | Example · Example Ltd |
| 需要的 scope | profile:read |
| 登入使用者所在的區(SG、HK、ID) | HK |
| 後端的位址 | https://api.example.com |
每個區給你一組 client secret,只顯示一次:存進後端的金鑰儲存區。每個後端位址還會給你一個驗證檔案(第 2 步)。
2. 證明後端網域屬於你
把這個檔案放在 https://api.example.com/micromeet-miniapp-<16 個字元>.txt,用 HTTPS 回傳 200,不能轉址,並一直保留;Micromeet 取回它來驗證網域。開發時,後端可以跑在 http://localhost:<連接埠> 或 http://127.0.0.1:<連接埠>,在 Micromeet 允許的區不需要放檔案。請見打包與簽章裡的「伺服器網域」。
3. 撰寫頁面
安裝 @micromeet-ai/miniapp-sdk(請見打包與簽章裡的「建置」),然後:
js
import { maestroSdk } from '@micromeet-ai/miniapp-sdk';
const BACKEND = 'https://api.example.com'; // 驗證過的伺服器網域
export async function signIn() {
const sdk = maestroSdk(); // 不在 Cowork 裡時為 null
if (!sdk?.auth) return { error: 'open_in_cowork' };
const login = await sdk.auth.login({ scopes: ['profile:read'] });
if (!login.ok) return { error: login.error };
const response = await fetch(`${BACKEND}/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ code: login.code, region: login.region })
});
return response.json(); // { session, name }:之後的請求帶上 session
}- 在使用者點擊時呼叫
auth.login():Cowork 只在使用者正在看的分頁上跳出確認卡。 auth.status()說明封裝是否已簽章、Cowork 是否有人登入,可以用來決定是否顯示登入按鈕。- 腳本都放在檔案裡:內嵌
<script>不會執行。
4. 撰寫後端
一個最小的 Node.js 後端:
js
import { createServer } from 'node:http';
import { randomUUID } from 'node:crypto';
import { createMiniappAuthClient, MiniappAuthError } from '@micromeet-ai/miniapp-sdk/server';
const APP_ID = 'ai.example.app';
const PAGE = `miniapp://${APP_ID}`; // 頁面的 origin
// 每個區一個 client,用那個區的 secret。
const clients = { HK: createMiniappAuthClient({ appId: APP_ID, clientSecret: process.env.MINIAPP_SECRET_HK }) };
const sessions = new Map(); // 實際存進你的資料庫
const reply = (res, status, body) => {
res.writeHead(status, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': PAGE, Vary: 'Origin' });
res.end(JSON.stringify(body));
};
createServer((req, res) => {
if (req.method === 'OPTIONS') {
res.writeHead(204, { 'Access-Control-Allow-Origin': PAGE, 'Access-Control-Allow-Methods': 'POST', 'Access-Control-Allow-Headers': 'Content-Type, Authorization' });
return res.end();
}
if (req.method !== 'POST' || req.url !== '/login') return reply(res, 404, { error: 'not_found' });
let raw = '';
req.on('data', (part) => (raw += part));
req.on('end', async () => {
try {
const { code, region } = JSON.parse(raw);
const auth = clients[region];
if (!auth) return reply(res, 400, { error: 'region_not_supported' });
const tokens = await auth.exchangeCode({ code, region });
const session = randomUUID();
sessions.set(session, { ref: tokens.user.ref, region, refreshToken: tokens.refreshToken });
reply(res, 200, { session, name: tokens.user.name });
} catch (error) {
reply(res, 400, { error: error instanceof MiniappAuthError ? error.code : 'bad_request' });
}
});
}).listen(8787);- 回傳
Access-Control-Allow-Origin: miniapp://<appId>:這是頁面的 origin,少了這個回應標頭,請求在頁面裡就失敗了,到不了你的程式。 - 用
user.ref當使用者的鍵,保存好 refresh token,之後要呼叫 Micromeet 時用refresh換新的 token。 - 頁面只拿到你自己的工作階段;Micromeet 的 token 留在後端。
- 部署在你驗證過的伺服器網域上,開發時跑在 localhost。其他語言的後端做同樣的呼叫(請見登入裡的「HTTP 呼叫」)。
5. 打包、簽章、安裝
- 在 Vite 外掛裡寫
domains: ['https://api.example.com'],然後vite build(請見打包與簽章)。 - 執行
micromeet-miniapp verify miniapp-package,再把封裝交給 Micromeet;Micromeet 在每個區登記並簽章這個版本,交回簽好的manifest.json,把它放回封裝裡。 - 執行
micromeet-miniapp verify miniapp-package --signed,然後micromeet-miniapp zip miniapp-package。 - 在 Cowork 裡請 Agent 安裝這個 zip,開啟 Mini App,點登入。
正式版 Cowork 只開啟 Micromeet 正式環境簽章的版本;沒有免簽章的開發模式。
6. 開發與測試
- 不需要登入的畫面和邏輯:在瀏覽器裡
vite dev。那裡maestroSdk()是null,顯示一句提示代替登入按鈕。 - 只有頁面的檔案會被簽章:改後端不需要新版本。頁面盡量簡單,邏輯放在後端。
- 改了頁面的任何檔案或
domains,都要換新的version,重新登記、簽章、安裝。 - 端到端測試登入需要:簽好的版本,加上登入了已登記區帳號的 Cowork。
- 開發用的版本可以只寫 localhost 網域;發布的版本不要帶 localhost:不允許 localhost 的區會因此拒絕登入(
no_server_domain)。
出錯怎麼辦
| 在哪裡 | 看到什麼 | 原因和處理 |
|---|---|---|
| Cowork | 提示這個 Mini App 未經認證,無法開啟 | 封裝沒有簽章、由別的 Micromeet 環境簽章,或簽章後改過檔案:安裝簽好的 zip |
| 頁面 | app_not_available | 使用者所在的區沒有登記這個 AppID,或已停用 |
| 頁面 | version_not_available | 這個版本沒有在那個區登記,或已停用 |
| 頁面 | no_server_domain | 這個版本在那個區沒有驗證過的伺服器網域,或驗證檔案不在了 |
| 頁面 | scope_denied | 請求了 Micromeet 沒有給這個 Mini App 的 scope |
| 頁面 | fetch 出現跨來源(CORS)錯誤 | 後端沒有回傳 Access-Control-Allow-Origin: miniapp://<appId> |
| 後端 | invalid_client | 這個區的 secret 不對,或已被更換 |
| 後端 | invalid_grant | code 已經用過、超過 5 分鐘,或不是這個 AppID 的 |