Skip to content

TypeScript SDK

Ilhwan Seo edited this page Aug 29, 2026 · 3 revisions

TypeScript SDK

React Native, Web, Node용 @seorilabs/platform-sdk. 현재 권장 버전은 0.4.0입니다.

  • source: packages/sdk-ts
  • 버전 정본: package.json과 src/version.ts의 SDK_VERSION
  • 요구: Node 20 이상, fetch 전역. 의존성 없음

설치

GitHub Release tarball — 인증 없이 됩니다.

pnpm add https://github.com/seorilabs/platform/releases/download/v0.6.7/seorilabs-platform-sdk-0.4.0.tgz

무결성을 고정하려면 platform-release.json의 sha256과 대조합니다 (0.4.0: 8d7151f6ec7ff0c0fe8c9fe6fee2e6aa5a1158bd394dc03cc09a4e40f5a6abd7).

GitHub Packages — read:packages 토큰이 필요합니다. .npmrc에는 registry만 둡니다.

@seorilabs:registry=https://npm.pkg.github.com
pnpm add @seorilabs/platform-sdk@0.4.0

NODE_AUTH_TOKEN 값은 파일, 로그, 앱 번들에 넣지 않습니다.

조립

import { createPlatform } from "@seorilabs/platform-sdk";

export const platform = createPlatform({
  baseUrl: PLATFORM_API_URL,
  iapBaseUrl: PLATFORM_IAP_URL,
  ingestBaseUrl: PLATFORM_INGEST_URL,
  adsBaseUrl: PLATFORM_ADS_URL,
  appId: "my-app",
  eventContext: () => ({
    platform: "android",
    appVersion: "1.2.3",
    locale: "ko-KR",
  }),
  sessionStore: new MySessionStore(),
  presenceEnabled: false,
});

platform.start();

옵션

옵션 기본 의미
baseUrl 필수 api 역할 URL
appId 필수 레지스트리의 app_id
iapBaseUrl ingestBaseUrl adsBaseUrl baseUrl 역할별 URL. production은 전부 지정. adsBaseUrl을 주면 세션 발급도 그리로 간다 — AppsInToss mTLS 자격증명이 ads/iap 역할에 격리돼 있기 때문
eventContext {} 배치 공통 환경. 객체 또는 함수. 함수면 flush 시점에 평가
eventAllowlist 전부 허용 플랫폼으로 보낼 이벤트 이름. 목록 밖은 조용히 버림
eventFlushIntervalMs 10000 자동 전송 주기. 0이면 수동 flush만
sessionStore 메모리 세션 영속화. 앱 재시작 후 로그인 유지
eventOutbox 메모리 500건 실패 배치 보관소
configTtlMs SDK 기본 Remote Config 캐시 수명
presenceEnabled false RPI edge heartbeat. 명시적으로 켠 앱만
presenceContext eventContext의 platform·appVersion heartbeat에 실을 환경
maxRetries timeoutMs SDK 기본 전송 계층 재시도·제한 시간
appCheckToken 없음 Firebase App Check 토큰 공급자. require_app_check 앱에 필수
fetchImpl now random sleep 전역 테스트 주입점

Platform 인스턴스는 session events iap config ads identity content presence 모듈을 갖습니다. 전부 같은 전송 계층과 세션을 공유합니다.

인증

자격증명 종류

type Credential = {
  kind: "firebase-id-token" | "ait-login" | "anonymous";
  value: string;
  referrer?: "DEFAULT" | "SANDBOX";   // ait-login에서 appLogin이 준 값
};
kind value 결제
firebase-id-token 앱 Firebase Auth의 ID 토큰 가능
ait-login AppsInToss appLogin()의 authorization code 가능
anonymous getAnonymousKey() 해시 불가 — bearer가 아니라 사칭 가능
const session = await platform.signIn({ kind: "firebase-id-token", value: idToken });
session.platformUserId;   // pu_...
session.supportCode;      // CS 화면에 보여줄 코드
session.isAnonymous;
session.isLinkedAccount;  // Kakao·Apple 연결 또는 AppsInToss 세션
session.expiresAt;        // epoch ms

