Skip to content

JavaScript 변환

기본적으로 구독자는 canonical JSON 레코드를 그대로 받습니다. 서버가 다른 것을 원한다면 — Markdown, 다른 JSON 형태, 텍스트 한 줄 — 그 구독자에 변환 스크립트를 연결해 본문을 직접 만드세요.

계약

함수 하나만 제공하면 됩니다.

js
function transform(data, context) {
  // HTTP 요청 본문(BODY)을 반환하세요
}
  • 문자열 반환 → 그대로 전송됩니다 (Markdown, 일반 텍스트, 폼 인코딩 등).
  • 객체 또는 배열 반환 → JSON.stringify(...) 결과가 전송되고, Content-Typeapplication/json으로 유지됩니다.
  • 그 밖의 값 반환 (undefined, 숫자, 불리언) → 전송이 실패합니다. 의도된 동작입니다. Courier는 비어 있거나 반쯤 만들어진 데이터를 절대 보내지 않습니다.

스크립트가 제어하는 것은 본문뿐입니다. URL, 메서드, 헤더, 인증은 구독자에 설정된 그대로 유지됩니다. 스크립트가 연결되어 있으면 정적 본문 매개변수는 무시됩니다 — 본문을 직접 만들어야 합니다.

샌드박스

스크립트는 기기 내의 밀폐된 JavaScriptCore 샌드박스에서 실행됩니다.

  • 네트워크도, 파일 시스템도, DOM도, require도, setTimeout도 없습니다.
  • 오류와 무한 루프는 전송을 실패시키며, 그 사유가 발행 내역에 표시됩니다.
  • console.log / warn / error는 캡처되어 테스트 미리보기에서만 표시됩니다.

context 참조

모든 값은 문자열입니다.

필드예시
context.endpointName"My Obsidian relay"
context.url목적지 URL
context.kind"workout" | "sleep" | "note" | "weather"
context.now이번 발행의 ISO-8601 타임스탬프
context.timeZone"Asia/Shanghai"
context.locale"zh-Hans"
context.appVersion / context.appBuild"1.0.0" / "1"
context.idempotencyKey이번 전송에 실릴 Idempotency-Key

data 참조

data는 해당 구독자 종류의 canonical 레코드입니다. 날짜는 ISO-8601 문자열이며(new Date(data.start)로 파싱), 선택적 필드는 없을 수 있습니다.

kind === "workout"

FieldTypeNotes
idstringHealthKit UUID — 멱등성의 기준
activityTypestring"running", "cycling", "walking", …
sourceobject{ name, bundleIdentifier?, productType?, version? }
start, endstringISO-8601
durationnumber
distanceMetersnumber?
activeEnergyKcal, totalEnergyKcalnumber?
elevationGainMetersnumber?
heartRateobject?{ averageBpm?, minBpm?, maxBpm? }
avgPaceSecPerKmnumber?
lapsarray?[{ index, start, duration, distanceMeters? }]
heartRateSeriesarray?심박 시계열 토글이 켜져 있을 때만
routearray?경로 토글이 켜져 있을 때만. 용량 큼
metadataobject?HealthKit 메타데이터 그대로 전달
schemaVersionnumber

kind === "sleep"

FieldTypeNotes
idstring
nightOfstring이 밤이 귀속되는 날짜
inBedStart, inBedEndstring?
sleepStart, sleepEndstring
timeInBedSecnumber?
totalAsleepSecnumber
stagesobject{ awakeSec, remSec, coreSec, deepSec, unspecifiedSec }
awakeningsnumber
efficiencyPctnumber?0–100
vitalsobject?{ averageHeartRateBpm?, averageHRVms?, respiratoryRate?, oxygenSaturation?, wristTemperatureDeltaC? }
segmentsarray[{ stage, start, end }], stage: inBed|awake|rem|core|deep|unspecified
sourcesarray[{ name, bundleIdentifier?, … }]
schemaVersionnumber

kind === "note"

FieldTypeNotes
idstring
createdAtstringISO-8601
textstring기록된 생각 (타이핑 또는 전사)
sourcestring"text" | "audio"
metadataobject?
schemaVersionnumber

kind === "weather"

FieldTypeNotes
idstring"{sleepID}:weather"
capturedAtstring측정된 시각 (≈ 기상 시각)
weatherDatestring함께 발행된 수면의 nightOf
symbolNamestringSF-Symbol 스타일, 예: "cloud.sun"
conditionTextstring예: "Cloudy"
temperatureC, apparentTemperatureCnumber
humidityPctnumber0–100
windKmhnumber
uvIndexnumber
precipitationChancePctnumber0–100
locationobject?{ lat, lon } — 좌표 토글이 켜져 있을 때만
schemaVersionnumber

예시

커스텀 JSON 형태:

js
function transform(data, context) {
  return {
    kind: "workout",
    activity: data.activityType,
    km: data.distanceMeters ? +(data.distanceMeters / 1000).toFixed(2) : null,
    minutes: Math.round(data.duration / 60),
    avgHr: (data.heartRate && data.heartRate.averageBpm) || null,
    at: data.start,
    via: context.endpointName,
  };
}

일반 텍스트 한 줄:

js
function transform(data) {
  const h = Math.floor(data.totalAsleepSec / 3600);
  const m = Math.round((data.totalAsleepSec % 3600) / 60);
  return data.nightOf.slice(0, 10) + " 수면 " + h + "시간 " + m + "분" +
         " (깬 횟수 " + data.awakenings + "회)";
}

주석을 위한 Markdown 인용구:

js
function transform(data) {
  return "> " + data.text + "\n>\n> — " + data.createdAt;
}

작업 흐름

  1. 구독자 편집기에서 스크립트 섹션을 열고 .js 파일을 가져오거나 코드를 붙여넣으세요. 앱이 주석이 충실히 달린 템플릿을 제공하니 거기서 시작할 수 있습니다.
  2. 테스트를 누르세요: 스크립트가 최근 샘플에 대해 실행되고, 실제 전송 전에 정확한 출력 본문, 콘솔 로그, 엔드포인트의 HTTP 응답을 확인할 수 있습니다.
  3. 저장하세요. 이후 이 구독자로 가는 모든 발행이 스크립트를 거칩니다. 스크립트 오류는 잘못된 데이터를 배달하는 대신 발행 내역에서 눈에 보이게 전송을 실패시킵니다.

스크립트는 설정 백업에 포함됩니다

비밀 값(키체인 저장, 절대 내보내지 않음)과 달리 변환 스크립트는 설정 백업에 평문으로 포함됩니다 — 스크립트에 자격 증명을 하드코딩하지 마세요.

집에서 인쇄 · © 2026 Xheldon