Skip to Content
문서SDKFlutter (Dart)API 레퍼런스

API 레퍼런스

deplite 패키지가 공개하는 모든 심볼을 시그니처와 함께 정리해요.
처음 보신다면 개요·Quickstart부터 읽어주세요.

진입 클래스

  • Deplite — External 모드 (Deplite를 호출)
  • DepliteAgent — Embedded 모드 (내 앱이 작업 노드)

이 페이지의 모든 메소드는 4xx/5xx 응답 시 DepliteApiException, 401·403 응답 시 DepliteAuthException을 던질 수 있어요.
처리 방법은 예외 섹션을 참고해주세요.

class Deplite

class Deplite { Deplite({ required String apiToken, String baseUrl = 'https://api.deplite.io/v1', http.Client? client, }); static const String defaultBaseUrl = 'https://api.deplite.io/v1'; final String apiToken; final String baseUrl; late final Triggers triggers; late final Files files; void close(); }

External 모드 클라이언트예요.
종료 시 close()를 호출하면 내부 http.Client가 정리돼요.

옵션타입필수설명
apiTokenStringdpl_... 토큰
baseUrlString기본 https://api.deplite.io/v1
clienthttp.Client?사용자 정의 HTTP 클라이언트

Deplite.enroll(…)

static Future<Enrollment> enroll({ required String installCode, required String name, String? hostname, String? os, String? agentVersion, String baseUrl = 'https://api.deplite.io/v1', http.Client? client, });

Embedded 모드용 1회 등록.
새 키쌍을 만들고 /agent/enroll을 호출해 Agent ID와 서버 공개키를 받아와요.

옵션타입필수설명
installCodeString대시보드에서 발급한 1회용 설치 코드 (en_...)
nameString에이전트 표시 이름
hostnameString?호스트네임
osString?'ios'·'android'
agentVersionString?에이전트 버전
baseUrlStringAPI 베이스 오버라이드

결과는 Enrollment로 받아오며, 포함된 identityprivateKey는 SDK가 보관하지 않으므로 호출 측이 암호화 후 저장하는 것을 추천드려요.

final enrollment = await Deplite.enroll( installCode: installCode, name: 'kiosk-seoul-01', ); await secureStore.save(enrollment); // identity + privateKey

설치 코드는 1회용이라 enroll 성공 후 폐기돼요.
저장 실패에 대비해 반환값을 먼저 저장한 뒤 후속 로직을 시작하는 게 안전해요.

class Triggers

triggers.run(…)

Future<TriggerRunResult> run({ required String triggerId, Object? params, String? workflowName, String? ref, bool debug = false, String? idempotencyKey, });

POST /triggers/{triggerId}/run을 호출해 트리거를 실행해요.

옵션타입필수설명
triggerIdString트리거 UUID
paramsObject?JSON 직렬화 가능한 객체 (Map·List·원시값)
workflowNameString?agent-scope 트리거에서는 필수
refString?git ref
debugboolverbose 실행
idempotencyKeyString?중복 실행 방지 키

호출 결과는 TriggerRunResult로 받아요.

final job = await deplite.triggers.run( triggerId: triggerId, params: {'ref': 'main', 'actor': 'sehyun'}, idempotencyKey: 'release-${DateTime.now().millisecondsSinceEpoch}', ); print('${job.jobId} ${job.status}');

responseMode: sync로 만들어진 트리거여야 응답에 exitCode·output이 와요.
async 트리거는 jobId만 즉시 반환되고, 결과는 알림이나 워크플로우 콜백으로 받아야 해요.

class Files

External 모드에서 스토리지 파일을 다뤄요.
기본 CleanupRuleTtlCleanup(86400)(24시간)이에요.

files.upload(…)

Future<FileMeta> upload({ required File file, CleanupRule cleanupRule = const TtlCleanup(86400), String? filename, String? contentType, String? bindingId, });

presign + PUT + complete를 하나의 호출로 처리해요.