세션은 만료 전에 SDK가 refresh 토큰으로 갱신합니다. 앱은 platform.session.token()을 직접 부를 일이 거의 없습니다 — 각 모듈이 알아서 붙입니다.

세션 발급과 갱신

sequenceDiagram
  autonumber
  participant App as 앱
  participant FB as Firebase Auth
  participant SDK as Platform SDK
  participant API as platform-api
  participant FS as Firestore
  App->>FB: 로그인
  FB-->>App: ID 토큰
  App->>SDK: signIn kind firebase-id-token
  SDK->>API: POST /v1/auth/session — X-Seori-App 헤더
  API->>API: 레지스트리에서 앱 조회 · paused면 403
  API->>API: ID 토큰 서명 · aud · iss · exp 검증
  API->>FS: 차단 목록 확인
  API->>FS: app_id + uid → platform_user_id 매핑 · 없으면 생성
  API-->>SDK: platformToken · refreshToken · supportCode · config
  SDK->>SDK: SessionStore에 저장
  SDK-->>App: Session
Loading

세션 갱신은 SDK가 알아서 합니다. 동시에 여러 호출이 만료를 만나도 refresh는 한 번만 나갑니다 — 서버가 refresh 토큰을 회전시키는 순간 나머지가 무효 토큰을 들고 실패하기 때문입니다.

sequenceDiagram
  participant App as 앱
  participant SDK as Platform SDK
  participant API as platform-api
  App->>SDK: 인증이 필요한 호출
  SDK->>SDK: expiresAt까지 60초 미만인가
  alt 아직 유효
    SDK-->>App: 저장된 platformToken으로 진행
  else 만료 임박 — 동시 호출도 refresh는 한 번
    SDK->>API: POST /v1/auth/refresh — refreshToken
    alt 200
      API-->>SDK: 새 세션
      SDK->>SDK: 저장 후 진행
    else 401 또는 403
      SDK->>API: 보관한 자격증명으로 POST /v1/auth/session 재로그인
      Note over SDK: 계정 연결 뒤에는 자격증명을 버리므로<br/>재로그인하지 않고 오류를 던진다
    end
  end
Loading

Firebase 계정이 아직 없을 때 — custom token bridge

플랫폼이 앱 Firebase 프로젝트용 custom token을 발급합니다. 레지스트리에 features.firebase_custom_token_bridge가 켜져 있어야 합니다.

// 1. 플랫폼에서 custom token을 받는다 (세션 불필요)
const { firebaseCustomToken, appUserId } = await platform.identity.firebaseCustomToken();
// 2. Firebase에 로그인한다
await auth().signInWithCustomToken(firebaseCustomToken);
// 3. ID 토큰으로 플랫폼 세션을 연다
const idToken = await auth().currentUser!.getIdToken();
await platform.signIn({ kind: "firebase-id-token", value: idToken });
sequenceDiagram
  autonumber
  participant App as 앱
  participant SDK as Platform SDK
  participant API as platform-api
  participant IAM as GCP IAM signJwt
  participant FB as Firebase Auth
  App->>SDK: identity.firebaseCustomToken
  SDK->>API: POST /v1/auth/firebase-custom-token — App Check 헤더
  API->>API: uid 생성 · 기존 ID 토큰이 있으면 그 uid 보존
  API->>IAM: 앱의 platform-auth 서비스 계정으로 서명
  IAM-->>API: custom token
  API-->>SDK: firebaseCustomToken · appUserId
  SDK-->>App: 결과 — 저장하지 않는다
  App->>FB: signInWithCustomToken
  FB-->>App: ID 토큰
  App->>SDK: signIn kind firebase-id-token
  Note over SDK,API: 이후는 일반 세션 발급 흐름
Loading

이미 Firebase 계정이 있는 사용자를 이전할 때는 firebaseCustomToken(existingIdToken)으로 기존 uid를 보존합니다. 신규 발급 요청은 자동 재시도하지 않습니다 — 응답이 유실된 뒤 다시 부르면 다른 uid가 생길 수 있습니다. custom token은 한 번 쓰고 저장하지 않습니다.

AppsInToss 로그인

Firebase ID 토큰이 없습니다. appLogin()이 준 authorization code를 ait-login으로 넘기면 서버가 Toss Login API와 mTLS로 교환합니다. 이 자격증명은 iap·ads 역할에만 있으므로 adsBaseUrl을 지정해 세션 발급을 그쪽으로 보냅니다.

sequenceDiagram
  autonumber
  participant App as 앱 — AppsInToss
  participant AIT as AppsInToss SDK
  participant SDK as Platform SDK
  participant IAP as platform-iap 또는 platform-ads
  participant TOSS as Toss Login API
  App->>AIT: appLogin
  AIT-->>App: authorization code · referrer
  App->>SDK: signIn kind ait-login · referrer
  SDK->>IAP: POST /v1/auth/session
  IAP->>TOSS: mTLS로 code 교환
  TOSS-->>IAP: 사용자 식별자
  IAP->>IAP: 앱 범위 platform_user 매핑
  IAP-->>SDK: 세션 — isLinkedAccount true
  SDK-->>App: Session
  Note over SDK,IAP: mTLS 자격증명이 iap · ads 역할에만 있어<br/>세션 발급 host를 그쪽으로 지정한다
Loading

계정 연결 — Kakao, Apple

유료 접근(iap.require_linked_account)이 켜진 앱은 연결 세션에서만 결제할 수 있습니다.

const challenge = await platform.identity.beginAccountLink("kakao");
// 로그인 SDK에 challenge.nonce를 넣어 OIDC ID 토큰을 받는다
const result = await platform.identity.completeAccountLink("kakao", oidcIdToken, challenge.nonce);
result.session;              // 교체된 세션. SDK가 이미 adopt했다
result.restored;             // 기존 계정으로 복원됐는지
result.firebaseCustomToken;  // 앱 Firebase도 같은 계정으로 맞출 때

completeAccountLink는 자동 재시도하지 않습니다. 레지스트리의 auth.account_providers에 provider audience가 등록돼 있어야 합니다.

sequenceDiagram
  autonumber
  participant App as 앱
  participant SDK as Platform SDK
  participant API as platform-api
  participant PV as Kakao 또는 Apple 로그인 SDK
  App->>SDK: identity.beginAccountLink provider
  SDK->>API: POST /v1/auth/account-link-challenges — 현재 세션
  API-->>SDK: nonce · expiresAt — 5분
  SDK-->>App: challenge
  App->>PV: nonce를 넣어 로그인
  PV-->>App: OIDC ID 토큰
  App->>SDK: identity.completeAccountLink provider · idToken · nonce
  SDK->>API: POST /v1/auth/account-links — noRetry
  API->>API: iss · aud · exp · 서명 · nonce 검증
  API->>API: provider subject를 SHA-256으로 앱 범위 매핑 · 원문 미저장
  alt 새 게스트가 기존 공급자 계정을 증명
    API-->>SDK: 기존 platform 사용자로 전환 — restored true
  else 처음 연결
    API-->>SDK: 현재 사용자에 연결
  else 서로 다른 두 연결 계정
    API-->>SDK: 409 account_link_conflict
  end
  SDK->>SDK: 새 세션 adopt · 보관 자격증명 폐기
  SDK-->>App: session · firebaseCustomToken · restored
Loading

App Check

레지스트리에 require_app_check가 켜진 앱은 custom token 발급과 계정 삭제 경계에서 X-Firebase-AppCheck를 요구합니다.

