@bstage-sdk/core 0.8.3 → 0.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -174,7 +174,7 @@ var HttpTimeoutError = class extends Error {
174
174
  };
175
175
 
176
176
  // src/version.ts
177
- var VERSION = "0.8.3";
177
+ var VERSION = "0.8.5";
178
178
 
179
179
  // src/client/BstageClient.ts
180
180
  function resolveBaseUrl() {
package/dist/index.js CHANGED
@@ -119,7 +119,7 @@ var HttpTimeoutError = class extends Error {
119
119
  };
120
120
 
121
121
  // src/version.ts
122
- var VERSION = "0.8.3";
122
+ var VERSION = "0.8.5";
123
123
 
124
124
  // src/client/BstageClient.ts
125
125
  function resolveBaseUrl() {
@@ -97,7 +97,7 @@ Platform → Template 이벤트는 `bubbles: false, composed: false`로 해당
97
97
 
98
98
  > **경로와 응답 모양의 출처는 게이트웨이 API Reference Doc입니다.** SDK가 OpenAPI 스펙에서 경로 타입을 생성해 자동완성을 제공하던 방식은 걷어냈습니다 — 스펙이 바뀌어도 SDK를 새로 배포해야 반영되는 구조라 실제 API 변경을 따라가지 못했습니다. 응답 타입은 호출 시 제네릭으로 명시하세요.
99
99
 
100
- > **지원 범위: 유저단(user-facing) API만.** BstageClient는 게이트웨이(`/gw`)를 타는 **유저 도메인 API**용입니다. **어드민용 API는 지원하지 않습니다** — 어드민은 게이트웨이를 타지 않고 인증 모델도 다릅니다. 어드민 API 호출이 필요한 경우 임의로 경로를 추측해 호출하지 말고 **반드시 사용자에게 먼저 확인**하세요.
100
+ > **지원 범위: 게이트웨이(`/gw`)를 타는 API.** 유저 템플릿은 유저 도메인의 게이트웨이를 PUBLIC 키(`bsp_`)로, 어드민 템플릿은 어드민 도메인의 **어드민 게이트웨이**를 MANAGEMENT 키(`bsm_`) + 어드민 로그인 세션으로 부릅니다. 같은 클라이언트이고 `baseUrl` 기본값이 현재 도메인을 따르므로 코드는 갈리지 않습니다 — 조건·에러는 [GETTING_STARTED.md](./GETTING_STARTED.md) "8. 어드민 템플릿 › API 호출"을 보세요. 어느 쪽이든 **포털 API 레퍼런스(유저/운영자 탭)에 있는 경로만** 씁니다. 목록에 없는 API가 필요하면 임의로 경로를 추측해 호출하지 말고 **반드시 사용자에게 먼저 확인**하세요.
101
101
 
102
102
  ```typescript
103
103
  const client = new BstageClient({
@@ -112,7 +112,7 @@ const client = new BstageClient({
112
112
  | 옵션 | 타입 | 설명 |
113
113
  | ----------- | --------------------------------------------- | ------------------------------------------------------------ |
114
114
  | `appId` | `string` | 앱 식별자 |
115
- | `appKey` | `string` | 앱 키(APP KEY). `appKey`·`appSecret` 중 하나는 필요합니다. 포털이 발급하고 게이트웨이 `X-BSTAGE-APP-KEY` 헤더로 검증하는 값. **브라우저에 노출되는 값**으로 비밀값이 아닙니다 |
115
+ | `appKey` | `string` | 앱 키(APP KEY). `appKey`·`appSecret` 중 하나는 필요합니다. 포털이 발급하고 게이트웨이 `X-BSTAGE-APP-KEY` 헤더로 검증하는 값. **브라우저에 노출되는 값**으로 비밀값이 아닙니다. 유저 템플릿은 PUBLIC(`bsp_`), 어드민 템플릿은 MANAGEMENT(`bsm_`) 키입니다 |
116
116
  | `appSecret` | `string` (deprecated) | `appKey`의 옛 이름. 값은 같습니다. 둘 다 주면 `appKey`가 우선하며, 0.4.0(공개 배포판 `@bstage-sdk/core` 기준)에서 제거됩니다 |
117
117
  | `tenantId` | `string` | 테넌트 식별자 |
118
118
  | `phase` | `'dev' \| 'qa' \| 'real' \| 'sandbox'` (선택) | 환경. 현재 미사용 (향후 확장용) |
@@ -573,9 +573,20 @@ npx @bstage-sdk/cli@latest init --target admin
573
573
 
574
574
  어드민 템플릿은 `<BstageLocaleProvider target="admin">` 하위에서 로케일 훅을 씁니다. 번역 코드젠도 `bstage i18n pull --target admin`입니다. 상세는 [I18N.md](./I18N.md).
575
575
 
576
- ### 아직 안 되는 것
576
+ ### API 호출
577
577
 
578
- **어드민 API 호출 경로는 없습니다.** `BstageClient`는 게이트웨이(유저단 API)만 지원하며 어드민용 게이트웨이는 아직 열리지 않았습니다. 어드민 데이터가 필요한 템플릿은 그때까지 기다려야 합니다 — 경로를 임의로 만들어 호출하지 마세요.
578
+ 어드민 템플릿도 **같은 `BstageClient`로 호출합니다.** `baseUrl`을 주지 않으면 `location.origin + '/gw'`가 되므로 어드민 도메인에 임베드된 화면은 자동으로 **어드민 게이트웨이**를 향합니다. 코드는 [6.1 BstageClient 설정](#61-bstageclient-설정)과 같고, 다른 점은 게이트웨이가 **두 가지를 함께 확인**한다는 것뿐입니다.
579
+
580
+ | 확인하는 것 | 어디서 오나 | 템플릿이 할 일 |
581
+ | --- | --- | --- |
582
+ | 로그인한 운영자인가 | 어드민 로그인 쿠키 — 같은 도메인이라 브라우저가 자동으로 실어 보냅니다 | 없음 |
583
+ | 허가된 앱인가 | `X-BSTAGE-APP-ID`·`X-BSTAGE-APP-KEY` 헤더 — **관리자 콘솔용(MANAGEMENT) 키**(`bsm_`)만 통과합니다 | `.env`와 포털 빌드 환경변수에 MANAGEMENT 키를 넣습니다 |
584
+
585
+ - **키 발급**: 포털 `조직 › API 키`에서 키 타입 **MANAGEMENT**, 스테이지는 이 화면이 들어갈 **하나**, 허용 Origin은 **어드민 콘솔 도메인**(예: sandbox는 `https://{스테이지ID}.mysandstage.in`)으로 발급합니다. 허용 Origin에 자동으로 채워지는 값은 유저 도메인이라 그대로 두면 어드민에서 온 호출이 거부됩니다. 변수 이름은 유저 템플릿과 같고 값만 다릅니다 — `VITE_BSTAGE_APP_KEY=bsm_…`.
586
+ - **Surface와 키 타입은 짝입니다** — USER ↔ PUBLIC(`bsp_`), ADMIN ↔ MANAGEMENT(`bsm_`). PUBLIC 키로 어드민 게이트웨이를 부르면 `401 KEY_TYPE_NOT_ALLOWED`, 어드민에 로그인하지 않았거나 어드민 도메인 밖에서 부르면 `401 MISSING_ADMIN_ACCESS_TOKEN`, 허용 Origin이 유저 도메인으로 남아 있으면 `403`입니다. 반대로 MANAGEMENT 키를 유저 템플릿에 넣으면 유저 게이트웨이가 거부하고 키만 노출됩니다 — 그래서 포털은 사용자(USER) 레포의 빌드 환경변수에 `bsm_` 값을 저장하지 않습니다(400). 게시한 뒤에는 `bstage doctor`가 키 타입 불일치(`appkey.type_surface`)를 짚어 줍니다.
587
+ - **MANAGEMENT 키도 빌드 결과물에 평문으로 실립니다.** 어드민 화면을 열 수 있는 사람은 개발자 도구로 볼 수 있으므로, 허용 Origin과 스테이지 범위를 좁히는 발급 조건이 곧 방어선입니다. 의심되면 포털에서 회전(새 키 발급 + 옛 키 폐기)한 뒤 빌드 환경변수를 바꾸고 다시 빌드합니다. 서버용(SIGNING) 키는 어떤 템플릿에도 넣지 않습니다.
588
+ - **호출할 수 있는 API**는 포털 개발자 문서의 **API 레퍼런스 › 운영자 탭**에 있는 것뿐입니다. 거기 없는 경로를 추측해 만들지 말고, 필요한 API가 목록에 없으면 b.stage에 요청하세요.
589
+ - **로컬·미리보기에서는 응답이 오지 않습니다.** `bstage dev`는 어드민 게이트웨이를 프록시하지 않고(어드민 모드에서 어드민 호스트로 가는 것은 로그인뿐), 포털 미리보기는 템플릿의 직접 게이트웨이 호출을 막습니다. 어드민 API 응답은 게시한 뒤 실제 어드민 화면에서 확인하세요.
579
590
 
580
591
  ---
581
592
 
@@ -613,6 +624,7 @@ CI에서는 `BSTAGE_TOKEN`·`BSTAGE_PORTAL_URL`(또는 `VITE_BSTAGE_PHASE`)·`BS
613
624
  | `login` / `logout` / `whoami` | 토큰 등록·삭제·확인 |
614
625
  | `link` | 디렉터리 ↔ 조직/스테이지/레포 |
615
626
  | `list` | 배치 상태·라이브 커밋·최근 빌드 |
627
+ | `doctor [--placement]` | 배치별 포털 진단 (문제·조치, `--json`) |
616
628
  | `logs [buildId] [-f]` | 빌드 로그 |
617
629
  | `deploy [--placement] [--yes] [--no-wait]` | 빌드 → 라이브 적용 |
618
630
  | `placement create --template [--path]` | 페이지 배치 만들기 (빌드 없으면 빌드부터) |
@@ -635,6 +647,8 @@ CI에서는 `BSTAGE_TOKEN`·`BSTAGE_PORTAL_URL`(또는 `VITE_BSTAGE_PHASE`)·`BS
635
647
 
636
648
  위젯(슬롯) 배치를 만드는 일과 배치를 지우는 일은 포털 화면에서만 합니다.
637
649
 
650
+ **배포했는데 페이지가 기대와 다르면 `bstage doctor`부터 실행하세요.** 로그인·링크된 디렉터리에서는 로컬 진단 뒤에 "포털 진단" 절이 붙어, 이 레포의 배치마다 포털이 판정한 문제(게시 꺼짐, 게시된 빌드 없음, 만료·불일치한 앱 키, 화면과 맞지 않는 키 타입, 다시 빌드하지 않은 환경변수, 반영 안 된 새 빌드 등)를 조치와 함께 보여 줍니다. 14일 안에 만료되는 키는 경고(`appkey.expiring_soon`)로 미리 알려 줍니다. 배치가 많으면 30개까지만 보고, `--placement <id|경로|슬롯 id>`로 하나만 볼 수 있습니다. `--json`은 `portal.placements[].findings[]`에 `{ id, severity, title, detail?, fix?, evidence? }`를 담고 `id`(예: `appkey.expired`)는 바뀌지 않는 식별자입니다. 진단에 `error` 항목이 있으면 종료 코드 1입니다(`warn`·`info`는 종료 코드를 바꾸지 않습니다). 로그인·링크가 없거나 포털이 아직 진단을 지원하지 않으면 그 절만 건너뜁니다(단 `--placement`를 줬으면 위 표대로 2·3으로 끝납니다).
651
+
638
652
  로컬에서 산출물을 확인하고 싶으면 `npx bstage build`를 실행합니다. 페이지는 `dist/{경로}/template.js`, 위젯은 `dist/{슬롯 id}/template.js`로 나옵니다.
639
653
 
640
654
  배포 절차를 에이전트에게 맡기려면 `bstage-deploy` 스킬을 쓰세요([AI_TOOLKIT.md](./AI_TOOLKIT.md)).
@@ -658,9 +672,9 @@ CI에서는 `BSTAGE_TOKEN`·`BSTAGE_PORTAL_URL`(또는 `VITE_BSTAGE_PHASE`)·`BS
658
672
 
659
673
  | 증상 | 원인 | 조치 | 소관 |
660
674
  | ----------------------- | ---------------------------------------- | -------------------------------------------- | ------------ |
661
- | `401 Unauthorized` | 다른 환경(QA 등)의 키로 배포 / 키 미발급 | 배포할 환경에서 발급한 appId·appKey인지 확인 | 파트너 콘솔 |
675
+ | `401 Unauthorized` | 다른 환경(QA 등)의 키로 배포 / 키 미발급 / 재발급 전 옛 APP ID | 배포할 환경에서 발급한 사용 중인 appId·appKey인지 확인(`bstage doctor`가 알려 줌) | 파트너 콘솔 |
662
676
  | `403 Forbidden` | Space ID가 프로젝트에 미등록 | BE에 Space ID 등록 요청 | BE |
663
- | `400 MISSING_ORIGIN` | 키의 Allowed Origins에 배포 도메인 없음 | 배포 도메인을 키 설정에 추가 요청 | BE (키 설정) |
677
+ | `403 ORIGIN_NOT_ALLOWED` | 키의 허용 Origin에 배포 도메인 없음(끝의 `/`·대문자도 다른 값) | 키 상세에서 허용 Origin에 `https://{도메인}` 그대로 추가, 재빌드 불필요 | 포털 (키 설정) |
664
678
  | 템플릿이 화면에 안 뜸 | 콘솔 "커스텀 템플릿 사용" 토글이 꺼짐 | 콘솔에서 토글 확인 | 콘솔 |
665
679
  | 배포 자체가 안 됨 | 데브포털 접근·리얼 배포 권한 없음 | 권한 요청 | DevOps |
666
680
  | 임베드(iframe)가 차단됨 | CSP `frame-ancestors`에 도메인 없음 | 도메인 추가 요청 | BE·보안 |
package/docs/MIGRATION.md CHANGED
@@ -51,6 +51,63 @@
51
51
 
52
52
  ---
53
53
 
54
+ ## → cli 0.8.5 · ai-toolkit 0.8.5
55
+
56
+ ### `bstage doctor`: 포털 진단이 실패해도 종료 코드 1 — `자동` · `선택`
57
+
58
+ **영향**
59
+
60
+ - CI·스크립트·에이전트가 `bstage doctor`의 종료 코드를 보는 프로젝트. 로그인·링크가 없는 환경(포털 진단 `skipped`)은 영향이 없다.
61
+
62
+ **변경 내용**
63
+
64
+ - 포털 진단 자체가 실패하면 — 배치 목록 조회 실패, 일부 배치 진단의 권한 부족(403)·서버 오류(5xx) 등으로 `portal.status`가 `"error"`면 — 종료 코드 **1**로 끝난다. 전에는 `error` 심각도 항목이 없으면 0이라, 진단을 못 끝낸 것을 "문제 없음"으로 읽을 수 있었다.
65
+ - 그대로인 것: `error` 항목이 있으면 1, 건너뜀(`skipped`)·서버 미지원(`unsupported`)·`warn`/`info`만 있으면 0, 로컬 진단 결과는 종료 코드에 영향 없음.
66
+
67
+ **적용**
68
+
69
+ 1. (자동) CLI를 올린다. 종료 코드 1을 실패로 처리하던 CI는 그대로 동작한다. 1이 나오면 `--json`의 `portal.status`·`portal.reason`·`portal.placements[].error`로 원인을 본다(권한 부족이면 스테이지 관리 권한이 있는 계정·토큰인지 확인).
70
+
71
+ ### 어드민 템플릿도 `BstageClient`로 어드민 API를 부른다(에이전트 안내 정정) — `자동`
72
+
73
+ **영향**
74
+
75
+ - 코드·빌드 동작은 바뀌지 않는다. 에이전트 안내 문서만 바로잡았다.
76
+ - `AGENTS.md` 관리 영역과 `bstage-template` 스킬이 "BstageClient는 유저단 API만 지원하고 어드민용 API는 미지원"이라고 안내했다. 어드민 게이트웨이가 열린 지금 이 문구를 따르면 에이전트가 어드민 템플릿의 데이터 호출을 거부하거나 사용자 확인을 되풀이한다.
77
+
78
+ **변경 내용**
79
+
80
+ - 어드민 템플릿도 같은 `BstageClient`를 쓴다. 어드민 도메인에 임베드되면 `baseUrl` 기본값이 어드민 게이트웨이(`/gw`)가 되고, 게이트웨이가 어드민 로그인 쿠키와 MANAGEMENT 키(`bsm_`)를 함께 확인한다. PUBLIC 키로는 `KEY_TYPE_NOT_ALLOWED`다.
81
+ - 호출 가능한 경로는 포털 API 레퍼런스(유저/운영자 탭)에 있는 것뿐이며, 목록에 없는 API는 경로를 추측하지 말고 사용자에게 먼저 확인한다는 안내는 그대로다.
82
+ - **AGENTS.md 관리 영역 v17**: 파일 트리의 `client.ts` 설명과 API 금지 사항 절을 위 내용으로 고쳤다. `bstage-template` 스킬도 같은 내용으로 고쳤다. 상세는 [GETTING_STARTED.md](./GETTING_STARTED.md) "8. 어드민 템플릿 › API 호출".
83
+
84
+ **적용**
85
+
86
+ 1. (자동) `npx @bstage-sdk/cli@latest ai update` — 스킬·`AGENTS.md` 관리 영역을 v17로 갱신한다.
87
+
88
+ ## → cli 0.8.4 · ai-toolkit 0.8.4
89
+
90
+ ### `bstage doctor`가 포털 배치 진단을 함께 본다 — `자동` · `선택`
91
+
92
+ **영향**
93
+
94
+ - 로그인(`bstage login`)·링크(`bstage link`)된 디렉터리에서 `bstage doctor`를 실행하는 모든 프로젝트. 로그인·링크가 없으면 지금과 같다(포털 진단 절만 "건너뜀"으로 표시).
95
+ - **종료 코드가 새로 생긴다.** 포털 진단에 `error` 심각도 항목이 하나라도 있으면 `bstage doctor`가 **1**로 끝난다. 예전엔 항상 0이었다. CI·스크립트에서 doctor의 종료 코드를 실패로 처리하고 있다면 확인한다(로컬 진단 결과는 여전히 종료 코드에 영향이 없다).
96
+ - 감지: `bstage doctor --json` 출력에 `portal` 필드가 있으면 이 버전 이상이다.
97
+
98
+ **변경 내용**
99
+
100
+ - 로컬 진단 뒤에 **"포털 진단"** 절이 붙는다. 이 레포(링크된 레포)의 배치마다 포털이 판정한 문제를 심각도(`✗` error · `!` warn · `·` info), 제목, 상세, 조치와 함께 보여 준다 — 스테이지 커스텀 페이지 꺼짐, 배치 게시 꺼짐, 게시된 빌드 없음, 게시 빌드의 APP ID·KEY 문제(만료·스코프·짝 불일치·앞뒤 공백), 다시 빌드하지 않은 환경변수, 반영하지 않은 새 성공 빌드, 최신 빌드 실패 등. 문제가 없으면 `✓ 문제 없음`이다.
101
+ - 배치는 30개까지(동시 4개) 진단한다. **`--placement <id|경로|슬롯 id>`**로 하나만 볼 수 있다(`bstage deploy --placement`와 같은 정확 일치). `--placement`를 줬는데 링크가 없으면 종료 코드 2, 토큰이 없으면 3이다.
102
+ - `--json`(stdout 객체 하나)에 **`portal`** 필드가 더해진다(기존 필드는 그대로): `{ status: 'ok'|'skipped'|'unsupported'|'error', reason?, hint?, omitted?, placements: [{ placementId, path, slotId, surface, findings: [{ id, severity, title, detail?, fix?, evidence? }], error? }] }`. `findings[].id`(예: `appkey.expired`, `placement.not_deployed`)는 바뀌지 않는 식별자라 스크립트·에이전트가 분기에 쓸 수 있다. 진단 요청이 실패한 배치는 `error`에 이유가 담기고 `status`는 `error`다.
103
+ - 포털 서버가 아직 진단을 지원하지 않으면(`status: 'unsupported'`) 그 절만 건너뛴다. CLI 토큰은 `read` 등급이면 된다.
104
+ - `bstage-deploy` 스킬: 배포 후 401이 나거나 페이지가 기대와 다르면 `bstage doctor --json`부터 실행해 `portal.placements[].findings`의 `id`·`fix`를 따르도록 안내한다.
105
+
106
+ **적용**
107
+
108
+ 1. (자동) CLI를 올리면 된다. 스킬 문구는 `npx @bstage-sdk/cli@latest ai update`로 갱신한다.
109
+ 2. (판단) CI에서 `bstage doctor`를 돌리고 있다면 새 종료 코드 1을 실패로 볼지 정한다. 로그인·링크가 없는 CI라면 영향이 없다.
110
+
54
111
  ## → cli 0.8.3 · ai-toolkit 0.8.3
55
112
 
56
113
  ### sandbox 포털 기본 주소가 공개 주소로 바뀌었다 — `자동`
@@ -96,7 +96,7 @@ graph LR
96
96
 
97
97
  Core는 프레임워크 바인딩과 플랫폼 통합 양쪽에서 사용되지만 서드파티에게 직접 노출되지 않습니다. 서드파티는 React 바인딩의 API만 쓰고 플랫폼은 Host SDK의 API만 사용합니다.
98
98
 
99
- **어드민 템플릿도 같은 패키지·같은 명령을 씁니다.** 갈리는 것은 프로젝트가 `package.json`의 `bstage.target`으로 선언하는 대상뿐이며 런타임 등록 경로와 어댑터는 하나입니다. 다만 **어드민 API 호출 경로는 아직 없습니다** — `BstageClient`는 게이트웨이(유저단)만 지원하고 어드민용 게이트웨이는 열리지 않았습니다. 자세한 내용은 [GETTING_STARTED.md](./GETTING_STARTED.md)의 "어드민 템플릿" 절을 참조하세요.
99
+ **어드민 템플릿도 같은 패키지·같은 명령을 씁니다.** 갈리는 것은 프로젝트가 `package.json`의 `bstage.target`으로 선언하는 대상뿐이며 런타임 등록 경로와 어댑터는 하나입니다. API 호출도 같은 `BstageClient`입니다 — `baseUrl` 기본값이 현재 도메인의 `/gw`라 어드민 도메인에서는 **어드민 게이트웨이**를 부르고, 게이트웨이가 어드민 로그인 세션과 MANAGEMENT 키를 함께 확인합니다. 자세한 내용은 [GETTING_STARTED.md](./GETTING_STARTED.md)의 "어드민 템플릿 › API 호출" 절을 참조하세요.
100
100
 
101
101
  ---
102
102
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bstage-sdk/core",
3
- "version": "0.8.3",
3
+ "version": "0.8.5",
4
4
  "description": "bstage SDK core — HTTP client for b.stage API",
5
5
  "type": "module",
6
6
  "publishConfig": {