개발자 서버에서 실행
runtime external — 앱 코드를 sayren 대신 내 서버에서 실행하고, sayren이 보낸 호출을 서명으로 확인하는 방법
앱 코드는 기본적으로 sayren이 실행합니다(runtime: "code"). 이미 운영 중인 서버가 있거나, sayren 실행 환경에서 쓸 수 없는 라이브러리·
데이터베이스가 필요하면 내 서버에서 실행합니다(runtime: "external"). 설치·동의·이벤트·예약 작업·공개 HTTP·앱 화면·흐름 알림은 그대로이고,
sayren이 앱 코드를 부르는 자리만 내 서버 주소로 바뀝니다.
{
"handle": "erp-sync",
"name": "ERP 연동",
"runtime": "external",
"external": { "url": "https://erp.example.com/sayren/invoke" },
"scopes": ["order:r"],
"events": ["ORDER.PAID"]
}external.url은https://주소입니다. IP 주소·localhost·sayren 플랫폼 호스트는 쓸 수 없습니다.- 외부 런타임 앱은
network.hosts를 적지 않습니다. 내 서버가 어디로 데이터를 보내는지 sayren이 제한할 수 없기 때문입니다. 대신 동의 화면의 「이 앱이 실행되는 곳」에 주소의 호스트가 보이고, 호스트가 바뀐 버전은 재동의가 필요합니다. npx sayren app deploy는 매니페스트·화면 파일·목록 정보만 올리고 서버 코드는 올리지 않습니다. release한 버전부터 그 주소로 호출합니다.
서버 만들기
@sayren/app의 defineApp을 그대로 쓰고, createExternalHandler로 감쌉니다. 핸들러는 표준 Request를 받아 Response를 돌려줍니다.
import { createExternalHandler, defineApp } from "@sayren/app";
const app = defineApp({
events: {
"ORDER.PAID": async (event, ctx) => {
const order = await ctx.api.orders.get(event.data.orderId);
await pushToErp(order);
},
},
});
// appId는 developer.sayren.io 앱 개요의 앱 ID입니다
export const handle = createExternalHandler(app, { appId: "app_853711c8c8f8" });
// Hono·Next.js 라우트·Bun·Deno처럼 fetch 핸들러를 받는 곳에 연결합니다
export default { fetch: handle };createExternalHandler가 하는 일:
- 헤더
x-sayren-signature의 서명을 sayren 공개 키(https://api.sayren.io/.well-known/sayren-apps-jwks.json, 캐시)로 확인합니다. - 서명의 대상이 이 앱(
app:{appId})이고 만료(5분) 전이며, 서명에 든 본문 해시가 받은 본문과 같은지 봅니다. - 통과하면 본문(실행 봉투)을
defineApp에 넘기고 결과를 JSON으로 돌려줍니다. 실패하면401입니다.
서명을 확인하지 않고 받은 요청을 실행하지 마십시오. 봉투에는 설치 토큰과 설정·비밀 값이 들어 있습니다.
호출과 한도
| 항목 | 값 |
|---|---|
| 메서드·본문 | POST, JSON 실행 봉투 |
| 응답 | createExternalHandler의 결과(JSON). 2xx가 아니거나 형식이 다르면 앱 오류로 기록합니다 |
| 시간 | 이벤트·예약 작업·흐름 알림 30초, HTTP(앱 화면·공개 HTTP) 25초 |
| 재시도 | 이벤트·흐름 알림은 sayren 실행과 같습니다. 서버가 응답하지 않으면 다시 보냅니다 |
CPU·요청 수·메모리 한도는 내 서버의 것이라 sayren이 재지 않습니다. 실행 기록과 로그(console.*·ctx.log)는 응답에 실린 만큼 남습니다.
로컬에서
npx sayren app dev는 외부 런타임 앱도 src/server.ts의 defineApp을 로컬에서 실행합니다. 서명 확인은 운영 호출에서만 합니다.