createPlatform({
  ...,
  appCheckToken: () => appCheck().getToken().then(r => r.token),
});

이벤트

platform.events.track({ name: "level_complete", params: { level: 3, is_new: true } });
  • 던지지 않습니다. 계측 때문에 제품 흐름이 멈추면 안 됩니다
  • 즉시 보내지 않습니다. 20건이 쌓이거나 주기가 되면 배치로 나갑니다
  • 실패 배치는 outbox에 남아 다음 주기에 다시 시도합니다
  • 세션이 없어도 익명으로 수집됩니다

이름은 spec/events.md의 3층 구조를 따릅니다. seori_*는 SDK 예약입니다.

sequenceDiagram
  participant App as 앱
  participant SDK as Platform SDK — Events
  participant OB as Outbox
  participant ING as platform-ingest
  App->>SDK: events.track name · params
  SDK->>SDK: allowlist 확인 · 파라미터 정규화 · eventId 부여
  SDK->>SDK: 버퍼에 추가 — 던지지 않는다
  alt 20건 도달 · 10초 주기 · flush 호출
    SDK->>OB: 이전 실패분 drain
    SDK->>ING: POST /v1/events — 최대 20건 · 세션 토큰은 있으면
    alt 성공
      ING-->>SDK: ok
    else 실패
      SDK->>OB: 배치 보관 — 최대 500건
      Note over OB: 다음 flush에 다시 시도
    end
  end
Loading

파라미터 정규화

두 SDK가 spec/conformance/param-normalization.json을 동일하게 통과합니다.

입력 출력
true / false 1 / 0
NaN, Infinity 0
null, undefined 파라미터 자체를 버림
객체, 배열 버림 — 문자열로 바꾸지 않음
100자 초과 문자열 잘림
PII 키(email, phone 등, PII_KEYS) 버림
파라미터 수 MAX_PARAMS 초과분 버림

수명주기

platform.start();                       // 자동 flush 시작
await platform.events.flush();          // 백그라운드 진입 시
await platform.shutdown();              // 종료 — 남은 것을 보내고 타이머 정지

React Native:

AppState.addEventListener("change", (state) => {
  if (state === "active") { platform.start(); platform.presence.resume(); return; }
  platform.presence.stop();
  void platform.events.flush();
});

Web은 SDK가 document.visibilityState를 감지합니다.

결제 (IAP)

const outcome = await platform.iap.verifyPurchase({
  platform: "google_play",           // "google_play" | "app_store" | "apps_in_toss"
  productId: "gecko_galaxy",
  token: purchase.purchaseToken,
});
outcome.status;            // "verified" | "pending" | "revoked"
outcome.entitlements;      // 현재 보유 전체
outcome.granted;           // 이번 호출로 지급됐는지. alreadyGranted와 배타
outcome.completion;        // { action, orderId }
마켓 token
Google Play purchaseToken
App Store transactionId
AppsInToss orderId

completion.action이 none이 아니면 앱이 마켓 쪽 마무리를 해야 합니다.

action 할 일
apps_in_toss_complete_product_grant AppsInToss SDK로 orderId의 지급 완료를 호출
retry_server_completion 서버 완료 처리 대기 중. 잠시 후 verifyPurchase 재호출
app_store_sync_after_sandbox_reset sandbox 초기화 후 StoreKit 동기화

자동 재시도하지 않습니다. 호출 전에 session.token()이 만료 임박 세션을 선제 갱신하고, 응답이 실패하면 그대로 던집니다 — 서버가 멱등이어도 응답을 기다리는 사이 사용자에게는 두 번 결제한 것처럼 보입니다. 재시도는 사용자가 정합니다.

구매 전 계정 참조부터 완료 처리까지의 전체 흐름입니다.

