Skip to Content

예제

@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', })

관련 문서

최종 수정 일자: