예제
@deplite/sdk로 실제 자주 쓰이는 흐름을 모았어요.
모든 예제는 npm install @deplite/sdk가 끝난 상태를 가정해요.
External — 파일 올리고 트리거
빌드 산출물(APK·ZIP·tarball)을 Deplite 스토리지에 올린 뒤, 그 파일 ID를 트리거 params에 실어 워크플로우에 전달하는 가장 흔한 패턴이에요.
import { Deplite } from '@deplite/sdk'
const deplite = new Deplite({ apiToken: process.env.DEPLITE_API_TOKEN! })
const uploaded = await deplite.files.upload({
file: { path: './build/app.apk' },
cleanupRule: { kind: 'ttl', ttlSeconds: 3600 },
contentType: 'application/vnd.android.package-archive',
})
const job = await deplite.triggers.run({
triggerId: process.env.TRIGGER_ID!,
params: { apkFileId: uploaded.id, ref: 'main' },
idempotencyKey: `release-${Date.now()}`,
})
console.log(job.jobId, job.status)워크플로우 측에서는 ${{ params.apkFileId }}로 ID를 받아 Files API로 받아 쓰면 돼요.
External — Sync 트리거로 결과까지 한 번에
responseMode: sync로 만들어진 트리거를 호출하면 워크플로우 완료까지 기다리고 output까지 그대로 받아요.
const job = await deplite.triggers.run({
triggerId: SYNC_TRIGGER_ID,
params: { ref: 'v1.2.3' },
})
if (job.timedOut) {
// responseTimeoutMs 초과. 워크플로우는 백그라운드에서 계속 실행됨
} else if (job.status === 'success') {
console.log('Deployed:', (job.output as any).url)
}sync 트리거는 워크플로우가 길면 HTTP 클라이언트 timeout에 걸릴 수 있어요.
30초 이상 걸리는 작업이라면 async + 알림 방식을 검토해주세요.
Embedded — 등록·실행·이벤트 처리
키오스크·전시 단말처럼 일반 앱 안에 Agent를 심는 시나리오예요.
첫 실행에서 enroll, 결과를 안전 저장소에 보관, 이후 부팅에선 그 자격으로 SSE를 구독해요.
import { Deplite, DepliteAgent, JobResult } from '@deplite/sdk'
// 1회만 — 안전 저장소에 보관
const enrollment = await Deplite.enroll({
installCode: process.env.INSTALL_CODE!,
name: 'kiosk-seoul-01',
})
await secureStore.save({
identity: enrollment.identity,
privateKey: enrollment.privateKey,
})
// 매 실행마다
const stored = await secureStore.load()
const agent = new DepliteAgent({
identity: stored.identity,
privateKey: stored.privateKey,
})
// 30초 heartbeat (기본값 일치)
setInterval(() => agent.heartbeat().catch(() => {}), 30_000)
for await (const ev of agent.events()) {
if (ev.type !== 'deploy') continue
const { jobId } = ev.payload
try {
await agent.jobs.appendLogs({
jobId,
items: [{ seq: 0, stream: 'system', level: 'info', content: 'started' }],
})
const result = await runJob(ev.payload)
await agent.jobs.reportResult({
jobId,
result: JobResult.success({ exitCode: 0, output: result }),
})
} catch (e) {
await agent.jobs.reportResult({
jobId,
result: JobResult.failed({ exitCode: 1, errorMessage: String(e) }),
})
}
}secureStore는 예시명이에요.
실제로는 privateKey(raw 32바이트)는 암호화 후 저장하는 것을 추천드려요.
Embedded — 워크플로우 인벤토리 동기화
sync_workflows 이벤트가 오면 현재 내가 실행 가능한 워크플로우 목록을 서버에 알려요.
실제 YAML 본문은 보내지 않고 이름과 메타만 보고해요.
async function reportWorkflows(agent: DepliteAgent) {
await agent.workflows.report([
{ name: 'deploy-prod', verboseSteps: ['build', 'push'], secretsKeys: ['DB_URL'] },
{ name: 'healthcheck', verboseSteps: ['ping'] },
])
}
for await (const ev of agent.events()) {
if (ev.type === 'sync_workflows') await reportWorkflows(agent)
}에러 처리 — 재시도 가능한 케이스만 백오프
import { DepliteAuthError, DepliteApiError } from '@deplite/sdk'
async function runWithRetry(fn: () => Promise<unknown>, max = 3) {
for (let i = 0; i < max; i++) {
try {
return await fn()
} catch (err) {
if (err instanceof DepliteAuthError) throw err // 재시도 무의미
if (err instanceof DepliteApiError && err.statusCode < 500 && err.statusCode !== 429) {
throw err // 4xx (429 제외)는 입력 오류
}
if (i === max - 1) throw err
await sleep(2 ** i * 500) // 0.5s, 1s, 2s
}
}
}
await runWithRetry(() => deplite.triggers.run({ triggerId, params: {} }))빈 파일·스트림 업로드
// 1) 디스크 경로
await deplite.files.upload({ file: { path: './out.tar.gz' } })
// 2) 메모리 버퍼
const buf = Buffer.from(JSON.stringify(data))
await deplite.files.upload({
file: { buffer: new Uint8Array(buf) },
filename: 'data.json',
contentType: 'application/json',
})
// 3) 스트림
import { createReadStream } from 'node:fs'
const stream = createReadStream('./big.bin')
await deplite.files.upload({
file: { stream: stream as any, size: 1024 * 1024 * 50 },
filename: 'big.bin',
})관련 문서
최종 수정 일자: