@natsuneko-laboratory/catalyst-sdk 0.7.2 → 1.0.0-alpha.10

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/README.md CHANGED
@@ -10,10 +10,10 @@ $ npm install @natsuneko-laboratory/catalyst-sdk --save
10
10
 
11
11
  ## Usage
12
12
 
13
+ ### Authentication (OAuth 2.0 + PKCE)
14
+
13
15
  ```typescript
14
- // authentication
15
16
  import { CatalystTS, PKCE } from "@natsuneko-laboratory/catalyst-sdk";
16
- import { v4 } from "uuid";
17
17
 
18
18
  const API_KEY = {
19
19
  clientId: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
@@ -24,32 +24,99 @@ const API_KEY = {
24
24
  const client = new CatalystTS({
25
25
  clientId: API_KEY.clientId,
26
26
  clientSecret: API_KEY.clientSecret,
27
- accessToken: "",
28
- refreshToken: "",
29
27
  });
28
+
29
+ // 1. redirect the user to the authorization URL
30
30
  const pkce = await PKCE.create();
31
- const state = v4();
32
- const redirect = client.oauth.getAuthorizeURL(API_KEY.redirectUri, pkce, state);
33
-
34
- // redirected to `redirectUri`
35
- const searchParams = new URLSearchParams(window.location.search);
36
- const code = searchParams.get("code");
37
- const returnedState = searchParams.get("state");
38
-
39
- if (code && returnedState === state) {
40
- const { accessToken, refreshToken } = await client.oauth.getAccessTokenByCode(
41
- code,
42
- API_KEY.redirectUri,
43
- pkce,
44
- );
45
-
46
- console.log("accessToken:", accessToken);
47
- console.log("refreshToken:", refreshToken);
48
- }
31
+ const state = crypto.randomUUID();
32
+ const url = client.oauth.getAuthorizeURL(API_KEY.redirectUri, pkce, state);
33
+
34
+ // 2. after the user is redirected back to `redirectUri`, extract the
35
+ // authorization code (state and redirect URI are verified for you,
36
+ // throws OAuthError on failure)
37
+ const callbackUrl = new URL(window.location.href);
38
+ const code = client.oauth.getAuthorizationCode(callbackUrl, state, API_KEY.redirectUri);
39
+
40
+ // 3. exchange the code for tokens and attach them to the client
41
+ const token = await client.oauth.getAccessTokenByCode(code, API_KEY.redirectUri, pkce);
42
+ client.setCredential(token.accessToken, token.refreshToken);
43
+ ```
49
44
 
50
- // call user specified APIs
51
- const me = await client.egeria.me();
45
+ If you already have tokens (e.g. restored from storage), pass them directly:
46
+
47
+ ```typescript
48
+ const client = new CatalystTS({
49
+ clientId: API_KEY.clientId,
50
+ clientSecret: API_KEY.clientSecret,
51
+ accessToken: storedAccessToken,
52
+ refreshToken: storedRefreshToken,
53
+ });
54
+ ```
55
+
56
+ ### Calling APIs
57
+
58
+ API clients are generated from the OpenAPI schema by [@hey-api/openapi-ts](https://heyapi.dev/) and grouped by service:
59
+
60
+ ```typescript
61
+ // GET /egeria/v1/me
62
+ const { data: me } = await client.egeria.egeria.v1.me.get();
52
63
  console.log({ me });
64
+
65
+ // GET /epiclese/v1/authors
66
+ const { data: authors } = await client.epiclese.epiclese.v1.authors.get();
67
+ ```
68
+
69
+ Available services: `client.catalyst`, `client.egeria`, `client.epiclese`, `client.featureFlags`, `client.media`, `client.steambird`.
70
+
71
+ ### Automatic token refresh
72
+
73
+ When a request fails with `401 Unauthorized` and a refresh token is set, the SDK automatically refreshes the access token and retries the request (up to 5 times). Concurrent requests share a single refresh operation.
74
+
75
+ You can also refresh manually and read back the current tokens for persistence:
76
+
77
+ ```typescript
78
+ const token = await client.refresh();
79
+
80
+ console.log(client.accessToken);
81
+ console.log(client.refreshToken);
82
+ ```
83
+
84
+ ### Interceptors
85
+
86
+ Requests, responses, and errors can be intercepted. A `LoggingInterceptor` is provided out of the box, and you can implement the `Interceptor` interface yourself:
87
+
88
+ ```typescript
89
+ import { CatalystTS, LoggingInterceptor } from "@natsuneko-laboratory/catalyst-sdk";
90
+ import type { Interceptor } from "@natsuneko-laboratory/catalyst-sdk";
91
+
92
+ const myInterceptor: Interceptor = {
93
+ onRequest: (request) => {
94
+ request.headers.set("X-Custom-Header", "value");
95
+ return request;
96
+ },
97
+ };
98
+
99
+ const client = new CatalystTS({
100
+ clientId: API_KEY.clientId,
101
+ clientSecret: API_KEY.clientSecret,
102
+ interceptors: [new LoggingInterceptor(), myInterceptor],
103
+ });
104
+ ```
105
+
106
+ ### Error handling
107
+
108
+ OAuth operations throw `OAuthError`, which carries a `kind` (`authorizationRequestFailed` | `invalidAuthorizationResponse` | `invalidTokenResponse`) and optional error details from the server:
109
+
110
+ ```typescript
111
+ import { OAuthError } from "@natsuneko-laboratory/catalyst-sdk";
112
+
113
+ try {
114
+ const code = client.oauth.getAuthorizationCode(callbackUrl, state, API_KEY.redirectUri);
115
+ } catch (err) {
116
+ if (err instanceof OAuthError) {
117
+ console.error(err.kind, err.info);
118
+ }
119
+ }
53
120
  ```
54
121
 
55
122
  ## License