옵션타입필수설명
fileFile업로드할 로컬 파일
cleanupRuleCleanupRule기본 24h TTL
filenameString?미지정 시 파일명 자동 추론
contentTypeString?MIME 타입
bindingIdString?토큰이 여러 binding을 허용할 때 필수

업로드가 끝나면 FileMeta 객체로 활성화된 파일 정보를 돌려줘요.

final uploaded = await deplite.files.upload( file: File('/tmp/app.apk'), cleanupRule: const TtlCleanup(3600), contentType: 'application/vnd.android.package-archive', ); await deplite.triggers.run( triggerId: triggerId, params: {'apkFileId': uploaded.id}, );

files.presignUpload(…)

Future<PresignedUpload> presignUpload({ required CleanupRule cleanupRule, String? filename, String? contentType, String? bindingId, });

업로드 URL만 발급받아 직접 PUT 한 뒤 completeUpload를 호출하는 저수준 흐름이에요.
응답은 PresignedUpload로 받아오고, 이걸 가지고 직접 PUT 후 completeUpload를 호출하면 끝나요.

External 모드에서는 OnJobEndCleanup을 쓸 수 없어요(잡 컨텍스트가 없으므로).
Agent Files 전용이에요.

files.completeUpload / downloadUrl / download / get / list / delete

Future<FileMeta> completeUpload({required String fileId}); Future<String> downloadUrl({required String fileId}); Future<File> download({required String fileId, required File to}); Future<FileMeta> get({required String fileId}); Future<List<FileMeta>> list({String? bindingId, String? status}); Future<void> delete({required String fileId});

completeUpload는 PUT을 마친 뒤 파일을 활성 상태로 만들어요.
downloadUrl은 짧은 만료의 URL을 발급하므로 다운로드 직전에 새로 받는 게 안전해요.
downloadto 파일로 직접 저장해요.
list는 토큰이 접근 가능한 binding 내 파일만 보여줘요.

class DepliteAgent