sequenceDiagram
  autonumber
  participant App as 앱
  participant SDK as Platform SDK
  participant MK as 마켓 SDK
  participant IAP as platform-iap
  participant MAPI as 마켓 API
  participant FS as 원장 Firestore
  App->>SDK: iap.accountReferences
  SDK->>IAP: GET /v1/iap/account-references
  IAP-->>SDK: HMAC 계정 참조
  App->>MK: 구매 요청 — obfuscatedAccountId · appAccountToken
  MK-->>App: purchaseToken · transactionId · orderId
  App->>SDK: iap.verifyPurchase platform · productId · token
  SDK->>IAP: POST /v1/iap/verify — noRetry
  IAP->>IAP: 마켓 검증기 선택 · SKU를 entitlement로 변환
  IAP->>MAPI: 구매 확인
  MAPI-->>IAP: 거래 상태
  IAP->>IAP: 계정 바인딩 검증 — 불일치는 신호로 기록하고 지급은 막지 않는다
  IAP->>FS: 트랜잭션 — 지급 · 보류 · 회수
  IAP->>MAPI: 완료 처리 — Play consume 등 · 실패해도 지급 유지
  IAP-->>SDK: status · entitlements · granted 또는 alreadyGranted · completion
  SDK-->>App: VerifyOutcome
  opt completion.action이 none이 아니면
    App->>MK: 마켓 쪽 마무리 — AppsInToss 지급 완료 등
  end
Loading

구매 전 — 계정 참조

다른 사용자가 시작한 구매를 가로채지 못하게 마켓 결제 화면에 계정 참조를 넣습니다.

const refs = await platform.iap.accountReferences();
refs.googlePlayObfuscatedAccountId;   // Play obfuscatedAccountId
refs.appStoreAppAccountToken;         // StoreKit appAccountToken

복원

const owned = await platform.iap.listEntitlements();   // string[]

환불은 마켓 웹훅으로 서버에 먼저 도착합니다. 앱은 다음 시작 때 listEntitlements()로 서버가 아는 최종 상태를 받아 반영합니다.

sequenceDiagram
  autonumber
  participant MAPI as App Store 또는 Google Play
  participant IAP as platform-iap
  participant FS as 원장 Firestore
  participant App as 앱
  participant SDK as Platform SDK
  MAPI->>IAP: 환불 알림 — Apple JWS 또는 Play RTDN
  IAP->>IAP: 서명 · OIDC 검증
  IAP->>FS: 기존 소유자의 entitlement 회수 — 알림만으로 신규 지급은 없다
  Note over App,SDK: 다음 앱 시작
  App->>SDK: iap.listEntitlements
  SDK->>IAP: GET /v1/iap/entitlements
  IAP-->>SDK: 서버가 아는 최종 상태
  SDK-->>App: entitlements — 환불분 제외
Loading

Remote Config

const config = await platform.config.fetch({
  appVersion: "1.2.3",
  platform: "android",   // "android" | "ios" | "web"
  locale: "ko-KR",
});
config.values;                 // Record<string, unknown>
config.features;               // Record<string, boolean>
config.sdk.status;             // "ok" | "deprecated" | "blocked"
config.sdk.updateUrl;
config.maintenance.active;     // 점검 모드
config.maintenance.until;
config.minSupportedVersion;

실패하면 마지막 캐시, 그것도 없으면 열린 기본값을 줍니다. 차단은 서버가 blocked나 maintenance.active를 명시할 때만 합니다. 네트워크 없이 마지막 값을 보려면 platform.config.current().

flowchart TD
  A["config 조회"] --> B{"캐시가 TTL 안인가"}
  B -->|예| C["캐시 반환"]
  B -->|아니오| D["GET /v1/config — appVersion · platform · locale"]
  D --> E{"성공"}
  E -->|예| F["캐시 갱신 후 반환"]
  E -->|아니오| G{"이전 캐시가 있는가"}
  G -->|예| H["마지막 캐시 반환"]
  G -->|아니오| I["열린 기본값 반환 — 차단 없음"]
  F --> J{"sdk.status blocked<br/>또는 maintenance.active"}
  H --> J
  I --> J
  J -->|예| K["앱이 차단 · 점검 화면 표시"]
  J -->|아니오| L["정상 진행"]
