@infoteam/account-web 0.6.0 → 0.7.0

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/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 GSA Infoteam
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 GSA Infoteam
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,78 +1,78 @@
1
- # @infoteam/account-web
2
-
3
- 인포팀 계정(IdP) 로그인을 웹 앱에 붙인다. 특정 프레임워크에 의존하지 않는다. React 앱이라면 [`@infoteam/account-react`](../react)를 쓴다.
4
-
5
- ## 설치
6
-
7
- ```bash
8
- pnpm add @infoteam/account-web zod
9
- ```
10
-
11
- ## 사용
12
-
13
- ```ts
14
- import { createAccountClient } from '@infoteam/account-web';
15
-
16
- // 라우터보다 먼저 만든다. callback 으로 열린 페이지면 여기서 주소를 로그인 전 위치로 바꾼다
17
- const account = createAccountClient({ issuer: 'production', clientId, api: apiUrl });
18
-
19
- await account.ready(); // callback 이면 백엔드 로그인을 마치고, 아니면 세션을 복구한다
20
- account.store.subscribe((state) => render(state));
21
-
22
- // 로그인 버튼
23
- await account.login({ returnTo: location.pathname });
24
-
25
- // 라우터 guard
26
- await account.requireAuth({ returnTo: nextUrl });
27
-
28
- // API 요청. 401 이면 토큰을 갱신한 뒤 다시 보낸다
29
- await account.fetch(`${apiUrl}/me`);
30
- ```
31
-
32
- - 상태는 zustand의 vanilla store(`account.store`)에 있으므로, 어느 프레임워크에서든 구독할 수 있다.
33
- - API 요청에는 `account.fetch`, `@infoteam/account-web/openapi-fetch`, `@infoteam/account-web/axios` 중 하나를 쓴다.
34
- - 옵션, guard, 에러 코드, 로그아웃은 React와 같다. [`account-react` README](../react/README.md#사용)를 참고한다.
35
-
36
- ## 백엔드 형식이 다를 때
37
-
38
- `api`는 백엔드가 [세션 프로토콜](../../README.md#세션-프로토콜)을 구현했다고 가정한다. 형식이 다르면 `api` 대신 `session`에 백엔드 호출을 직접
39
- 구현해서 넘긴다. 둘 중 하나만 줄 수 있다.
40
-
41
- ```ts
42
- import { createAccountClient, type Session } from '@infoteam/account-web';
43
-
44
- const session: Session = {
45
- async start(credential) {
46
- if ('ticket' in credential) throw new Error('this backend does not reject logins');
47
- const res = await fetch(`${apiUrl}/oauth/callback`, {
48
- method: 'POST',
49
- credentials: 'include',
50
- headers: { 'content-type': 'application/json' },
51
- body: JSON.stringify({
52
- code: credential.code,
53
- verifier: credential.codeVerifier,
54
- redirectUri: credential.redirectUri,
55
- nonce: credential.nonce,
56
- }),
57
- });
58
- if (!res.ok) throw new Error(`login failed: ${res.status}`);
59
- const { token } = await res.json();
60
- return { tokens: { accessToken: token } };
61
- },
62
- async refresh() {
63
- const res = await fetch(`${apiUrl}/token`, { method: 'POST', credentials: 'include' });
64
- if (res.status === 401) return null; // 세션 없음
65
- if (!res.ok) throw new Error(`refresh failed: ${res.status}`);
66
- return { accessToken: (await res.json()).token };
67
- },
68
- async end() {
69
- await fetch(`${apiUrl}/signout`, { method: 'POST', credentials: 'include' });
70
- },
71
- };
72
-
73
- const account = createAccountClient({ issuer: 'production', clientId, session });
74
- ```
75
-
76
- - `start`는 callback으로 받은 code, PKCE verifier, `redirectUri`, `nonce`를 받는다. 백엔드는 code를 교환할 때 이 `redirectUri`를 그대로 쓰고, id_token의 `nonce`를 확인해야 한다.
77
- - 로그인 전에 추가 입력을 받으려면 `start`가 `{ rejected: { error, ticket } }`를 돌려준다. 그러면 `retryLogin(body)`가 `start({ ticket }, body)`로 다시 부른다.
78
- - `refresh`는 세션이 없으면 `null`을 돌려준다. 다른 실패는 throw 한다.
1
+ # @infoteam/account-web
2
+
3
+ 인포팀 계정(IdP) 로그인을 웹 앱에 붙인다. 특정 프레임워크에 의존하지 않는다. React 앱이라면 [`@infoteam/account-react`](../react)를 쓴다.
4
+
5
+ ## 설치
6
+
7
+ ```bash
8
+ pnpm add @infoteam/account-web zod
9
+ ```
10
+
11
+ ## 사용
12
+
13
+ ```ts
14
+ import { createAccountClient } from '@infoteam/account-web';
15
+
16
+ // 라우터보다 먼저 만든다. callback 으로 열린 페이지면 여기서 주소를 로그인 전 위치로 바꾼다
17
+ const account = createAccountClient({ issuer: 'production', clientId, api: apiUrl });
18
+
19
+ await account.ready(); // callback 이면 백엔드 로그인을 마치고, 아니면 세션을 복구한다
20
+ account.store.subscribe((state) => render(state));
21
+
22
+ // 로그인 버튼
23
+ await account.login({ returnTo: location.pathname });
24
+
25
+ // 라우터 guard
26
+ await account.requireAuth({ returnTo: nextUrl });
27
+
28
+ // API 요청. 401 이면 토큰을 갱신한 뒤 다시 보낸다
29
+ await account.fetch(`${apiUrl}/me`);
30
+ ```
31
+
32
+ - 상태는 zustand의 vanilla store(`account.store`)에 있으므로, 어느 프레임워크에서든 구독할 수 있다.
33
+ - API 요청에는 `account.fetch`, `@infoteam/account-web/openapi-fetch`, `@infoteam/account-web/axios` 중 하나를 쓴다.
34
+ - 옵션, guard, 에러 코드, 로그아웃은 React와 같다. [`account-react` README](../react/README.md#사용)를 참고한다.
35
+
36
+ ## 백엔드 형식이 다를 때
37
+
38
+ `api`는 백엔드가 [세션 프로토콜](../../README.md#세션-프로토콜)을 구현했다고 가정한다. 형식이 다르면 `api` 대신 `session`에 백엔드 호출을 직접
39
+ 구현해서 넘긴다. 둘 중 하나만 줄 수 있다.
40
+
41
+ ```ts
42
+ import { createAccountClient, type Session } from '@infoteam/account-web';
43
+
44
+ const session: Session = {
45
+ async start(credential) {
46
+ if ('ticket' in credential) throw new Error('this backend does not reject logins');
47
+ const res = await fetch(`${apiUrl}/oauth/callback`, {
48
+ method: 'POST',
49
+ credentials: 'include',
50
+ headers: { 'content-type': 'application/json' },
51
+ body: JSON.stringify({
52
+ code: credential.code,
53
+ verifier: credential.codeVerifier,
54
+ redirectUri: credential.redirectUri,
55
+ nonce: credential.nonce,
56
+ }),
57
+ });
58
+ if (!res.ok) throw new Error(`login failed: ${res.status}`);
59
+ const { token } = await res.json();
60
+ return { tokens: { accessToken: token } };
61
+ },
62
+ async refresh() {
63
+ const res = await fetch(`${apiUrl}/token`, { method: 'POST', credentials: 'include' });
64
+ if (res.status === 401) return null; // 세션 없음
65
+ if (!res.ok) throw new Error(`refresh failed: ${res.status}`);
66
+ return { accessToken: (await res.json()).token };
67
+ },
68
+ async end() {
69
+ await fetch(`${apiUrl}/signout`, { method: 'POST', credentials: 'include' });
70
+ },
71
+ };
72
+
73
+ const account = createAccountClient({ issuer: 'production', clientId, session });
74
+ ```
75
+
76
+ - `start`는 callback으로 받은 code, PKCE verifier, `redirectUri`, `nonce`를 받는다. 백엔드는 code를 교환할 때 이 `redirectUri`를 그대로 쓰고, id_token의 `nonce`를 확인해야 한다.
77
+ - 로그인 전에 추가 입력을 받으려면 `start`가 `{ rejected: { error, ticket } }`를 돌려준다. 그러면 `retryLogin(body)`가 `start({ ticket }, body)`로 다시 부른다.
78
+ - `refresh`는 세션이 없으면 `null`을 돌려준다. 다른 실패는 throw 한다.
package/dist/axios.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as AccountClient } from "./create-account-client-MB6AawN9.js";
1
+ import { t as AccountClient } from "./create-account-client-B8wwVkQt.js";
2
2
  import { AxiosInstance } from "axios";
3
3
  //#region src/adapters/axios.d.ts
4
4
  /** 401이면 refresh 한 뒤 한 번 다시 시도한다. 돌려주는 함수를 부르면 interceptor를 제거한다. */
@@ -62,11 +62,11 @@ declare const AccountClientOptionsSchema: z.ZodMiniObject<{
62
62
  redirectUri: z.ZodMiniOptional<z.ZodMiniString<string>>;
63
63
  scopes: z.ZodMiniOptional<z.ZodMiniArray<z.ZodMiniEnum<{
64
64
  email: "email";
65
- profile: "profile";
66
65
  name: "name";
66
+ profile: "profile";
67
67
  picture: "picture";
68
- phone_number: "phone_number";
69
68
  student_id: "student_id";
69
+ phone_number: "phone_number";
70
70
  }>>>;
71
71
  silentLogin: z.ZodMiniOptional<z.ZodMiniBoolean<boolean>>;
72
72
  fetch: z.ZodMiniOptional<z.ZodMiniCustom<typeof fetch, typeof fetch>>;
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { a as createAccountClient, c as LoginCredential, d as SessionRejection, f as SessionTokens, i as RequireAuthOptions, l as Session, m as AccountStatus, n as LoginOptions, o as AccountClientOptions, p as AccountState, r as LogoutOptions, s as AccountClientOptionsSchema, t as AccountClient, u as SessionPaths } from "./create-account-client-MB6AawN9.js";
1
+ import { a as createAccountClient, c as LoginCredential, d as SessionRejection, f as SessionTokens, i as RequireAuthOptions, l as Session, m as AccountStatus, n as LoginOptions, o as AccountClientOptions, p as AccountState, r as LogoutOptions, s as AccountClientOptionsSchema, t as AccountClient, u as SessionPaths } from "./create-account-client-B8wwVkQt.js";
2
2
  import { AccountError, AccountErrorCode, ClientScope, Environment, IssuerInput, Prompt } from "@infoteam/account-core";
3
3
  export { type AccountClient, type AccountClientOptions, AccountClientOptionsSchema, AccountError, type AccountErrorCode, type AccountState, type AccountStatus, type ClientScope, type Environment, type IssuerInput, type LoginCredential, type LoginOptions, type LogoutOptions, type Prompt, type RequireAuthOptions, type Session, type SessionPaths, type SessionRejection, type SessionTokens, createAccountClient };
@@ -1,4 +1,4 @@
1
- import { t as AccountClient } from "./create-account-client-MB6AawN9.js";
1
+ import { t as AccountClient } from "./create-account-client-B8wwVkQt.js";
2
2
  import { Middleware } from "openapi-fetch";
3
3
  //#region src/adapters/openapi-fetch.d.ts
4
4
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@infoteam/account-web",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Browser client for the Infoteam account IdP: sign-in redirect, callback handling and service sessions",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -23,7 +23,7 @@
23
23
  "./package.json": "./package.json"
24
24
  },
25
25
  "dependencies": {
26
- "@infoteam/account-core": "^0.6.0",
26
+ "@infoteam/account-core": "^0.7.0",
27
27
  "es-toolkit": "^1.52.0",
28
28
  "zustand": "^5.0.15"
29
29
  },