class DepliteAgent { DepliteAgent({ required AgentIdentity identity, required Uint8List privateKey, // 정확히 32바이트 http.Client? client, }); final AgentIdentity identity; late final AgentWorkflows workflows; late final AgentJobs jobs; late final AgentFiles files; void close(); }

Embedded 모드 클라이언트예요.
enroll() 결과를 별도 저장소에서 꺼내 넘기면 돼요.

속성타입설명
identityAgentIdentity등록 시 받은 비밀이 아닌 신원
workflowsAgentWorkflows워크플로우 인벤토리 보고
jobsAgentJobsJob 로그·결과 보고
filesAgentFilesJob 범위 파일 매니저

agent.heartbeat()

Future<void> heartbeat();

서명된 heartbeat를 1회 송신해요(추천 주기 30초).

agent.updateIdentity(…)

Future<void> updateIdentity({ String? hostname, String? os, String? agentVersion, });

호스트네임·OS·버전 변경 시 PATCH로 알려요.

agent.events()

Stream<AgentEvent> events();

SSE 스트림을 Dart Stream으로 노출해요.
서버 → Agent 명령(deploy 등)의 서명 검증은 SDK가 자동 처리하므로 호출 측은 이벤트 타입만 분기하면 돼요.

이벤트 종류는 AgentEvent를 참고해주세요.
Dart 3 sealed class라 switch로 exhaustive 매칭을 추천드려요.

await for (final event in agent.events()) { switch (event) { case DeployEvent(payload: final p): await handleDeploy(p); case SyncWorkflowsEvent(): await reportWorkflows(); case RevokeEvent(): return; case PingEvent(): continue; case UnknownEvent(name: final n): print('unknown event: $n'); } }

전체 시나리오는 예제 페이지에 있어요.

class AgentJobs

jobs.appendLogs(…)

Future<int> appendLogs({ required String jobId, required List<LogItem> items, });

LogItem 배열을 한 번에 보내요.
서버가 실제로 수락한 라인 수가 돌아오고, 추천 배치 크기는 64KB 또는 1초 간격 중 빠른 쪽이에요.

jobs.reportResult(…)

Future<void> reportResult({ required String jobId, required JobResult result, });

잡당 1회만 호출해요.
JobResult는 직접 만들기보다 팩토리(JobResult.success 등)를 추천드려요.

try { final output = await runWorkflow(payload); await agent.jobs.reportResult( jobId: payload.jobId, result: JobResult.success(output: output), ); } catch (e) { await agent.jobs.reportResult( jobId: payload.jobId, result: JobResult.failed(exitCode: 1, errorMessage: '$e'), ); }

class AgentFiles

Job 컨텍스트 안에서 산출물 파일을 다뤄요.
기본 CleanupRuleOnJobEndCleanup()이라 잡 종료 시 자동 정리돼요.
각 메소드의 옵션과 반환값은 External Files와 동일하고, 모든 호출에 jobId가 추가로 필요한 점만 달라요.

Future<FileMeta> upload({required String jobId, required File file, ...}); Future<PresignedUpload> presignUpload({required String jobId, ...}); Future<FileMeta> complete({required String fileId}); Future<String> downloadUrl({required String fileId}); Future<File> download({required String fileId, required File to}); Future<FileMeta> get({required String fileId}); Future<void> delete({required String fileId});

External의 Files와 달리 모든 호출이 서명되고 jobId로 스코프돼요.
list는 노출되지 않아요.

class AgentWorkflows

workflows.report(…)

Future<int> report(List<WorkflowReport> workflows);

서버에 알려진 워크플로우 인벤토리를 WorkflowReport 리스트로 완전히 교체해요.
보고된 워크플로우 수가 돌아와요.

실제 YAML·step run 명령·시크릿 값은 보내지 않는 것을 추천드려요.
이름·메타만 보고하는 게 격리 모델의 핵심이에요.

타입 참조

Enrollment

class Enrollment { const Enrollment({ required this.identity, required this.privateKey, // raw 32-byte 개인키 }); final AgentIdentity identity; final Uint8List privateKey; }

Deplite.enroll의 결과. 두 필드 모두 호출 측이 암호화 후 저장하는 것을 추천드려요.

AgentIdentity

class AgentIdentity { const AgentIdentity({ required this.agentId, required this.organizationId, required this.baseUrl, required this.serverPublicKeyPem, }); final String agentId; final String organizationId; final String baseUrl; final String serverPublicKeyPem; Map<String, dynamic> toJson(); factory AgentIdentity.fromJson(Map<String, dynamic> json); }

비밀이 아니라 toJson()으로 직렬화해 일반 저장소에 두어도 무방해요.

AgentEvent

sealed class AgentEvent { const AgentEvent(); } class DeployEvent extends AgentEvent { const DeployEvent(this.payload, this.signature); final DeployPayload payload; final String signature; } class RevokeEvent extends AgentEvent { const RevokeEvent(); } class SyncWorkflowsEvent extends AgentEvent { const SyncWorkflowsEvent(); } class PingEvent extends AgentEvent { const PingEvent(); } class UnknownEvent extends AgentEvent { const UnknownEvent(this.name, this.data); final String name; final String data; }
타입의미
DeployEvent워크플로우 실행 명령 (payloadjobId·workflowName·params 등)
RevokeEventAgent 자격 회수
SyncWorkflowsEvent워크플로우 인벤토리 재보고 요청
PingEventkeep-alive
UnknownEvent알 수 없는 이벤트 또는 서명 검증 실패

Dart 3 sealed class라 switch 표현식에서 exhaustive 매칭 가능해요.

DeployPayload

class DeployPayload { const DeployPayload({ required this.jobId, required this.workflowName, this.debug = false, this.ref, this.params, this.issuedAt = 0, this.nonce = '', this.force = false, this.forceReason, }); final String jobId; final String workflowName; final bool debug; final String? ref; final Object? params; final int issuedAt; final String nonce; final bool force; final String? forceReason; }

TriggerRunResult

class TriggerRunResult { const TriggerRunResult({ required this.jobId, required this.status, this.idempotent = false, this.timedOut = false, this.exitCode, this.errorMessage, this.output, this.statusUrl, }); final String jobId; final String status; final bool idempotent; final bool timedOut; final int? exitCode; final String? errorMessage; final Object? output; final String? statusUrl; }

CleanupRule

sealed class CleanupRule { const CleanupRule(); String get wireValue; } class TtlCleanup extends CleanupRule { const TtlCleanup(this.ttlSeconds); // 60s ≤ ttl ≤ 90일 final int ttlSeconds; } class PersistentCleanup extends CleanupRule { const PersistentCleanup(); } class OnJobEndCleanup extends CleanupRule { // Agent Files 전용 const OnJobEndCleanup(); }

FileMeta

class FileMeta { const FileMeta({ required this.id, this.bindingId, this.jobId, this.filename, this.contentType, this.size, this.status, this.cleanupRule, this.expiresAt, this.createdAt, }); final String id; final String? bindingId; final String? jobId; final String? filename; final String? contentType; final int? size; final String? status; final String? cleanupRule; final String? expiresAt; final String? createdAt; }

PresignedUpload

class PresignedUpload { const PresignedUpload({ required this.fileId, required this.uploadUrl, this.uploadHeaders, this.expiresInSeconds, }); final String fileId; final Uri uploadUrl; final Map<String, String>? uploadHeaders; final int? expiresInSeconds; }

LogItem

enum LogStream { raw, system } enum LogLevel { info, warn, error } class LogItem { const LogItem({ required this.seq, required this.stream, required this.content, this.stepName, this.level, }); final int seq; final LogStream stream; final String content; final String? stepName; final LogLevel? level; }

JobResult

enum JobStatus { running, success, failed, timeout, rejected } class JobResult { final JobStatus status; final int? exitCode; final String? errorMessage; final Object? output; final Rejection? rejection; factory JobResult.running(); factory JobResult.success({int exitCode = 0, Object? output}); factory JobResult.failed({int? exitCode, String? errorMessage}); factory JobResult.timeout({String? errorMessage}); factory JobResult.rejected(Rejection rejection); }

Rejection

class Rejection { const Rejection({ required this.reason, this.limitType, this.retryAfterSeconds, this.bypassedLimits = const <String>[], }); final String reason; final String? limitType; final int? retryAfterSeconds; final List<String> bypassedLimits; }

WorkflowReport

class WorkflowReport { const WorkflowReport({ required this.name, this.verboseSteps = const <String>[], this.secretsKeys = const <String>[], }); final String name; final List<String> verboseSteps; final List<String> secretsKeys; Map<String, dynamic> toJson(); }

예외

DepliteException

class DepliteException implements Exception { DepliteException(this.message, {this.cause}); final String message; final Object? cause; }

네트워크·키·디스크 등 SDK 내부 오류의 베이스 클래스예요.

DepliteApiException

class DepliteApiException extends DepliteException { DepliteApiException(this.statusCode, this.body); final int statusCode; final String body; }

서버가 비-2xx 응답을 반환했을 때 던져져요(401·403 제외).

DepliteAuthException

class DepliteAuthException extends DepliteApiException { DepliteAuthException(int statusCode, String body) : super(statusCode, body); }

401·403 전용. 토큰 회수·교체가 필요해요(재시도 무의미). Embedded는 재등록이 필요해요.

추천 처리 패턴

try { await deplite.triggers.run(triggerId: triggerId, params: {}); } on DepliteAuthException { // 토큰 회수·교체 필요 } on DepliteApiException catch (e) { if (e.statusCode == 429 || e.statusCode >= 500) { // 백오프 후 재시도 } } on DepliteException catch (e) { print('${e.message} ${e.cause}'); }

관련 문서

최종 수정 일자: