@brigadasos/nadeshiko-sdk 2.0.7-internal.5cdd62f → 2.1.0-internal

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
@@ -1,20 +1,11 @@
1
1
  # Nadeshiko SDK
2
2
 
3
- TypeScript SDK for the [Nadeshiko API](https://nadeshiko.co).
3
+ TypeScript SDK for the [Nadeshiko API](https://nadeshiko.co). Full API reference at [nadeshiko.co/docs/api](https://nadeshiko.co/docs/api/index.html).
4
4
 
5
5
  ## Install
6
6
 
7
7
  ```bash
8
- # npm / pnpm / bun
9
8
  npm add @brigadasos/nadeshiko-sdk
10
- pnpm add @brigadasos/nadeshiko-sdk
11
- bun add @brigadasos/nadeshiko-sdk
12
- ```
13
-
14
- Install the internal build (includes session-authenticated endpoints) via the `internal` dist-tag:
15
-
16
- ```bash
17
- bun add @brigadasos/nadeshiko-sdk@internal
18
9
  ```
19
10
 
20
11
  ## Quick start
@@ -26,113 +17,115 @@ const client = createNadeshikoClient({
26
17
  apiKey: process.env.NADESHIKO_API_KEY!,
27
18
  });
28
19
 
29
- const { data } = await client.search({ body: { query: { search: '彼女' } } });
20
+ const data = await client.search({ query: { search: '彼女' } });
30
21
  console.log(data.segments);
22
+ // [
23
+ // {
24
+ // segmentPublicId: 'xK9mP2nQwR4t',
25
+ // mediaPublicId: 'steins-gate',
26
+ // episode: 1,
27
+ // startTimeMs: 62340,
28
+ // endTimeMs: 65180,
29
+ // textJa: { content: '彼女に会いたい' },
30
+ // textEn: { content: 'I want to see her' },
31
+ // urls: {
32
+ // imageUrl: 'https://...',
33
+ // audioUrl: 'https://...',
34
+ // videoUrl: 'https://...',
35
+ // },
36
+ // },
37
+ // // ...
38
+ // ]
31
39
  ```
32
40
 
33
- Errors throw by default. Wrap calls you want to handle explicitly in `try/catch`.
34
-
35
41
  ## Authentication
36
42
 
37
- ### API key (server-to-server)
38
-
39
- Use an API key for public endpoints. The key is sent as `Authorization: Bearer <apiKey>`.
43
+ Pass your API key to `createNadeshikoClient`. It is sent as `Authorization: Bearer <apiKey>` on every request.
40
44
 
41
45
  ```typescript
42
- import { createNadeshikoClient } from '@brigadasos/nadeshiko-sdk';
43
-
44
46
  const client = createNadeshikoClient({
45
47
  apiKey: process.env.NADESHIKO_API_KEY!,
46
- baseURL: 'PRODUCTION', // 'LOCAL' | 'DEVELOPMENT' | 'PRODUCTION' | custom URL
47
- });
48
- ```
49
-
50
- ### Session token (user-authenticated endpoints, internal build only)
51
-
52
- The public package exposes only API-key-capable endpoints.
53
- For session-authenticated endpoints (`/v1/user/*`, `/v1/collections/*`), use the internal build.
54
-
55
- Pass a `sessionToken` getter that returns the value of the `nadeshiko.session_token` cookie — called fresh on every request.
56
-
57
- **Nuxt / Nitro server routes:**
58
-
59
- ```typescript
60
- // server/utils/nadeshiko.ts
61
- import { createNadeshikoClient } from '@brigadasos/nadeshiko-sdk';
62
- import type { H3Event } from 'h3';
63
-
64
- export function useNadeshikoClient(event: H3Event) {
65
- return createNadeshikoClient({
66
- sessionToken: () => getCookie(event, 'nadeshiko.session_token'),
67
- });
68
- }
69
- ```
70
-
71
- ```typescript
72
- // server/api/preferences.get.ts
73
- export default defineEventHandler(async (event) => {
74
- const client = useNadeshikoClient(event);
75
- return client.getUserPreferences();
48
+ baseURL: 'PRODUCTION'
76
49
  });
77
50
  ```
78
51
 
79
- **Browser note:** if your session cookie is `HttpOnly`, use same-origin proxy routes and let the browser attach cookies automatically.
52
+ ## Available endpoints
53
+
54
+ ### Search
55
+ | Method | Description |
56
+ |---|---|
57
+ | `search(params?)` | Search segments by query, with filters and sorting |
58
+ | `getSearchStats(params?)` | Category counts and media list for filter UI |
59
+ | `searchWords(params)` | Look up multiple words and get match counts per media |
60
+ | `searchMedia(params)` | Find media by name (autocomplete) |
61
+
62
+ ### Stats
63
+ | Method | Description |
64
+ |---|---|
65
+ | `getStatsOverview()` | Corpus-wide stats: segment count, media count, coverage tiers |
66
+
67
+ ### Media
68
+ | Method | Description |
69
+ |---|---|
70
+ | `listMedia(params?)` | Browse the media catalog |
71
+ | `getMedia(id)` | Get a single media entry by public ID |
72
+ | `listEpisodes(params)` | List episodes for a media entry |
73
+ | `getEpisode(params)` | Get a single episode |
74
+ | `getSegment(id)` | Get a single segment by UUID |
75
+ | `getSegmentContext(id)` | Get segments surrounding a given segment |
76
+
77
+ ### User
78
+ | Method | Description |
79
+ |---|---|
80
+ | `getMe()` | Current user profile and API quota |
81
+ | `listUserActivity(params?)` | Activity history (searches, plays, exports) |
82
+ | `getUserActivityHeatmap(params?)` | Daily activity counts for a heatmap |
83
+ | `getUserActivityStats(params?)` | Aggregate stats over a date range |
84
+ | `listExcludedMedia()` | Media hidden from search results |
85
+ | `addExcludedMedia(params)` | Hide a media entry from search results |
86
+ | `removeExcludedMedia(id)` | Un-hide a media entry |
87
+
88
+ ### Collections
89
+ | Method | Description |
90
+ |---|---|
91
+ | `listCollections(params?)` | List your saved collections |
92
+ | `createCollection(params)` | Create a new collection |
93
+ | `getCollection(id)` | Get a collection and its segments |
94
+ | `deleteCollection(id)` | Delete a collection |
95
+ | `addSegmentToCollection(params)` | Add a segment to a collection |
96
+ | `searchCollectionSegments(params)` | Search within a collection |
97
+ | `removeSegmentFromCollection(params)` | Remove a segment from a collection |
80
98
 
81
99
  ## Error handling
82
100
 
83
- Errors throw a `NadeshikoError` a proper `Error` subclass with all RFC 7807 Problem Details fields available directly.
101
+ Errors throw a `NadeshikoError`. A proper `Error` subclass with all RFC 7807 Problem Details fields.
84
102
 
85
103
  ```typescript
86
- import { createNadeshikoClient, NadeshikoError } from '@brigadasos/nadeshiko-sdk';
87
-
88
- const client = createNadeshikoClient({ apiKey: process.env.NADESHIKO_API_KEY! });
104
+ import { NadeshikoError } from '@brigadasos/nadeshiko-sdk';
89
105
 
90
106
  try {
91
- const { data } = await client.search({ body: { query: { search: '食べる' } } });
107
+ const data = await client.search({ query: { search: '食べる' } });
92
108
  console.log(data.segments);
93
109
  } catch (err) {
94
110
  if (err instanceof NadeshikoError) {
95
111
  switch (err.code) {
96
- // 400 — Bad Request
97
112
  case 'VALIDATION_FAILED':
98
113
  console.error('Validation failed:', err.detail);
99
114
  for (const [field, msg] of Object.entries(err.errors ?? {})) {
100
115
  console.error(` ${field}: ${msg}`);
101
116
  }
102
117
  break;
103
- case 'INVALID_JSON':
104
- case 'INVALID_REQUEST':
105
- console.error('Bad request:', err.detail);
106
- break;
107
-
108
- // 401 — Unauthorized
109
118
  case 'AUTH_CREDENTIALS_REQUIRED':
110
- console.error('Missing API key');
111
- break;
112
119
  case 'AUTH_CREDENTIALS_INVALID':
113
- console.error('API key is invalid');
114
- break;
115
- case 'AUTH_CREDENTIALS_EXPIRED':
116
- console.error('Token has expired, re-authenticate');
120
+ console.error('Authentication failed:', err.detail);
117
121
  break;
118
-
119
- // 403 — Forbidden
120
- case 'ACCESS_DENIED':
121
- case 'INSUFFICIENT_PERMISSIONS':
122
- console.error('Access denied');
123
- break;
124
-
125
- // 429 — Too Many Requests
126
122
  case 'RATE_LIMIT_EXCEEDED':
127
- console.error('Rate limit hit, slow down');
123
+ console.error('Rate limited slow down');
128
124
  break;
129
125
  case 'QUOTA_EXCEEDED':
130
126
  console.error('Monthly quota exhausted');
131
127
  break;
132
-
133
- // 500 — Internal Server Error
134
128
  case 'INTERNAL_SERVER_EXCEPTION':
135
- // err.traceId is the instance field — include when reporting issues
136
129
  console.error('Server error, trace ID:', err.traceId);
137
130
  break;
138
131
  }
@@ -148,20 +141,20 @@ try {
148
141
  | `title` | `string` | Short summary |
149
142
  | `detail` | `string` | Human-readable explanation |
150
143
  | `status` | `number` | HTTP status code |
151
- | `traceId` | `string \| undefined` | Trace ID for this error — include when reporting issues |
144
+ | `traceId` | `string \| undefined` | Trace ID — include when reporting issues |
152
145
  | `errors` | `Record<string, string> \| undefined` | Per-field messages (`VALIDATION_FAILED` only) |
153
146
 
154
147
  ### Opt out of throwing per-call
155
148
 
156
- If you need the old `{ data, error }` return shape for a specific call, pass `throwOnError: false`:
149
+ Pass `throwOnError: false` to get a `{ data, error }` result instead of throwing:
157
150
 
158
151
  ```typescript
159
152
  const result = await client.search({
160
153
  throwOnError: false,
161
- body: { query: { search: '猫' } },
154
+ query: { search: '猫' },
162
155
  });
163
156
 
164
- if (result.error) {
157
+ if ('error' in result) {
165
158
  console.error(result.error);
166
159
  } else {
167
160
  console.log(result.data.segments);
@@ -170,7 +163,7 @@ if (result.error) {
170
163
 
171
164
  ## Retry and timeout
172
165
 
173
- The client retries automatically on network errors and `408 / 429 / 500 / 502 / 503 / 504` responses. `429` responses with a `Retry-After` header are respected. Configure via `retryOptions`:
166
+ The client retries automatically on network errors and `408 / 429 / 500 / 502 / 503 / 504` responses. `429` responses with a `Retry-After` header are respected.
174
167
 
175
168
  ```typescript
176
169
  const client = createNadeshikoClient({
@@ -186,33 +179,38 @@ const client = createNadeshikoClient({
186
179
 
187
180
  ## Pagination
188
181
 
189
- Use `paginate()` to iterate through all pages without manual cursor tracking:
182
+ Paginated endpoints have a `.paginate()` method that returns an async iterator over individual items:
190
183
 
191
184
  ```typescript
192
- import { createNadeshikoClient, paginate } from '@brigadasos/nadeshiko-sdk';
193
-
194
- const client = createNadeshikoClient({ apiKey: process.env.NADESHIKO_API_KEY! });
195
-
196
- for await (const segment of paginate(
197
- (opts) => client.search(opts),
198
- { body: { query: { search: '猫' } } },
199
- (data) => ({ items: data.segments, pagination: data.pagination }),
200
- )) {
185
+ for await (const segment of client.search.paginate({
186
+ query: { search: '猫' },
187
+ })) {
201
188
  console.log(segment.textJa.content);
202
189
  }
190
+
191
+ for await (const media of client.listMedia.paginate()) {
192
+ console.log(media.nameEn);
193
+ }
203
194
  ```
204
195
 
205
- `paginate()` works with any endpoint that returns `{ pagination: { hasMore, cursor } }`:
196
+ For manual page-by-page control, use the `cursor` field:
206
197
 
207
198
  ```typescript
208
- // Browse all media
209
- for await (const media of paginate(
210
- (opts) => client.listMedia(opts),
211
- {},
212
- (data) => ({ items: data.media, pagination: data.pagination }),
213
- )) {
214
- console.log(media.nameEn);
215
- }
199
+ let cursor: string | undefined;
200
+
201
+ do {
202
+ const data = await client.search({
203
+ query: { search: '犬' },
204
+ take: 10,
205
+ cursor,
206
+ });
207
+
208
+ for (const segment of data.segments) {
209
+ console.log(segment.textJa.content);
210
+ }
211
+
212
+ cursor = data.pagination.hasMore ? data.pagination.cursor : undefined;
213
+ } while (cursor);
216
214
  ```
217
215
 
218
216
  See [`examples/examples.ts`](examples/examples.ts) for more usage patterns.
package/dist/errors.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import type { Error400, Error401, Error403, Error429, Error500, Error409, Error404 } from './types.gen';
2
2
  /** Union of all known API error codes. */
3
- export type NadeshikoErrorCode = Error400['code'] | Error401['code'] | Error403['code'] | Error429['code'] | Error500['code'] | Error409['code'] | Error404['code'];
3
+ export type NadeshikoErrorCode = Error400['code'] | Error401['code'] | Error403['code'] | Error429['code'] | Error500['code'] | Error409['code'] | Error404['code'] | 'UNKNOWN_ERROR';
4
4
  export interface NadeshikoProblemDetails {
5
5
  code: NadeshikoErrorCode;
6
6
  title: string;
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../generated/internal/errors.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAExG,0CAA0C;AAC1C,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC;AAEpK,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,kBAAkB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,iFAAiF;IACjF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAE7B,IAAI,EAAE,uBAAuB;CAW1C"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../generated/internal/errors.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAExG,0CAA0C;AAC1C,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,eAAe,CAAC;AAEtL,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,kBAAkB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,kFAAkF;IAClF,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAE,kBAAkB,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,iFAAiF;IACjF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAE7B,IAAI,EAAE,uBAAuB;CAW1C"}