API 레퍼런스
io.deplite:sdk-android가 공개하는 모든 심볼을 시그니처와 함께 정리해요.
처음 보신다면 개요·Quickstart부터 읽어주세요.
진입 클래스
Deplite— External 모드 (Deplite를 호출)DepliteAgent— Embedded 모드 (내 앱이 작업 노드)
이 페이지의 모든 suspend 함수는 4xx/5xx 응답 시 DepliteApiException, 401·403 응답 시 DepliteAuthException을 던질 수 있어요.
처리 방법은 예외 섹션을 참고해주세요.
class Deplite
public class Deplite(
public val apiToken: String,
public val baseUrl: String = DEFAULT_BASE_URL,
okHttp: OkHttpClient = HttpClient.defaultOkHttp(),
)External 모드 클라이언트예요.
| 속성 | 타입 | 설명 |
|---|---|---|
apiToken | String | dpl_... 토큰 (로그 출력 금지) |
baseUrl | String | 기본 https://api.deplite.io/v1 |
triggers | Triggers | 트리거 호출 매니저 |
files | Files | External 파일 매니저 |
Deplite.enroll(…)
@JvmStatic
@JvmOverloads
public suspend fun enroll(
installCode: String,
name: String,
hostname: String? = null,
os: String? = null,
agentVersion: String? = null,
baseUrl: String = DEFAULT_BASE_URL,
okHttp: OkHttpClient = HttpClient.defaultOkHttp(),
): EnrollmentEmbedded 모드용 1회 등록.
새 키쌍을 만들고 /agent/enroll을 호출해 Agent ID와 서버 공개키를 받아와요.
| 옵션 | 타입 | 필수 | 설명 |
|---|---|---|---|
installCode | String | ✓ | 대시보드에서 발급한 1회용 설치 코드 (en_...) |
name | String | ✓ | 에이전트 표시 이름 |
hostname | String? | 호스트네임 | |
os | String? | "linux"·"android" 등 | |
agentVersion | String? | 에이전트 버전 | |
baseUrl | String | API 베이스 오버라이드 |
결과는 Enrollment로 받아오며, 포함된 identity와 privateKey는 SDK가 보관하지 않으므로 호출 측이 암호화 후 저장하는 것을 추천드려요.
val enrollment = Deplite.enroll(
installCode = INSTALL_CODE,
name = "kiosk-seoul-01",
)
secureStore.save(enrollment) // identity + privateKey설치 코드는 1회용이라 enroll 성공 후 폐기돼요.
저장 실패에 대비해 반환값을 먼저 저장한 뒤 후속 로직을 시작하는 게 안전해요.
class Triggers — deplite.triggers
triggers.run(…)
public suspend fun run(
triggerId: String,
params: JsonElement? = null,
workflowName: String? = null,
ref: String? = null,
debug: Boolean = false,
idempotencyKey: String? = null,
): TriggerRunResultPOST /triggers/{triggerId}/run을 호출해 트리거를 실행해요.
| 옵션 | 타입 | 필수 | 설명 |
|---|---|---|---|
triggerId | String | ✓ | 트리거 UUID |
params | JsonElement? | 워크플로우에 전달될 페이로드 (buildJsonObject { ... }) | |
workflowName | String? | agent-scope 트리거에서는 필수 | |
ref | String? | git ref | |
debug | Boolean | verbose 실행 | |
idempotencyKey | String? | 중복 실행 방지 키 |
호출 결과는 TriggerRunResult로 받아요.
val job = deplite.triggers.run(
triggerId = TRIGGER_ID,
params = buildJsonObject {
put("ref", "main")
put("actor", "sehyun")
},
idempotencyKey = UUID.randomUUID().toString(),
)
Log.i("Deplite", "${job.jobId} ${job.status}")responseMode: sync로 만들어진 트리거여야 응답에 exitCode·output이 와요.
async 트리거는 jobId만 즉시 반환되고, 결과는 알림이나 워크플로우 콜백으로 받아야 해요.
class Files — deplite.files
External 모드에서 스토리지 파일을 다뤄요.
기본 CleanupRule은 Ttl(86_400) (24시간)이에요.
files.upload(…)
public suspend fun upload(
file: File,
cleanupRule: CleanupRule = CleanupRule.Ttl(86_400),
filename: String? = null,
contentType: String? = null,
bindingId: String? = null,
): FileMetapresign + PUT + complete를 하나의 호출로 처리해요(내부적으로 HTTP 3회).
| 옵션 | 타입 | 필수 | 설명 |
|---|---|---|---|
file | File | ✓ | 업로드할 로컬 파일 |
cleanupRule | CleanupRule | 기본 24h TTL | |
filename | String? | 미지정 시 파일명 자동 추론 | |
contentType | String? | MIME 타입 | |
bindingId | String? | 토큰이 여러 binding을 허용할 때 필수 |
업로드가 끝나면 FileMeta 객체로 활성화된 파일 정보를 돌려줘요.
val uploaded = deplite.files.upload(
file = File("/tmp/app.apk"),
cleanupRule = CleanupRule.Ttl(3600),
contentType = "application/vnd.android.package-archive",
)
deplite.triggers.run(
triggerId = TRIGGER_ID,
params = buildJsonObject { put("apkFileId", uploaded.id) },
)files.presignUpload(…)
public suspend fun presignUpload(
cleanupRule: CleanupRule,
filename: String? = null,
contentType: String? = null,
bindingId: String? = null,
): PresignedUpload업로드 URL만 발급받아 직접 PUT 한 뒤 completeUpload를 호출하는 저수준 흐름이에요.
응답은 PresignedUpload로 받아오고, 이걸 가지고 직접 PUT 후 completeUpload를 호출하면 끝나요.
External 모드에서는 CleanupRule.OnJobEnd를 쓸 수 없어요(잡 컨텍스트가 없으므로).
Agent Files 전용이에요.
files.completeUpload / downloadUrl / download / get / list / delete
public suspend fun completeUpload(fileId: String): FileMeta
public suspend fun downloadUrl(fileId: String): String
public suspend fun download(fileId: String, to: File): File
public suspend fun get(fileId: String): FileMeta
public suspend fun list(bindingId: String? = null, status: String? = null): List<FileMeta>
public suspend fun delete(fileId: String)completeUpload는 PUT을 마친 뒤 파일을 활성 상태로 만들어요.
downloadUrl은 짧은 만료의 다운로드 URL을 발급하므로, 다운로드 직전에 새로 받는 게 안전해요.
download는 to로 직접 저장하며 상위 디렉토리는 자동으로 만들어줘요.
list는 토큰이 접근 가능한 binding 내 파일만 보여줘요.
class DepliteAgent
public class DepliteAgent(
public val identity: AgentIdentity,
privateKey: ByteArray, // 정확히 32바이트
okHttp: OkHttpClient = HttpClient.defaultOkHttp(),
)Embedded 모드 클라이언트예요.
enroll() 결과를 별도 저장소에서 꺼내 넘기면 돼요.
| 속성 | 타입 | 설명 |
|---|---|---|
identity | AgentIdentity | 등록 시 받은 비밀이 아닌 신원 |
workflows | AgentWorkflows | 워크플로우 인벤토리 보고 |
jobs | AgentJobs | Job 로그·결과 보고 |
files | AgentFiles | Job 범위 파일 매니저 |
생성자에 전달된 privateKey가 정확히 32바이트가 아니면 즉시 DepliteException이 던져져요.
agent.heartbeat()
public suspend fun heartbeat()서명된 heartbeat를 1회 송신해요(추천 주기 30초).
agent.updateIdentity(…)
public suspend fun updateIdentity(
hostname: String? = null,
os: String? = null,
agentVersion: String? = null,
)호스트네임·OS·버전 변경 시 PATCH로 알려요.
agent.events()
public fun events(): Flow<AgentEvent>SSE 스트림을 코틀린 Flow로 노출해요.
서버 → Agent 명령(deploy 등)의 서명 검증은 SDK가 자동 처리하므로 호출 측은 이벤트 타입만 분기하면 돼요.
이벤트 종류는 AgentEvent를 참고해주세요.
agent.events().collect { ev ->
when (ev) {
is AgentEvent.Deploy -> handleDeploy(ev.payload)
AgentEvent.SyncWorkflows -> reportWorkflows()
AgentEvent.Revoke -> return@collect
AgentEvent.Ping -> {} // keep-alive 무시
is AgentEvent.Unknown -> Log.w("Agent", "unknown: ${ev.name}")
}
}전체 시나리오는 예제 페이지에 있어요.
class AgentJobs — agent.jobs
jobs.appendLogs(…)
public suspend fun appendLogs(jobId: String, items: List<LogItem>): IntLogItem 배열을 한 번에 보내요.
서버가 실제로 수락한 라인 수가 돌아오고, 추천 배치 크기는 64KB 또는 1초 간격 중 빠른 쪽이에요.
jobs.reportResult(…)
public suspend fun reportResult(jobId: String, result: JobResult)잡당 1회만 호출해요.
JobResult는 직접 만들기보다 팩토리(JobResult.success 등)를 추천드려요.
try {
val output = runWorkflow(payload)
agent.jobs.reportResult(payload.jobId, JobResult.success(output = output))
} catch (e: Exception) {
agent.jobs.reportResult(payload.jobId, JobResult.failed(exitCode = 1, errorMessage = e.message))
}class AgentFiles — agent.files
Job 컨텍스트 안에서 산출물 파일을 다뤄요.
기본 CleanupRule은 OnJobEnd라 잡 종료 시 자동 정리돼요.
각 메소드의 옵션과 반환값은 External Files와 동일하고, 모든 호출에 jobId가 추가로 필요한 점만 달라요.
public suspend fun upload(jobId: String, file: File, ...): FileMeta
public suspend fun presignUpload(jobId: String, ...): PresignedUpload
public suspend fun complete(fileId: String): FileMeta
public suspend fun downloadUrl(fileId: String): String
public suspend fun download(fileId: String, to: File): File
public suspend fun get(fileId: String): FileMeta
public suspend fun delete(fileId: String)External의 Files와 달리 모든 호출이 서명되고 jobId로 스코프돼요.
list는 노출되지 않아요.
class AgentWorkflows — agent.workflows
workflows.report(…)
public suspend fun report(workflows: List<WorkflowReport>): Int서버에 알려진 워크플로우 인벤토리를 WorkflowReport 리스트로 완전히 교체해요.
보고된 워크플로우 수가 돌아와요.
실제 YAML·step run 명령·시크릿 값은 보내지 않는 것을 추천드려요.
이름·메타만 보고하는 게 격리 모델의 핵심이에요.
타입 참조
Enrollment
public data class Enrollment(
val identity: AgentIdentity,
val privateKey: ByteArray, // raw 32-byte 개인키
)Deplite.enroll의 결과. 두 필드 모두 호출 측이 암호화 후 저장하는 것을 추천드려요.
AgentIdentity
public data class AgentIdentity(
val agentId: String,
val organizationId: String,
val baseUrl: String,
val serverPublicKeyPem: String,
)비밀이 아니라 일반 저장소에 두어도 무방해요.
AgentEvent
public sealed class AgentEvent {
public data class Deploy(val payload: DeployPayload, val signature: String) : AgentEvent()
public data object Revoke : AgentEvent()
public data object SyncWorkflows : AgentEvent()
public data object Ping : AgentEvent()
public data class Unknown(val name: String, val data: String) : AgentEvent()
}| 타입 | 의미 |
|---|---|
Deploy | 워크플로우 실행 명령 (payload에 jobId·workflowName·params 등) |
Revoke | Agent 자격 회수 |
SyncWorkflows | 워크플로우 인벤토리 재보고 요청 |
Ping | keep-alive |
Unknown | 알 수 없는 이벤트 또는 서명 검증 실패 |
DeployPayload
@Serializable
public data class DeployPayload(
val jobId: String,
val workflowName: String,
val debug: Boolean = false,
val ref: String? = null,
val params: JsonElement? = null,
val issuedAt: Long = 0,
val nonce: String = "",
val force: Boolean = false,
val forceReason: String? = null,
)TriggerRunResult
@Serializable
public data class TriggerRunResult(
val jobId: String,
val status: String,
val idempotent: Boolean = false,
val timedOut: Boolean = false,
val exitCode: Int? = null,
val errorMessage: String? = null,
val output: JsonElement? = null,
val statusUrl: String? = null,
)CleanupRule
public sealed class CleanupRule {
public data class Ttl(val ttlSeconds: Long) : CleanupRule() // 60s ≤ ttl ≤ 90일
public data object Persistent : CleanupRule()
public data object OnJobEnd : CleanupRule() // Agent Files 전용
}FileMeta
@Serializable
public data class FileMeta(
val id: String,
val bindingId: String? = null,
val jobId: String? = null,
val filename: String? = null,
val contentType: String? = null,
val size: Long? = null,
val status: String? = null,
val cleanupRule: String? = null,
val expiresAt: String? = null,
val createdAt: String? = null,
)PresignedUpload
@Serializable
public data class PresignedUpload(
val fileId: String,
val uploadUrl: String,
val uploadHeaders: Map<String, String>? = null,
val expiresInSeconds: Int? = null,
)LogItem
public enum class LogStream { Raw, System }
public enum class LogLevel { Info, Warn, Error }
public data class LogItem(
val seq: Int,
val stream: LogStream,
val content: String,
val stepName: String? = null,
val level: LogLevel? = null,
)seq는 잡 안에서 단조 증가해야 해요.
Raw는 stdout/stderr 원본, System은 SDK 메타예요.
JobResult
public enum class JobStatus { Running, Success, Failed, Timeout, Rejected }
public data class JobResult internal constructor(
val status: JobStatus,
val exitCode: Int? = null,
val errorMessage: String? = null,
val output: JsonElement? = null,
val rejection: Rejection? = null,
) {
public companion object {
public fun running(): JobResult
public fun success(exitCode: Int = 0, output: JsonElement? = null): JobResult
public fun failed(exitCode: Int? = null, errorMessage: String? = null): JobResult
public fun timeout(errorMessage: String? = null): JobResult
public fun rejected(rejection: Rejection): JobResult
}
}생성자가 internal이라 직접 만들지 말고 JobResult.success(...)·failed(...) 같은 팩토리를 사용해주세요.
Rejection
public data class Rejection(
val reason: String, // 'rate_limited' | 'queue_full' | ...
val limitType: String? = null,
val retryAfterSeconds: Int? = null,
val bypassedLimits: List<String> = emptyList(),
)WorkflowReport
@Serializable
public data class WorkflowReport(
val name: String,
val verboseSteps: List<String> = emptyList(),
val secretsKeys: List<String> = emptyList(),
)예외
DepliteException
public open class DepliteException(
message: String,
cause: Throwable? = null,
) : RuntimeException(message, cause)네트워크·키·디스크 등 SDK 내부 오류의 베이스 클래스예요.
DepliteApiException
public open class DepliteApiException(
public val statusCode: Int,
public val body: String,
) : DepliteException("Deplite API error: $statusCode")서버가 비-2xx 응답을 반환했을 때 던져져요(401·403 제외).
DepliteAuthException
public class DepliteAuthException(
statusCode: Int,
body: String,
) : DepliteApiException(statusCode, body)401·403 전용. 토큰 회수·교체가 필요해요(재시도 무의미). Embedded는 재등록이 필요해요.
추천 처리 패턴
try {
deplite.triggers.run(triggerId, params = buildJsonObject {})
} catch (e: DepliteAuthException) {
// 토큰 회수·교체 필요
} catch (e: DepliteApiException) {
if (e.statusCode == 429 || e.statusCode >= 500) {
// 백오프 후 재시도
}
} catch (e: DepliteException) {
Log.e("Deplite", e.message, e.cause)
}