Loading

광고 — reward claim

레지스트리에 features.ads와 placement가 등록돼 있어야 합니다.

const policy = await platform.ads.policy();
if (!policy.adsEnabled) return;   // disabledBy: "operator" | "ad_free"

const claim = await platform.ads.createClaim({
  requestId: localId,             // 앱이 만든 멱등 키
  placement: "hint_reward",
  provider: "admob",              // "admob" | "apps_in_toss"
  clientPlatform: "android",
  reward: { key: "hint", amount: 3 },
});
claim.admobSsv;                   // { customData, userId } → 네이티브 SDK의 SSV 옵션에 그대로
상태 뜻
accepted claim 생성. 광고 노출 전
confirmed 보상 확인됨 (assurance: server_verified = SSV, client_confirmed = 클라이언트 보고)
delivered 앱이 ack — 로컬 지급 완료
expired 만료
await platform.ads.confirm(claim.claimId, transactionId);   // SSV가 없는 provider에서 클라이언트 확인
const latest = await platform.ads.claim(claim.claimId);      // 상태 조회
await platform.ads.ack(claim.claimId);                       // 로컬 exactly-once 지급 후

정책 조회 실패를 광고 허용으로 바꾸지 않습니다. 상태를 바꾸는 호출은 자동 반복하지 않습니다.

claim 상태

stateDiagram-v2
  [*] --> accepted: claim 생성
  accepted --> confirmed: AdMob SSV 콜백 — server_verified
  accepted --> confirmed: confirm — client_confirmed · AppsInToss만
  accepted --> expired: expiresAt 경과
  confirmed --> delivered: ack — 로컬 지급 완료 후
  delivered --> [*]
  expired --> [*]
Loading

AdMob — 서버 검증

AdMob이 시청 완료를 서버에 직접 알립니다. 앱은 claim 상태를 조회해 server_verified를 확인한 뒤에만 로컬 지급합니다.

sequenceDiagram
  autonumber
  participant App as 앱
  participant SDK as Platform SDK
  participant ADS as platform-ads
  participant GMA as AdMob SDK
  participant SSV as AdMob SSV
  App->>SDK: ads.policy
  SDK->>ADS: GET /v1/ads/policy
  ADS-->>SDK: adsEnabled · disabledBy
  alt adsEnabled false 또는 조회 실패
    SDK-->>App: 광고 경로 중단 — 실패를 허용으로 바꾸지 않는다
  end
  App->>SDK: ads.createClaim requestId · placement · reward
  SDK->>ADS: POST /v1/ads/reward-claims
  ADS->>ADS: placement · reward 범위 · 일일 한도 · cooldown 확인
  ADS-->>SDK: claim — state accepted · admobSsv customData · userId
  App->>GMA: 보상형 광고 표시 — SSV 옵션에 customData · userId
  GMA->>SSV: 시청 완료
  SSV->>ADS: GET /v1/ads/admob/ssv/appId — 서명 · key_id · custom_data · user_id
  ADS->>ADS: AdMob 공개키로 서명 검증 · claim과 사용자 결합 확인
  ADS->>ADS: 한도 원자적 재판정 → confirmed · server_verified
  App->>SDK: ads.claim claimId
  SDK->>ADS: GET /v1/ads/reward-claims/claimId
  ADS-->>SDK: confirmed · server_verified
  App->>App: 로컬 exactly-once 보상 지급
  App->>SDK: ads.ack claimId
  SDK->>ADS: POST /v1/ads/reward-claims/claimId/ack
  ADS-->>SDK: state delivered
Loading

AppsInToss — 클라이언트 확인

AppsInToss 광고는 SSV가 없어 앱이 confirm으로 transactionId를 보고합니다. 다른 provider에서 confirm을 부르면 ad_claim_assurance_invalid입니다.

