@book000/pixivts-db-mysql 0.56.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/README.md +118 -0
- package/package.json +63 -0
package/README.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# @book000/pixivts-db-mysql
|
|
2
|
+
|
|
3
|
+
MySQL response recorder for [`@book000/pixivts`](https://www.npmjs.com/package/@book000/pixivts).
|
|
4
|
+
|
|
5
|
+
Persists every pixiv API response to a MySQL database using [Drizzle ORM](https://orm.drizzle.team/).
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```shell
|
|
10
|
+
npm install @book000/pixivts-db-mysql
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @book000/pixivts-db-mysql
|
|
13
|
+
# or
|
|
14
|
+
yarn add @book000/pixivts-db-mysql
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Peer dependency**: `@book000/pixivts`
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { PixivClient } from '@book000/pixivts'
|
|
23
|
+
import { createResponseRecorder } from '@book000/pixivts-db-mysql'
|
|
24
|
+
|
|
25
|
+
// Create the recorder (connects to MySQL and optionally bootstraps the schema)
|
|
26
|
+
const { interceptor, db, close } = await createResponseRecorder({
|
|
27
|
+
host: 'localhost',
|
|
28
|
+
port: 3306,
|
|
29
|
+
user: 'pixiv',
|
|
30
|
+
password: 'secret',
|
|
31
|
+
database: 'pixivts',
|
|
32
|
+
bootstrap: true, // run CREATE TABLE IF NOT EXISTS on first use
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
// Pass the interceptor to PixivClient
|
|
36
|
+
const client = await PixivClient.of(process.env.PIXIV_REFRESH_TOKEN!, {
|
|
37
|
+
onResponse: interceptor,
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
// Every API call is now recorded to MySQL automatically
|
|
41
|
+
const result = await client.illusts.detail({ illustId: 12345 })
|
|
42
|
+
|
|
43
|
+
// Close the pool when done
|
|
44
|
+
await close()
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Connection Options
|
|
48
|
+
|
|
49
|
+
Connection options can be passed explicitly or fall back to environment variables:
|
|
50
|
+
|
|
51
|
+
| Option | Env var | Default |
|
|
52
|
+
|---|---|---|
|
|
53
|
+
| `host` | `RESPONSE_DB_HOSTNAME` | `localhost` |
|
|
54
|
+
| `port` | `RESPONSE_DB_PORT` | `3306` |
|
|
55
|
+
| `user` | `RESPONSE_DB_USERNAME` | — |
|
|
56
|
+
| `password` | `RESPONSE_DB_PASSWORD` | — |
|
|
57
|
+
| `database` | `RESPONSE_DB_DATABASE` | — |
|
|
58
|
+
| `bootstrap` | — | `false` |
|
|
59
|
+
|
|
60
|
+
### Query Helpers
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import {
|
|
64
|
+
createResponseRecorder,
|
|
65
|
+
getResponses,
|
|
66
|
+
getResponseCount,
|
|
67
|
+
getEndpoints,
|
|
68
|
+
} from '@book000/pixivts-db-mysql'
|
|
69
|
+
|
|
70
|
+
const { db, close } = await createResponseRecorder({ bootstrap: true })
|
|
71
|
+
|
|
72
|
+
// Get responses with pagination (last 90 days)
|
|
73
|
+
const rows = await getResponses(db, { endpoint: '/v1/illust/detail' }, { page: 1, limit: 50 })
|
|
74
|
+
|
|
75
|
+
// Count matching records
|
|
76
|
+
const count = await getResponseCount(db, { statusCode: 200 })
|
|
77
|
+
|
|
78
|
+
// List all unique endpoints with counts
|
|
79
|
+
const endpoints = await getEndpoints(db)
|
|
80
|
+
// [{ method: 'GET', endpoint: '/v1/illust/detail', statusCode: 200, count: 142 }, ...]
|
|
81
|
+
|
|
82
|
+
await close()
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Schema
|
|
86
|
+
|
|
87
|
+
The `responses` table stores one row per API call:
|
|
88
|
+
|
|
89
|
+
| Column | Type | Nullable | Description |
|
|
90
|
+
|---|---|---|---|
|
|
91
|
+
| `id` | `INT AUTO_INCREMENT` | NO | Primary key |
|
|
92
|
+
| `method` | `VARCHAR(10)` | NO | HTTP method |
|
|
93
|
+
| `endpoint` | `VARCHAR(255)` | NO | API path |
|
|
94
|
+
| `url` | `TEXT` | YES | Full request URL |
|
|
95
|
+
| `url_hash` | `VARCHAR(255)` | NO | SHA-256 hex of URL (for deduplication) |
|
|
96
|
+
| `request_headers` | `LONGTEXT` | YES | Serialised request headers (JSON) |
|
|
97
|
+
| `request_body` | `LONGTEXT` | YES | Request body (null for GET) |
|
|
98
|
+
| `response_type` | `VARCHAR(10)` | NO | Response content type (`"JSON"` or `"TEXT"`) |
|
|
99
|
+
| `status_code` | `INT` | NO | HTTP status code |
|
|
100
|
+
| `response_headers` | `LONGTEXT` | YES | Serialised response headers (JSON) |
|
|
101
|
+
| `response_body` | `LONGTEXT` | NO | Raw response body |
|
|
102
|
+
| `created_at` | `DATETIME(3)` | NO | Timestamp (millisecond precision) |
|
|
103
|
+
|
|
104
|
+
Duplicate rows (same method + endpoint + statusCode + createdAt + urlHash) are silently ignored via `ON DUPLICATE KEY UPDATE`.
|
|
105
|
+
|
|
106
|
+
## Database Migration
|
|
107
|
+
|
|
108
|
+
To generate a Drizzle migration file, run from the `packages/db-mysql` directory:
|
|
109
|
+
|
|
110
|
+
```shell
|
|
111
|
+
pnpm drizzle-kit generate
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Alternatively, set `bootstrap: true` in `createResponseRecorder()` to run `CREATE TABLE IF NOT EXISTS` automatically.
|
|
115
|
+
|
|
116
|
+
## License
|
|
117
|
+
|
|
118
|
+
This project is licensed under the [MIT License](../../LICENSE)
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@book000/pixivts-db-mysql",
|
|
3
|
+
"version": "0.56.0",
|
|
4
|
+
"description": "MySQL response recorder for @book000/pixivts (Drizzle ORM)",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"pixiv",
|
|
7
|
+
"typescript",
|
|
8
|
+
"mysql",
|
|
9
|
+
"drizzle"
|
|
10
|
+
],
|
|
11
|
+
"homepage": "https://www.npmjs.com/package/@book000/pixivts-db-mysql",
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/book000/pixivts/issues"
|
|
14
|
+
},
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"author": "Tomachi <tomachi@tomacheese.com>",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/book000/pixivts.git",
|
|
20
|
+
"directory": "packages/db-mysql"
|
|
21
|
+
},
|
|
22
|
+
"type": "module",
|
|
23
|
+
"files": [
|
|
24
|
+
"dist"
|
|
25
|
+
],
|
|
26
|
+
"main": "./dist/index.cjs",
|
|
27
|
+
"module": "./dist/index.js",
|
|
28
|
+
"types": "./dist/index.d.ts",
|
|
29
|
+
"exports": {
|
|
30
|
+
".": {
|
|
31
|
+
"import": {
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"default": "./dist/index.js"
|
|
34
|
+
},
|
|
35
|
+
"require": {
|
|
36
|
+
"types": "./dist/index.d.cts",
|
|
37
|
+
"default": "./dist/index.cjs"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"drizzle-orm": "0.38.4",
|
|
43
|
+
"mysql2": "3.22.5"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"@book000/pixivts": "workspace:*"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "24.13.2",
|
|
50
|
+
"@vitest/coverage-v8": "3.2.4",
|
|
51
|
+
"drizzle-kit": "0.29.1",
|
|
52
|
+
"tsup": "8.5.0",
|
|
53
|
+
"typescript": "6.0.3",
|
|
54
|
+
"vitest": "3.2.4"
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsup",
|
|
58
|
+
"clean": "rimraf dist",
|
|
59
|
+
"lint": "tsc --noEmit",
|
|
60
|
+
"fix": "echo 'no fix needed'",
|
|
61
|
+
"test:integration": "vitest run --config vitest.integration.config.ts"
|
|
62
|
+
}
|
|
63
|
+
}
|