버전 정책 — @yetdapay/* 및 @yetdapay/* 패키지
읽기 안내
SDK와 CLI 패키지는 아직 1.0 이전입니다. 패키지 버전 정책과 별개로 라이선스 wire v1은 버전 협상을 제공하지 않습니다.
SDK·백엔드 변경 전 호환성 표를 확인하고, 패키지 버전만 보고 호환된다고 판단하지 마세요.
상태:
IMPLEMENTED(정책 문서) — d7 릴리스 후보를 위해 작성됨. 모든 패키지는 pre-1.0이며, 이 정책은 그 의미를 정직하게 말합니다: 아직 안정성 보장이 주장되지 않고, wire 계약에 협상 메커니즘이 없습니다.
1. 범위
| 패키지 | 경로 | 현재 버전 | 발행 상태 |
|---|---|---|---|
@yetdapay/cli | tools/yp | 0.2.0 | private: true — 설계상 미발행(리포 내 vendored 소스 포함); npm pack / npm i -g <tgz> 동작 |
@yetdapay/mcp | tools/devpay-mcp | 0.1.0 | private: true — 설계상 미발행 |
@yetdapay/license-web | sdk/license/web | 0.1.0 | private: false, UNLICENSED — 팩 검증됨, 미발행 |
@yetdapay/license-server | sdk/license/server | 0.1.0 | private: false, UNLICENSED — 팩 검증됨, 미발행 |
@yetdapay/license-nuxt | sdk/license/nuxt | 0.1.0 | private: false, UNLICENSED — 팩 검증됨, 미발행 |
@yetdapay/sdk | sdk/ | 0.1.0 | private: true — copy-in 소스 번들(files: TS/Vue/React 소스), 빌드 아티팩트 아님 |
yetdapay-mcp (Rust) | mcp/ | 0.1.0 | cargo 바이너리, 리포 SHA 버전 |
yetdapay-mcp-gateway | mcp/gateway/ | 0.1.0 | Worker 스크립트, 리포 SHA 버전 |
레지스트리에서 서로를 해결할 수 없는 형제 패키지는 file: 지정자를 사용합니다 — §4 참조.
2. SemVer 정책 (pre-1.0 해석)
Semantic Versioning 2.0.0을 표준 pre-1.0 주의와 함께 따릅니다, 명시적으로 진술하여 추측할 필요가 없게:
0.MINOR.PATCH— wire 계약(§3)이 v1-stable에 도달하고 각 패키지의 공개 JS/TS API가 이 문서에서 안정으로 선언될 때까지 메이저 버전은0유지.- 마이너(
0.x.0) 범프는 깨지는 변경을 포함할 수 있습니다. 이것은0.x의 합법 SemVer이며 사용합니다: 1.0 전의 깨지는 API나 wire 변경은 PATCH가 아닌 MINOR를 올립니다.@yetdapay/cli0.1.0→0.2.0 (플랫폼 명령 표면 추가)이 첫 예입니다. - PATCH(
0.x.y)는 하위 호환 수정에 예약됨 — 공개 시그니처나 wire 바이트를 변경하지 않는 버그 수정, 문서 교정, 테스트/CI 수리. - 깨지는 변경은 조용히 랜딩할 수 없습니다.
interface-contract-matrix.md에 문서화된 인터페이스를 깨는0.x.0범프는CHANGELOG.md의### Removed/### Changed헤딩 아래 마이그레이션 노트와 함께 기록되어야 합니다. "0.x일 뿐"은 체인지로그 항목을 건너뛸 이유가 아닙니다. - 1.0.0 기준(아직 미충족): wire 계약 v1 동결 선언;
@yetdapay/license-*공개 API 안정 선언; 후보 백엔드에 대한sdk-worker-contract.test.mjs의 최소 한 번 실행된 호환 실행이 릴리스 증거에 기록.
3. Wire 계약 버전 관리
| 계약 | 버전 | 협상 | 노트 |
|---|---|---|---|
Entitlement/PoP wire(/api/v1/licenses/{activate,capability,execute,status}, JWS 클레임, DPoP 스타일 증명) | v1 | 없음 — 토큰, 헤더, 엔벨로프에 버전 필드 없음(known-limitations.md §3.2). 호환성은 "동일 계약 세대", 정직하게 협상되지 않음. | |
커머스 REST(/api/v1/public/integrations/*, 호스티드 /h/*, feedbacks/donations POST) | 버전 없는 경로 접두어 /api/v1/ | 없음 | d3(migration 018) 이후 Axum be/와 be-cloudflare에서 동일 페이로드 |
| MCP 프로토콜(로컬 stdio + 원격 게이트웨이) | MCP 2024-11-05 | MCP 프로토콜 버전 핸드셰이크만 | 도구 표면은 버전 없음; 지금까지 도구는 추가적 |
증거 레코드 스키마(yp protect verify 출력) | schema_version: 1 | 명시적 필드 | 오늘 실제 버전 필드를 가진 유일한 아티팩트 |
이미 기록된 wire v2 후보(이 중 하나라도 랜딩 = 계약 v2, 양쪽 SDK MINOR 범프): Worker 발급 entitlement의 aud/tenant_id 클레임, 오류 코드 수렴(INVALID_PUBLIC_JWK, CAPABILITY_INVALID, PAYLOAD_TOO_LARGE, INVALID_STATUS), 모든 토큰 형식 변경. interface-contract-matrix.md §5와 known-limitations.md §3.8 참조.
4. SDK ↔ 백엔드 호환성 매트릭스
interface-contract-matrix.md §1–§4에서 파생(단일 계약 레퍼런스). 아래 "호환"은: 실행된 페어링이 존재하거나, 페어링이 createWorkerConfig()의 한 설정 줄이라는 의미입니다.
| 클라이언트 | Axum be/ | be-cloudflare Worker | 자체 호스팅 @yetdapay/license-server |
|---|---|---|---|
@yetdapay/license-web 0.1.0 | n/a — Axum에 PoP entitlement 플레인 없음(레거시 레코드만) | ✔ createWorkerConfig()로 wire v1(activatePath=/api/v1/licenses/activate, iss=devpay-lic); sdk-worker-contract.test.mjs로 검증(10 검사, 루프백 wrangler dev) | ✔ 기본 설정(activatePath=/api/license/activate, iss=devpay); Scenario C(examples/license-server) |
@yetdapay/license-server 0.1.0 (검증자로서) | n/a — 다른 플레인 | createWorkerConfig()로 클레임 패리티(iss=devpay-lic, aud 미설정, tenant_id 허용); 남은 델타는 문서화된 오류 코드 폴드인(매트릭스 §2) | 네이티브 |
@yetdapay/license-nuxt 0.1.0 | n/a | 위 web+server를 래핑 — 동일 행 | 동일 |
@yetdapay/sdk 0.1.0 | ✔ 기부/피드백 REST — Scenario D 로컬 실행(시딩된 dev-auth sqlite) | ✔ d3(migration 018) 이후 엔드포인트 존재; 배포된 왕복 NOT_VERIFIED — 모든 실행된 증거는 루프백 | n/a |
@yetdapay/cli 0.2.0 플랫폼 명령 | ✔ auth/project/license/integration(dev-auth X-Dev-User 모델) | ✔ integration check 포함(d3 포트); 라이선스 상세 프로브(/bindings, /usage)는 Worker 전용 | n/a |
@yetdapay/mcp 0.1.0 | 로컬 protect 툴링 — 판정은 yp --json을 그대로 통과 | 동일 | n/a |
| 원격 MCP 게이트웨이 0.1.0 | n/a(Worker 타겟) | 20개 도구(10 configure/validate + 10 셀러 스코프/공개 읽기); Bearer 패스스루; 셀러 왕복 NOT_VERIFIED 배포 대상 | n/a |
미발행 형제의 피어 해결
@yetdapay/license-nuxt는 @yetdapay/license-server ^0.1.0과 @yetdapay/license-web ^0.1.0에 peerDependencies를 선언합니다 (license-web은 optional 표시 — 서버 전용 경로는 없이도 동작). 어떤 @yetdapay/* 패키지도 레지스트리에 발행되지 않았으므로, 소비자는 npm에서 이 피어를 해결할 수 없습니다. 오늘 지원되는 설치 패턴은 리포 체크아웃에 대한 file:(또는 팩된 .tgz)이며, examples/license-server/package.json이 하는 것과 정확히 같습니다:
"dependencies": {
"@yetdapay/license-server": "file:../../sdk/license/server",
"@yetdapay/license-web": "file:../../sdk/license/web",
"@yetdapay/license-nuxt": "file:../../sdk/license/nuxt"
}2
3
4
5
npm/pnpm은 file: 설치를 경로당 단일 사본으로 dedupe하므로, license-nuxt 피어 요구는 동일 체크아웃으로 만족됩니다. 실제 발행이 승인되면 ^0.1.0 피어 범위는 정상적으로 해결됩니다; 그때까지 license-nuxt의 레지스트리 설치는 피어 해결에서 경고/실패합니다 — 그것은 버그가 아닌 예상입니다.
5. 깨지는 변경 정책 (pre-1.0)
- 깨지는 변경은 MINOR 범프에서 허용되지만 (a) 의도적이고, (b)
CHANGELOG.md에 기록되고, (c) wire 바이트, 클레임, 오류 코드를 건드릴 때interface-contract-matrix.md에 반영되어야 합니다. - 발급/검증된 entitlement 클레임, 증명 형태, 활성화 요청/응답의 변경은 wire 변경이며 구현 디테일이 아닙니다 — 같은 wave에서 매트릭스와
sdk-worker-contract.test.mjs기대를 업데이트해야 합니다. - 0.x에서도 제거 전 폐기가 선호됩니다: 가능하면 하나의 MINOR 동안 이전 필드/라우트 유지(d5b 기부
donor_name/message수정이 정확히 선택적 + 서버 측 기본값을 선택한 이유는 가장 적게 깨는 방향이기 때문). - Fail-closed 자세는 계약의 일부입니다: 검사 강화(예: 알 수 없는
status→REVOKED)는 깨짐이 아닌 수정; 완화는 INDEPENDENT_SECURITY 승인이 필요한 보안 변경입니다.