sequenceDiagram
  autonumber
  participant App as 앱 — AppsInToss
  participant SDK as Platform SDK
  participant ADS as platform-ads
  participant AIT as AppsInToss 광고 SDK
  App->>SDK: ads.createClaim provider apps_in_toss
  SDK->>ADS: POST /v1/ads/reward-claims
  ADS-->>SDK: claim — state accepted
  App->>AIT: 보상형 광고 표시
  AIT-->>App: 보상 완료 · transactionId
  App->>SDK: ads.confirm claimId · transactionId
  SDK->>ADS: POST /v1/ads/reward-claims/claimId/confirm
  ADS->>ADS: provider가 apps_in_toss인지 확인 · transactionId 해시 · 한도 재판정
  ADS-->>SDK: confirmed · client_confirmed
  App->>App: 로컬 exactly-once 보상 지급
  App->>SDK: ads.ack claimId
  SDK->>ADS: POST /v1/ads/reward-claims/claimId/ack
  ADS-->>SDK: delivered
Loading

Presence (opt-in)

최근 활성 세션 heartbeat입니다. presenceEnabled: true이고 레지스트리에 features.presence가 켜진 앱만 동작합니다. fail-open — 실패를 던지지도, 저장해서 재전송하지도 않습니다. 앱 시작·로그인·결제를 기다리게 하면 안 됩니다.

platform.presence.start();    // platform.start()가 함께 부른다
platform.presence.stop();
platform.presence.resume();   // foreground 복귀

heartbeat에는 익명 세션 ID, sequence, platform, appVersion만 실립니다.

sequenceDiagram
  participant SDK as Platform SDK — Presence
  participant ING as platform-ingest
  participant EDGE as presence edge — RPI
  SDK->>ING: POST /v1/presence/token — 익명 세션 ID
  alt enabled false 또는 발급기 미준비
    ING-->>SDK: enabled false — 5분 뒤 다시 bootstrap
  else
    ING-->>SDK: 단기 토큰 · edgeUrl
    loop 60초 주기 · 실패 시 최대 5분 backoff
      SDK->>EDGE: POST /v1/presence/heartbeat — sequence · platform · appVersion
      EDGE-->>SDK: 200 또는 Retry-After
    end
  end
  Note over SDK: 실패를 던지지도 outbox에 넣지도 않는다
Loading

Content

platform.content.version() / resolve() / term()은 운글(ungeul) 전용 private 콘텐츠 계약(schemaVersion: 1)입니다. 일반 앱은 쓰지 않습니다.

오류 처리

모든 실패는 PlatformError로 던집니다.

import { PlatformError } from "@seorilabs/platform-sdk";

try { ... } catch (err) {
  if (err instanceof PlatformError) {
    err.code;    // "session_expired" — 분기는 이 값으로만
    err.status;  // HTTP 상태
    err.local;   // true면 서버에 닿지 못했다 (network_error 등)
  }
}

전체 목록과 권장 대응은 Error Codes. SDK가 로컬에서 만드는 코드는 network_error, auth_required, purchase_proof_invalid, request_invalid, iap_response_invalid, internal입니다.

세션 저장소 구현

import type { Session, SessionStore } from "@seorilabs/platform-sdk";

class KeychainSessionStore implements SessionStore {
  async load(): Promise<Session | null> { ... }
  async save(session: Session): Promise<void> { ... }
  async clear(): Promise<void> { ... }
}

refreshToken이 들어갑니다. 탈취되면 세션을 계속 갱신할 수 있으므로 Keychain·Keystore를 권장합니다. AsyncStorage 예시는 레퍼런스에 있습니다.

버전 문서

  • 0.4.0 — 현재 권장. Presence 추가
  • 0.3.0 — Ads, Content, Identity
  • 0.1.0 — 인증, 이벤트, IAP, Config

Clone this wiki locally