+44
README.md
+44
README.md
···
1
+
# ANProto over ATProto
2
+
3
+
This project demonstrates ANProto messaging on top of the AT Protocol (Bluesky/ATProto) with OAuth auth. It is designed to be clear, concise, and "LLM-friendly" (easy for AI assistants to parse and understand context).
4
+
5
+
## Purpose
6
+
7
+
To demonstrate a secure, production-ready (conceptually) OAuth flow using `@atproto/oauth-client-node`, including:
8
+
- **Handle Resolution**: Converting `user.bsky.social` to a DID.
9
+
- **Session Management**: Persisting sessions securely using a database.
10
+
- **Scopes**: Requesting appropriate permissions (Standard vs. Transition).
11
+
- **Token Management**: Handling access and refresh tokens automatically.
12
+
13
+
## Quick Start
14
+
15
+
1. **Install Dependencies**:
16
+
```bash
17
+
npm install
18
+
```
19
+
2. **Run the Server**:
20
+
```bash
21
+
npm run dev
22
+
```
23
+
3. **Open**: Visit `http://localhost:3000`
24
+
25
+
## Documentation
26
+
27
+
- **[Architecture Overview](./docs/ARCHITECTURE.md)**: How the components (Client, DB, Storage, Express) fit together.
28
+
- **[Understanding Scopes](./docs/SCOPES.md)**: Which permissions to ask for and why.
29
+
- **[Handles vs. DIDs](./docs/HANDLES_AND_DIDS.md)**: How user identity works in ATProto.
30
+
- **[Setup & Configuration](./docs/SETUP.md)**: Configuring the client metadata for localhost vs. production.
31
+
32
+
## Key Files
33
+
34
+
- `src/index.ts`: The web server and route handlers.
35
+
- `src/client.ts`: Configuration of the OAuth client.
36
+
- `src/storage.ts`: Interface between the OAuth client and the database.
37
+
- `src/db.ts`: SQLite database connection.
38
+
39
+
## "Do's and Don'ts"
40
+
41
+
- **DO** use DIDs (`did:plc:...`) as the primary user key in your database, not handles. Handles are mutable.
42
+
- **DO** persist the `state` and `session` data securely.
43
+
- **DON'T** request `atproto` (full access) scope unless you absolutely need it. Prefer granular scopes if available (though currently `atproto` or `transition:generic` are common).
44
+
- **DON'T** hardcode the PDS URL. Always resolve it from the user's DID/Handle.
+43
docs/ARCHITECTURE.md
+43
docs/ARCHITECTURE.md
···
1
+
# Architecture
2
+
3
+
This reference app follows a standard server-side OAuth flow suited for a backend (Node.js/Express) application.
4
+
5
+
## Components
6
+
7
+
1. **Express Server (`src/index.ts`)**
8
+
- Host web endpoints (`/`, `/login`, `/oauth/callback`).
9
+
- Manages the browser session (cookie-based) using `iron-session`.
10
+
- NOTE: The browser session is *separate* from the OAuth session. The browser session just remembers "Who is logged in here?" (by storing the DID).
11
+
12
+
2. **OAuth Client (`src/client.ts`)**
13
+
- Instance of `NodeOAuthClient`.
14
+
- Manages the complexity of the handshake, token exchanges, and key management (DPoP).
15
+
- Uses `client-metadata` to define itself to the world (redirect URIs, etc.).
16
+
17
+
3. **Storage Adapters (`src/storage.ts`)**
18
+
- **State Store**: Temporarily stores the random `state` parameter generated during the login request to prevent CSRF.
19
+
- **Session Store**: Persists the actual Access and Refresh tokens (the "OAuth Session") mapped to the user's DID.
20
+
21
+
4. **Database (`src/db.ts`)**
22
+
- A simple SQLite database to back the Storage Adapters.
23
+
- In a real app, this would be Postgres, Redis, etc.
24
+
25
+
## The Flow
26
+
27
+
1. **Initiation**:
28
+
- User enters Handle.
29
+
- App calls `client.authorize(handle)`.
30
+
- App redirects User to the PDS (e.g., bsky.social login page).
31
+
2. **Authentication**:
32
+
- User logs in at the PDS.
33
+
- User approves the app.
34
+
3. **Callback**:
35
+
- PDS redirects User back to `/oauth/callback?code=...`.
36
+
- App calls `client.callback(params)`.
37
+
- `client` exchanges `code` for `tokens`.
38
+
- `client` saves tokens to `SessionStore`.
39
+
- App saves `session.did` to the browser cookie.
40
+
4. **Usage**:
41
+
- On subsequent requests, App reads DID from browser cookie.
42
+
- App loads OAuth tokens from `SessionStore` using the DID.
43
+
- App creates an `Agent` to make API calls.
+38
docs/HANDLES_AND_DIDS.md
+38
docs/HANDLES_AND_DIDS.md
···
1
+
# Handles vs. DIDs
2
+
3
+
In the AT Protocol, users have two identifiers: a **Handle** and a **DID** (Decentralized Identifier).
4
+
5
+
## Handle (`alice.bsky.social`)
6
+
- **Human-readable**: Looks like a domain name.
7
+
- **Mutable**: Users can change their handle at any time (e.g., `alice.bsky.social` -> `alice.com`).
8
+
- **Usage**: Used for login input, display names, and mentions.
9
+
- **NOT for Storage**: Never use the handle as the primary key in your database user table.
10
+
11
+
## DID (`did:plc:z72...`)
12
+
- **Machine-readable**: A unique string starting with `did:`.
13
+
- **Immutable**: This creates a permanent identity for the user, regardless of handle changes.
14
+
- **Usage**: Database primary keys, internal logic, and resolving data from the PDS (Personal Data Server).
15
+
16
+
## The Resolution Flow
17
+
18
+
1. **User Input**: User types `alice.bsky.social`.
19
+
2. **Resolution**: The OAuth client (or a resolver) queries the network to find the DID associated with that handle.
20
+
3. **Authentication**: The OAuth flow proceeds using the DID.
21
+
4. **Storage**: Your app stores the DID.
22
+
5. **Display**: When showing the user, you resolve the DID back to their *current* handle (or cache it and update periodically).
23
+
24
+
## Code Example
25
+
26
+
When a user logs in:
27
+
28
+
```typescript
29
+
// src/index.ts logic
30
+
const handle = req.body.handle; // "alice.bsky.social"
31
+
32
+
// The client.authorize() method handles the resolution internally!
33
+
const url = await client.authorize(handle, { ... });
34
+
35
+
// On callback, we get the session which contains the DID
36
+
const { session } = await client.callback(params);
37
+
const userDid = session.did; // "did:plc:123..."
38
+
```
+39
docs/SCOPES.md
+39
docs/SCOPES.md
···
1
+
# AT Protocol Scopes
2
+
3
+
OAuth scopes define the permissions your application requests from the user. In the AT Protocol, scopes are critical for security and user trust.
4
+
5
+
## Common Scopes
6
+
7
+
### `atproto`
8
+
- **Description**: Grants full access to the user's account (except for account deletion or migration in some contexts).
9
+
- **Use Case**: Full-featured clients (e.g., a Twitter-like app) that need to read notifications, post content, update profiles, and manage follows.
10
+
- **Risk**: High. If your token is leaked, the attacker has nearly full control.
11
+
12
+
### `transition:generic`
13
+
- **Description**: A transitional scope often used while the ecosystem moves towards more granular scopes. It provides broad access similar to `atproto` but is intended to be phased out for specific capabilities.
14
+
15
+
### `transition:chat.bsky`
16
+
- **Description**: specific to Bluesky chat capabilities.
17
+
18
+
## Granular Scopes (The Future)
19
+
20
+
The protocol is moving towards fine-grained scopes like:
21
+
- `com.atproto.repo.create`
22
+
- `com.atproto.repo.delete`
23
+
- `app.bsky.feed.post`
24
+
25
+
*Note: As of late 2024/early 2025, `atproto` is still the most commonly used scope for general apps, but you should always check the latest ATProto specs.*
26
+
27
+
## Best Practices
28
+
29
+
1. **Least Privilege**: Only request what you need. If you only need to verify identity, you might only need a hypothetical "signin" scope (or just check the DID returned without requesting API access, although typically some scope is required to get the token).
30
+
2. **Transparency**: Explain to your users why you need specific permissions.
31
+
3. **Offline Access**: If you need to perform actions when the user is not actively using the app (background jobs), ensure you request `offline_access` (often implicit or managed via refresh tokens in this library).
32
+
33
+
## In This Demo
34
+
35
+
We use:
36
+
```typescript
37
+
scope: 'atproto'
38
+
```
39
+
This is because we demonstrate fetching the user's profile and potentially other account data. For a simple "Log in with Bluesky" (identity only), you might strictly restrict usage to reading the profile and nothing else, even if the token technically allows more.
+47
docs/SETUP.md
+47
docs/SETUP.md
···
1
+
# Setup and Configuration
2
+
3
+
## Prerequisites
4
+
- Node.js v18+
5
+
- NPM
6
+
7
+
## Local Development
8
+
9
+
1. **Clone & Install**:
10
+
```bash
11
+
git clone <repo>
12
+
cd atproto-oauth-demo
13
+
npm install
14
+
```
15
+
16
+
2. **Public URL**:
17
+
OAuth requires a publicly reachable or explicitly defined callback URL. For `localhost`, strict matching is enforced.
18
+
19
+
In `src/client.ts`, the `client_id` is constructed specifically for localhost development to avoid needing a public domain:
20
+
```typescript
21
+
client_id: 'http://localhost?redirect_uri=http%3A%2F%2F127.0.0.1%3A3000%2Foauth%2Fcallback&scope=atproto'
22
+
```
23
+
*Note: This is a "Loopback Client" technique. In production, your Client ID will be your website's URL (e.g., `https://myapp.com/client-metadata.json`).*
24
+
25
+
3. **Run**:
26
+
```bash
27
+
npm run dev
28
+
```
29
+
30
+
## Production Deployment
31
+
32
+
1. **Domain**: You need a public domain (e.g., `https://myapp.com`).
33
+
2. **Metadata Endpoint**: You must serve the client metadata at a known URL (usually `https://myapp.com/.well-known/oauth-client-metadata` or similar, or just referenced by the ID).
34
+
3. **Update `src/client.ts`**:
35
+
```typescript
36
+
clientMetadata: {
37
+
client_name: 'My App',
38
+
client_id: 'https://myapp.com/client-metadata.json', // The URL where this JSON is served
39
+
client_uri: 'https://myapp.com',
40
+
redirect_uris: ['https://myapp.com/oauth/callback'],
41
+
// ...
42
+
}
43
+
```
44
+
4. **Serve Metadata**: Ensure your app actually serves this JSON at the `client_id` URL (if using URL-based IDs). The demo app serves it at `/oauth-client-metadata.json`.
45
+
46
+
5. **Environment Variables**:
47
+
Move secrets (like cookie passwords) to `.env` files.
+21
docs/WORK_ORDER.md
+21
docs/WORK_ORDER.md
···
1
+
# Work Order: ANProto Messages on Bluesky PDS
2
+
3
+
## Scope
4
+
- Store ANProto-signed messages (and blobs) in a Bluesky PDS using the existing Node OAuth backend. APDS remains frontend-only.
5
+
- Use custom collections `com.anproto.message.v1` (messages) and optional `com.anproto.blob` if we need standalone blob records.
6
+
7
+
## First Steps
8
+
- Lexicons: `com.anproto.message.v1` has `anmsg` (full ANProto message), optional `anblob`, `anhash` (base64 ANProto hash), and `blobhash` (hash of the attached blob). PDS rkey uses a base64url form of `anhash` (replace `+`→`-`, `/`→`_`, strip `=`) to satisfy record-key rules. IDs must match the collection names exactly. `com.anproto.blob` is optional if blobs stay in `anblob`.
9
+
- OAuth/scopes: Keep Node OAuth flow; request repo read/write + blob upload (`atproto` for now). Continue storing DID in cookies and tokens server-side.
10
+
- Signing/validation: Frontend APDS signs messages; send backend `{anmsg, blob?, blobMime?}`. Backend recomputes `anhash` via ANProto, converts to base64url rkey, and rejects mismatches.
11
+
- Persistence: Upload blobs via `com.atproto.repo.uploadBlob`; create `com.anproto.message.v1` records with rkey = base64url(anhash), storing `anmsg`, `anhash`, optional `anblob`, and optional `blobhash`.
12
+
- Retrieval/indexing: Add backend endpoints to fetch by rkey/anhash/DID; optional local index (DB) for search/filter; fallback to repo reads by rkey.
13
+
- Safety: Enforce size limits on content/blobs, rate-limit publish, reject tampered/duplicate/invalid signatures, log verification failures.
14
+
15
+
## Client UI (Frontend)
16
+
- Auth status: “Connect Bluesky” button; show connected DID/handle; disable publish until connected.
17
+
- Key management: Display ANProto pubkey; controls to generate/import/export (avoid leaking private key in production).
18
+
- Composer: Text area for content, optional “previous” hash, blob uploader, live display of computed hash/signature.
19
+
- Publish flow: “Sign & Save to Bluesky” runs APDS sign then POSTs to backend; show progress/errors.
20
+
- Viewer: Fetch by hash, display content, author pubkey, timestamp, previous chain, blob previews; simple search/filter if backend index exists.
21
+
- Notifications: Inline status/toasts for auth, signing, upload, and save failures.
+37
lexicons/com.anproto.message.json
+37
lexicons/com.anproto.message.json
···
1
+
{
2
+
"lexicon": 1,
3
+
"id": "com.anproto.message.v1",
4
+
"defs": {
5
+
"main": {
6
+
"type": "record",
7
+
"description": "ANProto message stored on a PDS; rkey = base64url(anhash).",
8
+
"key": "anhash-b64url",
9
+
"record": {
10
+
"type": "object",
11
+
"required": ["anmsg", "anhash"],
12
+
"properties": {
13
+
"anmsg": {
14
+
"type": "string",
15
+
"description": "Full ANProto message/signature string.",
16
+
"maxLength": 20000
17
+
},
18
+
"anhash": {
19
+
"type": "string",
20
+
"description": "ANProto hash (base64). rkey uses base64url (+->-, /->_, trim =).",
21
+
"maxLength": 256
22
+
},
23
+
"anblob": {
24
+
"type": "string",
25
+
"description": "Optional attached blob payload, base64-encoded (inline).",
26
+
"maxLength": 9000000
27
+
},
28
+
"blobhash": {
29
+
"type": "string",
30
+
"description": "Hash of the attached blob (base64).",
31
+
"maxLength": 256
32
+
}
33
+
}
34
+
}
35
+
}
36
+
}
37
+
}
+2343
package-lock.json
+2343
package-lock.json
···
1
+
{
2
+
"name": "atproto-oauth-test",
3
+
"version": "1.0.0",
4
+
"lockfileVersion": 3,
5
+
"requires": true,
6
+
"packages": {
7
+
"": {
8
+
"name": "atproto-oauth-test",
9
+
"version": "1.0.0",
10
+
"license": "ISC",
11
+
"dependencies": {
12
+
"@atproto/api": "^0.18.3",
13
+
"@atproto/oauth-client-node": "^0.3.11",
14
+
"better-sqlite3": "^12.5.0",
15
+
"express": "^5.1.0",
16
+
"iron-session": "^8.0.4"
17
+
},
18
+
"devDependencies": {
19
+
"@types/better-sqlite3": "^7.6.13",
20
+
"@types/express": "^5.0.5",
21
+
"@types/node": "^24.10.1",
22
+
"tsx": "^4.20.6",
23
+
"typescript": "^5.9.3"
24
+
}
25
+
},
26
+
"node_modules/@atproto-labs/did-resolver": {
27
+
"version": "0.2.3",
28
+
"resolved": "https://registry.npmjs.org/@atproto-labs/did-resolver/-/did-resolver-0.2.3.tgz",
29
+
"integrity": "sha512-NAAVMthPD98eEYprpU7+MccDxFzwa3OhecweitL0/4ntjjcmqy1ytTl+ynOcTEC69H/ENjlpo36BB+b2obDcvA==",
30
+
"license": "MIT",
31
+
"dependencies": {
32
+
"@atproto-labs/fetch": "0.2.3",
33
+
"@atproto-labs/pipe": "0.1.1",
34
+
"@atproto-labs/simple-store": "0.3.0",
35
+
"@atproto-labs/simple-store-memory": "0.1.4",
36
+
"@atproto/did": "0.2.2",
37
+
"zod": "^3.23.8"
38
+
}
39
+
},
40
+
"node_modules/@atproto-labs/fetch": {
41
+
"version": "0.2.3",
42
+
"resolved": "https://registry.npmjs.org/@atproto-labs/fetch/-/fetch-0.2.3.tgz",
43
+
"integrity": "sha512-NZtbJOCbxKUFRFKMpamT38PUQMY0hX0p7TG5AEYOPhZKZEP7dHZ1K2s1aB8MdVH0qxmqX7nQleNrrvLf09Zfdw==",
44
+
"license": "MIT",
45
+
"dependencies": {
46
+
"@atproto-labs/pipe": "0.1.1"
47
+
}
48
+
},
49
+
"node_modules/@atproto-labs/fetch-node": {
50
+
"version": "0.2.0",
51
+
"resolved": "https://registry.npmjs.org/@atproto-labs/fetch-node/-/fetch-node-0.2.0.tgz",
52
+
"integrity": "sha512-Krq09nH/aeoiU2s9xdHA0FjTEFWG9B5FFenipv1iRixCcPc7V3DhTNDawxG9gI8Ny0k4dBVS9WTRN/IDzBx86Q==",
53
+
"license": "MIT",
54
+
"dependencies": {
55
+
"@atproto-labs/fetch": "0.2.3",
56
+
"@atproto-labs/pipe": "0.1.1",
57
+
"ipaddr.js": "^2.1.0",
58
+
"undici": "^6.14.1"
59
+
},
60
+
"engines": {
61
+
"node": ">=18.7.0"
62
+
}
63
+
},
64
+
"node_modules/@atproto-labs/handle-resolver": {
65
+
"version": "0.3.3",
66
+
"resolved": "https://registry.npmjs.org/@atproto-labs/handle-resolver/-/handle-resolver-0.3.3.tgz",
67
+
"integrity": "sha512-tBPRiDNWigk39TEQgupnez2st/midvtSuwg+UMEhnEyYItH7imXgZWcHuDkO4HmT9Lxz7br5zLUNaqIfFuTf5w==",
68
+
"license": "MIT",
69
+
"dependencies": {
70
+
"@atproto-labs/simple-store": "0.3.0",
71
+
"@atproto-labs/simple-store-memory": "0.1.4",
72
+
"@atproto/did": "0.2.2",
73
+
"zod": "^3.23.8"
74
+
}
75
+
},
76
+
"node_modules/@atproto-labs/handle-resolver-node": {
77
+
"version": "0.1.22",
78
+
"resolved": "https://registry.npmjs.org/@atproto-labs/handle-resolver-node/-/handle-resolver-node-0.1.22.tgz",
79
+
"integrity": "sha512-Qu2Jc8CqwY8PeToWh1DBeExC6acHHamFXVsrhxB1+7jDRpRDNXhXfQLkblIkdL4y+F7c3KnE0u9VAxLWN9tFBw==",
80
+
"license": "MIT",
81
+
"dependencies": {
82
+
"@atproto-labs/fetch-node": "0.2.0",
83
+
"@atproto-labs/handle-resolver": "0.3.3",
84
+
"@atproto/did": "0.2.2"
85
+
},
86
+
"engines": {
87
+
"node": ">=18.7.0"
88
+
}
89
+
},
90
+
"node_modules/@atproto-labs/identity-resolver": {
91
+
"version": "0.3.3",
92
+
"resolved": "https://registry.npmjs.org/@atproto-labs/identity-resolver/-/identity-resolver-0.3.3.tgz",
93
+
"integrity": "sha512-UfijnA+1JB97vKXRv1zqOacgP6BRGVr6zS7sZCt+i84TxhydPfFxbku1iH+BUUEv86VMys/C/anunFu3Hmg6wg==",
94
+
"license": "MIT",
95
+
"dependencies": {
96
+
"@atproto-labs/did-resolver": "0.2.3",
97
+
"@atproto-labs/handle-resolver": "0.3.3"
98
+
}
99
+
},
100
+
"node_modules/@atproto-labs/pipe": {
101
+
"version": "0.1.1",
102
+
"resolved": "https://registry.npmjs.org/@atproto-labs/pipe/-/pipe-0.1.1.tgz",
103
+
"integrity": "sha512-hdNw2oUs2B6BN1lp+32pF7cp8EMKuIN5Qok2Vvv/aOpG/3tNSJ9YkvfI0k6Zd188LeDDYRUpYpxcoFIcGH/FNg==",
104
+
"license": "MIT"
105
+
},
106
+
"node_modules/@atproto-labs/simple-store": {
107
+
"version": "0.3.0",
108
+
"resolved": "https://registry.npmjs.org/@atproto-labs/simple-store/-/simple-store-0.3.0.tgz",
109
+
"integrity": "sha512-nOb6ONKBRJHRlukW1sVawUkBqReLlLx6hT35VS3imaNPwiXDxLnTK7lxw3Lrl9k5yugSBDQAkZAq3MPTEFSUBQ==",
110
+
"license": "MIT"
111
+
},
112
+
"node_modules/@atproto-labs/simple-store-memory": {
113
+
"version": "0.1.4",
114
+
"resolved": "https://registry.npmjs.org/@atproto-labs/simple-store-memory/-/simple-store-memory-0.1.4.tgz",
115
+
"integrity": "sha512-3mKY4dP8I7yKPFj9VKpYyCRzGJOi5CEpOLPlRhoJyLmgs3J4RzDrjn323Oakjz2Aj2JzRU/AIvWRAZVhpYNJHw==",
116
+
"license": "MIT",
117
+
"dependencies": {
118
+
"@atproto-labs/simple-store": "0.3.0",
119
+
"lru-cache": "^10.2.0"
120
+
}
121
+
},
122
+
"node_modules/@atproto/api": {
123
+
"version": "0.18.3",
124
+
"resolved": "https://registry.npmjs.org/@atproto/api/-/api-0.18.3.tgz",
125
+
"integrity": "sha512-CBqyZfkcKYsr348KP4CKb9plMlZ5A96HwA/DnYscPBl6fvMZkAezAjniZX+xUILASHQJg5c+NaNw9xP8ZuyyDQ==",
126
+
"license": "MIT",
127
+
"dependencies": {
128
+
"@atproto/common-web": "^0.4.5",
129
+
"@atproto/lexicon": "^0.5.2",
130
+
"@atproto/syntax": "^0.4.1",
131
+
"@atproto/xrpc": "^0.7.6",
132
+
"await-lock": "^2.2.2",
133
+
"multiformats": "^9.9.0",
134
+
"tlds": "^1.234.0",
135
+
"zod": "^3.23.8"
136
+
}
137
+
},
138
+
"node_modules/@atproto/common-web": {
139
+
"version": "0.4.5",
140
+
"resolved": "https://registry.npmjs.org/@atproto/common-web/-/common-web-0.4.5.tgz",
141
+
"integrity": "sha512-Tx0xUafLm3vRvOQpbBl5eb9V8xlC7TaRXs6dAulHRkDG3Kb+P9qn3pkDteq+aeMshbVXbVa1rm3Ok4vFyuoyYA==",
142
+
"license": "MIT",
143
+
"dependencies": {
144
+
"@atproto/lex-data": "0.0.1",
145
+
"@atproto/lex-json": "0.0.1",
146
+
"zod": "^3.23.8"
147
+
}
148
+
},
149
+
"node_modules/@atproto/did": {
150
+
"version": "0.2.2",
151
+
"resolved": "https://registry.npmjs.org/@atproto/did/-/did-0.2.2.tgz",
152
+
"integrity": "sha512-IfOcEIpGp3owcaWA/e8VSIjdi/ocz5JbT3Ghg9jgFgnxLlwE8ndrihiR4xbRdcdPLza9YQjrPQhfRYdCu7s4Yw==",
153
+
"license": "MIT",
154
+
"dependencies": {
155
+
"zod": "^3.23.8"
156
+
}
157
+
},
158
+
"node_modules/@atproto/jwk": {
159
+
"version": "0.6.0",
160
+
"resolved": "https://registry.npmjs.org/@atproto/jwk/-/jwk-0.6.0.tgz",
161
+
"integrity": "sha512-bDoJPvt7TrQVi/rBfBrSSpGykhtIriKxeYCYQTiPRKFfyRhbgpElF0wPXADjIswnbzZdOwbY63az4E/CFVT3Tw==",
162
+
"license": "MIT",
163
+
"dependencies": {
164
+
"multiformats": "^9.9.0",
165
+
"zod": "^3.23.8"
166
+
}
167
+
},
168
+
"node_modules/@atproto/jwk-jose": {
169
+
"version": "0.1.11",
170
+
"resolved": "https://registry.npmjs.org/@atproto/jwk-jose/-/jwk-jose-0.1.11.tgz",
171
+
"integrity": "sha512-i4Fnr2sTBYmMmHXl7NJh8GrCH+tDQEVWrcDMDnV5DjJfkgT17wIqvojIw9SNbSL4Uf0OtfEv6AgG0A+mgh8b5Q==",
172
+
"license": "MIT",
173
+
"dependencies": {
174
+
"@atproto/jwk": "0.6.0",
175
+
"jose": "^5.2.0"
176
+
}
177
+
},
178
+
"node_modules/@atproto/jwk-webcrypto": {
179
+
"version": "0.2.0",
180
+
"resolved": "https://registry.npmjs.org/@atproto/jwk-webcrypto/-/jwk-webcrypto-0.2.0.tgz",
181
+
"integrity": "sha512-UmgRrrEAkWvxwhlwe30UmDOdTEFidlIzBC7C3cCbeJMcBN1x8B3KH+crXrsTqfWQBG58mXgt8wgSK3Kxs2LhFg==",
182
+
"license": "MIT",
183
+
"dependencies": {
184
+
"@atproto/jwk": "0.6.0",
185
+
"@atproto/jwk-jose": "0.1.11",
186
+
"zod": "^3.23.8"
187
+
}
188
+
},
189
+
"node_modules/@atproto/lex-data": {
190
+
"version": "0.0.1",
191
+
"resolved": "https://registry.npmjs.org/@atproto/lex-data/-/lex-data-0.0.1.tgz",
192
+
"integrity": "sha512-DrS/8cQcQs3s5t9ELAFNtyDZ8/PdiCx47ALtFEP2GnX2uCBHZRkqWG7xmu6ehjc787nsFzZBvlnz3T/gov5fGA==",
193
+
"license": "MIT",
194
+
"dependencies": {
195
+
"@atproto/syntax": "0.4.1",
196
+
"multiformats": "^9.9.0",
197
+
"tslib": "^2.8.1",
198
+
"uint8arrays": "3.0.0",
199
+
"unicode-segmenter": "^0.14.0"
200
+
}
201
+
},
202
+
"node_modules/@atproto/lex-json": {
203
+
"version": "0.0.1",
204
+
"resolved": "https://registry.npmjs.org/@atproto/lex-json/-/lex-json-0.0.1.tgz",
205
+
"integrity": "sha512-ivcF7+pDRuD/P97IEKQ/9TruunXj0w58Khvwk3M6psaI5eZT6LRsRZ4cWcKaXiFX4SHnjy+x43g0f7pPtIsERg==",
206
+
"license": "MIT",
207
+
"dependencies": {
208
+
"@atproto/lex-data": "0.0.1",
209
+
"tslib": "^2.8.1"
210
+
}
211
+
},
212
+
"node_modules/@atproto/lexicon": {
213
+
"version": "0.5.2",
214
+
"resolved": "https://registry.npmjs.org/@atproto/lexicon/-/lexicon-0.5.2.tgz",
215
+
"integrity": "sha512-lRmJgMA8f5j7VB5Iu5cp188ald5FuI4FlmZ7nn6EBrk1dgOstWVrI5Ft6K3z2vjyLZRG6nzknlsw+tDP63p7bQ==",
216
+
"license": "MIT",
217
+
"dependencies": {
218
+
"@atproto/common-web": "^0.4.4",
219
+
"@atproto/syntax": "^0.4.1",
220
+
"iso-datestring-validator": "^2.2.2",
221
+
"multiformats": "^9.9.0",
222
+
"zod": "^3.23.8"
223
+
}
224
+
},
225
+
"node_modules/@atproto/oauth-client": {
226
+
"version": "0.5.9",
227
+
"resolved": "https://registry.npmjs.org/@atproto/oauth-client/-/oauth-client-0.5.9.tgz",
228
+
"integrity": "sha512-23Z77A9bQFJYWAn5qJRwfzYeLEzcAx77G6HK8mlbIOYuQbmv6YMmQBm4BntAntJmEukOG69IrdnGIHKvsC4wdg==",
229
+
"license": "MIT",
230
+
"dependencies": {
231
+
"@atproto-labs/did-resolver": "0.2.3",
232
+
"@atproto-labs/fetch": "0.2.3",
233
+
"@atproto-labs/handle-resolver": "0.3.3",
234
+
"@atproto-labs/identity-resolver": "0.3.3",
235
+
"@atproto-labs/simple-store": "0.3.0",
236
+
"@atproto-labs/simple-store-memory": "0.1.4",
237
+
"@atproto/did": "0.2.2",
238
+
"@atproto/jwk": "0.6.0",
239
+
"@atproto/oauth-types": "0.5.1",
240
+
"@atproto/xrpc": "0.7.6",
241
+
"core-js": "^3",
242
+
"multiformats": "^9.9.0",
243
+
"zod": "^3.23.8"
244
+
}
245
+
},
246
+
"node_modules/@atproto/oauth-client-node": {
247
+
"version": "0.3.11",
248
+
"resolved": "https://registry.npmjs.org/@atproto/oauth-client-node/-/oauth-client-node-0.3.11.tgz",
249
+
"integrity": "sha512-qcA3rr4gO9+THrwDWxAp0N249fiDhHpU1paOjq7eQUvpP0yAx0zaMjBnXCIY+ghU0ahX9dO+fS9/+TGNqZR6DA==",
250
+
"license": "MIT",
251
+
"dependencies": {
252
+
"@atproto-labs/did-resolver": "0.2.3",
253
+
"@atproto-labs/handle-resolver-node": "0.1.22",
254
+
"@atproto-labs/simple-store": "0.3.0",
255
+
"@atproto/did": "0.2.2",
256
+
"@atproto/jwk": "0.6.0",
257
+
"@atproto/jwk-jose": "0.1.11",
258
+
"@atproto/jwk-webcrypto": "0.2.0",
259
+
"@atproto/oauth-client": "0.5.9",
260
+
"@atproto/oauth-types": "0.5.1"
261
+
},
262
+
"engines": {
263
+
"node": ">=18.7.0"
264
+
}
265
+
},
266
+
"node_modules/@atproto/oauth-types": {
267
+
"version": "0.5.1",
268
+
"resolved": "https://registry.npmjs.org/@atproto/oauth-types/-/oauth-types-0.5.1.tgz",
269
+
"integrity": "sha512-x651IN8Ul0LOB7fZXXggcBbc66/7vsTvh0Zqg6vplSbVjozJR6lzKo8i42QKrstXO8+2kLy49qoIHXbTHHOI1Q==",
270
+
"license": "MIT",
271
+
"dependencies": {
272
+
"@atproto/did": "0.2.2",
273
+
"@atproto/jwk": "0.6.0",
274
+
"zod": "^3.23.8"
275
+
}
276
+
},
277
+
"node_modules/@atproto/syntax": {
278
+
"version": "0.4.1",
279
+
"resolved": "https://registry.npmjs.org/@atproto/syntax/-/syntax-0.4.1.tgz",
280
+
"integrity": "sha512-CJdImtLAiFO+0z3BWTtxwk6aY5w4t8orHTMVJgkf++QRJWTxPbIFko/0hrkADB7n2EruDxDSeAgfUGehpH6ngw==",
281
+
"license": "MIT"
282
+
},
283
+
"node_modules/@atproto/xrpc": {
284
+
"version": "0.7.6",
285
+
"resolved": "https://registry.npmjs.org/@atproto/xrpc/-/xrpc-0.7.6.tgz",
286
+
"integrity": "sha512-RvCf4j0JnKYWuz3QzsYCntJi3VuiAAybQsMIUw2wLWcHhchO9F7UaBZINLL2z0qc/cYWPv5NSwcVydMseoCZLA==",
287
+
"license": "MIT",
288
+
"dependencies": {
289
+
"@atproto/lexicon": "^0.5.2",
290
+
"zod": "^3.23.8"
291
+
}
292
+
},
293
+
"node_modules/@esbuild/aix-ppc64": {
294
+
"version": "0.25.12",
295
+
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
296
+
"integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
297
+
"cpu": [
298
+
"ppc64"
299
+
],
300
+
"dev": true,
301
+
"license": "MIT",
302
+
"optional": true,
303
+
"os": [
304
+
"aix"
305
+
],
306
+
"engines": {
307
+
"node": ">=18"
308
+
}
309
+
},
310
+
"node_modules/@esbuild/android-arm": {
311
+
"version": "0.25.12",
312
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
313
+
"integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
314
+
"cpu": [
315
+
"arm"
316
+
],
317
+
"dev": true,
318
+
"license": "MIT",
319
+
"optional": true,
320
+
"os": [
321
+
"android"
322
+
],
323
+
"engines": {
324
+
"node": ">=18"
325
+
}
326
+
},
327
+
"node_modules/@esbuild/android-arm64": {
328
+
"version": "0.25.12",
329
+
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
330
+
"integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
331
+
"cpu": [
332
+
"arm64"
333
+
],
334
+
"dev": true,
335
+
"license": "MIT",
336
+
"optional": true,
337
+
"os": [
338
+
"android"
339
+
],
340
+
"engines": {
341
+
"node": ">=18"
342
+
}
343
+
},
344
+
"node_modules/@esbuild/android-x64": {
345
+
"version": "0.25.12",
346
+
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
347
+
"integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
348
+
"cpu": [
349
+
"x64"
350
+
],
351
+
"dev": true,
352
+
"license": "MIT",
353
+
"optional": true,
354
+
"os": [
355
+
"android"
356
+
],
357
+
"engines": {
358
+
"node": ">=18"
359
+
}
360
+
},
361
+
"node_modules/@esbuild/darwin-arm64": {
362
+
"version": "0.25.12",
363
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
364
+
"integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
365
+
"cpu": [
366
+
"arm64"
367
+
],
368
+
"dev": true,
369
+
"license": "MIT",
370
+
"optional": true,
371
+
"os": [
372
+
"darwin"
373
+
],
374
+
"engines": {
375
+
"node": ">=18"
376
+
}
377
+
},
378
+
"node_modules/@esbuild/darwin-x64": {
379
+
"version": "0.25.12",
380
+
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
381
+
"integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
382
+
"cpu": [
383
+
"x64"
384
+
],
385
+
"dev": true,
386
+
"license": "MIT",
387
+
"optional": true,
388
+
"os": [
389
+
"darwin"
390
+
],
391
+
"engines": {
392
+
"node": ">=18"
393
+
}
394
+
},
395
+
"node_modules/@esbuild/freebsd-arm64": {
396
+
"version": "0.25.12",
397
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
398
+
"integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
399
+
"cpu": [
400
+
"arm64"
401
+
],
402
+
"dev": true,
403
+
"license": "MIT",
404
+
"optional": true,
405
+
"os": [
406
+
"freebsd"
407
+
],
408
+
"engines": {
409
+
"node": ">=18"
410
+
}
411
+
},
412
+
"node_modules/@esbuild/freebsd-x64": {
413
+
"version": "0.25.12",
414
+
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
415
+
"integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
416
+
"cpu": [
417
+
"x64"
418
+
],
419
+
"dev": true,
420
+
"license": "MIT",
421
+
"optional": true,
422
+
"os": [
423
+
"freebsd"
424
+
],
425
+
"engines": {
426
+
"node": ">=18"
427
+
}
428
+
},
429
+
"node_modules/@esbuild/linux-arm": {
430
+
"version": "0.25.12",
431
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
432
+
"integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
433
+
"cpu": [
434
+
"arm"
435
+
],
436
+
"dev": true,
437
+
"license": "MIT",
438
+
"optional": true,
439
+
"os": [
440
+
"linux"
441
+
],
442
+
"engines": {
443
+
"node": ">=18"
444
+
}
445
+
},
446
+
"node_modules/@esbuild/linux-arm64": {
447
+
"version": "0.25.12",
448
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
449
+
"integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
450
+
"cpu": [
451
+
"arm64"
452
+
],
453
+
"dev": true,
454
+
"license": "MIT",
455
+
"optional": true,
456
+
"os": [
457
+
"linux"
458
+
],
459
+
"engines": {
460
+
"node": ">=18"
461
+
}
462
+
},
463
+
"node_modules/@esbuild/linux-ia32": {
464
+
"version": "0.25.12",
465
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
466
+
"integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
467
+
"cpu": [
468
+
"ia32"
469
+
],
470
+
"dev": true,
471
+
"license": "MIT",
472
+
"optional": true,
473
+
"os": [
474
+
"linux"
475
+
],
476
+
"engines": {
477
+
"node": ">=18"
478
+
}
479
+
},
480
+
"node_modules/@esbuild/linux-loong64": {
481
+
"version": "0.25.12",
482
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
483
+
"integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
484
+
"cpu": [
485
+
"loong64"
486
+
],
487
+
"dev": true,
488
+
"license": "MIT",
489
+
"optional": true,
490
+
"os": [
491
+
"linux"
492
+
],
493
+
"engines": {
494
+
"node": ">=18"
495
+
}
496
+
},
497
+
"node_modules/@esbuild/linux-mips64el": {
498
+
"version": "0.25.12",
499
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
500
+
"integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
501
+
"cpu": [
502
+
"mips64el"
503
+
],
504
+
"dev": true,
505
+
"license": "MIT",
506
+
"optional": true,
507
+
"os": [
508
+
"linux"
509
+
],
510
+
"engines": {
511
+
"node": ">=18"
512
+
}
513
+
},
514
+
"node_modules/@esbuild/linux-ppc64": {
515
+
"version": "0.25.12",
516
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
517
+
"integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
518
+
"cpu": [
519
+
"ppc64"
520
+
],
521
+
"dev": true,
522
+
"license": "MIT",
523
+
"optional": true,
524
+
"os": [
525
+
"linux"
526
+
],
527
+
"engines": {
528
+
"node": ">=18"
529
+
}
530
+
},
531
+
"node_modules/@esbuild/linux-riscv64": {
532
+
"version": "0.25.12",
533
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
534
+
"integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
535
+
"cpu": [
536
+
"riscv64"
537
+
],
538
+
"dev": true,
539
+
"license": "MIT",
540
+
"optional": true,
541
+
"os": [
542
+
"linux"
543
+
],
544
+
"engines": {
545
+
"node": ">=18"
546
+
}
547
+
},
548
+
"node_modules/@esbuild/linux-s390x": {
549
+
"version": "0.25.12",
550
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
551
+
"integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
552
+
"cpu": [
553
+
"s390x"
554
+
],
555
+
"dev": true,
556
+
"license": "MIT",
557
+
"optional": true,
558
+
"os": [
559
+
"linux"
560
+
],
561
+
"engines": {
562
+
"node": ">=18"
563
+
}
564
+
},
565
+
"node_modules/@esbuild/linux-x64": {
566
+
"version": "0.25.12",
567
+
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
568
+
"integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
569
+
"cpu": [
570
+
"x64"
571
+
],
572
+
"dev": true,
573
+
"license": "MIT",
574
+
"optional": true,
575
+
"os": [
576
+
"linux"
577
+
],
578
+
"engines": {
579
+
"node": ">=18"
580
+
}
581
+
},
582
+
"node_modules/@esbuild/netbsd-arm64": {
583
+
"version": "0.25.12",
584
+
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
585
+
"integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
586
+
"cpu": [
587
+
"arm64"
588
+
],
589
+
"dev": true,
590
+
"license": "MIT",
591
+
"optional": true,
592
+
"os": [
593
+
"netbsd"
594
+
],
595
+
"engines": {
596
+
"node": ">=18"
597
+
}
598
+
},
599
+
"node_modules/@esbuild/netbsd-x64": {
600
+
"version": "0.25.12",
601
+
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
602
+
"integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
603
+
"cpu": [
604
+
"x64"
605
+
],
606
+
"dev": true,
607
+
"license": "MIT",
608
+
"optional": true,
609
+
"os": [
610
+
"netbsd"
611
+
],
612
+
"engines": {
613
+
"node": ">=18"
614
+
}
615
+
},
616
+
"node_modules/@esbuild/openbsd-arm64": {
617
+
"version": "0.25.12",
618
+
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
619
+
"integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
620
+
"cpu": [
621
+
"arm64"
622
+
],
623
+
"dev": true,
624
+
"license": "MIT",
625
+
"optional": true,
626
+
"os": [
627
+
"openbsd"
628
+
],
629
+
"engines": {
630
+
"node": ">=18"
631
+
}
632
+
},
633
+
"node_modules/@esbuild/openbsd-x64": {
634
+
"version": "0.25.12",
635
+
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
636
+
"integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
637
+
"cpu": [
638
+
"x64"
639
+
],
640
+
"dev": true,
641
+
"license": "MIT",
642
+
"optional": true,
643
+
"os": [
644
+
"openbsd"
645
+
],
646
+
"engines": {
647
+
"node": ">=18"
648
+
}
649
+
},
650
+
"node_modules/@esbuild/openharmony-arm64": {
651
+
"version": "0.25.12",
652
+
"resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
653
+
"integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
654
+
"cpu": [
655
+
"arm64"
656
+
],
657
+
"dev": true,
658
+
"license": "MIT",
659
+
"optional": true,
660
+
"os": [
661
+
"openharmony"
662
+
],
663
+
"engines": {
664
+
"node": ">=18"
665
+
}
666
+
},
667
+
"node_modules/@esbuild/sunos-x64": {
668
+
"version": "0.25.12",
669
+
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
670
+
"integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
671
+
"cpu": [
672
+
"x64"
673
+
],
674
+
"dev": true,
675
+
"license": "MIT",
676
+
"optional": true,
677
+
"os": [
678
+
"sunos"
679
+
],
680
+
"engines": {
681
+
"node": ">=18"
682
+
}
683
+
},
684
+
"node_modules/@esbuild/win32-arm64": {
685
+
"version": "0.25.12",
686
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
687
+
"integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
688
+
"cpu": [
689
+
"arm64"
690
+
],
691
+
"dev": true,
692
+
"license": "MIT",
693
+
"optional": true,
694
+
"os": [
695
+
"win32"
696
+
],
697
+
"engines": {
698
+
"node": ">=18"
699
+
}
700
+
},
701
+
"node_modules/@esbuild/win32-ia32": {
702
+
"version": "0.25.12",
703
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
704
+
"integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
705
+
"cpu": [
706
+
"ia32"
707
+
],
708
+
"dev": true,
709
+
"license": "MIT",
710
+
"optional": true,
711
+
"os": [
712
+
"win32"
713
+
],
714
+
"engines": {
715
+
"node": ">=18"
716
+
}
717
+
},
718
+
"node_modules/@esbuild/win32-x64": {
719
+
"version": "0.25.12",
720
+
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
721
+
"integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
722
+
"cpu": [
723
+
"x64"
724
+
],
725
+
"dev": true,
726
+
"license": "MIT",
727
+
"optional": true,
728
+
"os": [
729
+
"win32"
730
+
],
731
+
"engines": {
732
+
"node": ">=18"
733
+
}
734
+
},
735
+
"node_modules/@types/better-sqlite3": {
736
+
"version": "7.6.13",
737
+
"resolved": "https://registry.npmjs.org/@types/better-sqlite3/-/better-sqlite3-7.6.13.tgz",
738
+
"integrity": "sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==",
739
+
"dev": true,
740
+
"license": "MIT",
741
+
"dependencies": {
742
+
"@types/node": "*"
743
+
}
744
+
},
745
+
"node_modules/@types/body-parser": {
746
+
"version": "1.19.6",
747
+
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
748
+
"integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==",
749
+
"dev": true,
750
+
"license": "MIT",
751
+
"dependencies": {
752
+
"@types/connect": "*",
753
+
"@types/node": "*"
754
+
}
755
+
},
756
+
"node_modules/@types/connect": {
757
+
"version": "3.4.38",
758
+
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
759
+
"integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
760
+
"dev": true,
761
+
"license": "MIT",
762
+
"dependencies": {
763
+
"@types/node": "*"
764
+
}
765
+
},
766
+
"node_modules/@types/express": {
767
+
"version": "5.0.5",
768
+
"resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.5.tgz",
769
+
"integrity": "sha512-LuIQOcb6UmnF7C1PCFmEU1u2hmiHL43fgFQX67sN3H4Z+0Yk0Neo++mFsBjhOAuLzvlQeqAAkeDOZrJs9rzumQ==",
770
+
"dev": true,
771
+
"license": "MIT",
772
+
"dependencies": {
773
+
"@types/body-parser": "*",
774
+
"@types/express-serve-static-core": "^5.0.0",
775
+
"@types/serve-static": "^1"
776
+
}
777
+
},
778
+
"node_modules/@types/express-serve-static-core": {
779
+
"version": "5.1.0",
780
+
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz",
781
+
"integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==",
782
+
"dev": true,
783
+
"license": "MIT",
784
+
"dependencies": {
785
+
"@types/node": "*",
786
+
"@types/qs": "*",
787
+
"@types/range-parser": "*",
788
+
"@types/send": "*"
789
+
}
790
+
},
791
+
"node_modules/@types/http-errors": {
792
+
"version": "2.0.5",
793
+
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz",
794
+
"integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==",
795
+
"dev": true,
796
+
"license": "MIT"
797
+
},
798
+
"node_modules/@types/mime": {
799
+
"version": "1.3.5",
800
+
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
801
+
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
802
+
"dev": true,
803
+
"license": "MIT"
804
+
},
805
+
"node_modules/@types/node": {
806
+
"version": "24.10.1",
807
+
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.1.tgz",
808
+
"integrity": "sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==",
809
+
"dev": true,
810
+
"license": "MIT",
811
+
"dependencies": {
812
+
"undici-types": "~7.16.0"
813
+
}
814
+
},
815
+
"node_modules/@types/qs": {
816
+
"version": "6.14.0",
817
+
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz",
818
+
"integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==",
819
+
"dev": true,
820
+
"license": "MIT"
821
+
},
822
+
"node_modules/@types/range-parser": {
823
+
"version": "1.2.7",
824
+
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
825
+
"integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
826
+
"dev": true,
827
+
"license": "MIT"
828
+
},
829
+
"node_modules/@types/send": {
830
+
"version": "1.2.1",
831
+
"resolved": "https://registry.npmjs.org/@types/send/-/send-1.2.1.tgz",
832
+
"integrity": "sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==",
833
+
"dev": true,
834
+
"license": "MIT",
835
+
"dependencies": {
836
+
"@types/node": "*"
837
+
}
838
+
},
839
+
"node_modules/@types/serve-static": {
840
+
"version": "1.15.10",
841
+
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.10.tgz",
842
+
"integrity": "sha512-tRs1dB+g8Itk72rlSI2ZrW6vZg0YrLI81iQSTkMmOqnqCaNr/8Ek4VwWcN5vZgCYWbg/JJSGBlUaYGAOP73qBw==",
843
+
"dev": true,
844
+
"license": "MIT",
845
+
"dependencies": {
846
+
"@types/http-errors": "*",
847
+
"@types/node": "*",
848
+
"@types/send": "<1"
849
+
}
850
+
},
851
+
"node_modules/@types/serve-static/node_modules/@types/send": {
852
+
"version": "0.17.6",
853
+
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.6.tgz",
854
+
"integrity": "sha512-Uqt8rPBE8SY0RK8JB1EzVOIZ32uqy8HwdxCnoCOsYrvnswqmFZ/k+9Ikidlk/ImhsdvBsloHbAlewb2IEBV/Og==",
855
+
"dev": true,
856
+
"license": "MIT",
857
+
"dependencies": {
858
+
"@types/mime": "^1",
859
+
"@types/node": "*"
860
+
}
861
+
},
862
+
"node_modules/accepts": {
863
+
"version": "2.0.0",
864
+
"resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz",
865
+
"integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==",
866
+
"license": "MIT",
867
+
"dependencies": {
868
+
"mime-types": "^3.0.0",
869
+
"negotiator": "^1.0.0"
870
+
},
871
+
"engines": {
872
+
"node": ">= 0.6"
873
+
}
874
+
},
875
+
"node_modules/await-lock": {
876
+
"version": "2.2.2",
877
+
"resolved": "https://registry.npmjs.org/await-lock/-/await-lock-2.2.2.tgz",
878
+
"integrity": "sha512-aDczADvlvTGajTDjcjpJMqRkOF6Qdz3YbPZm/PyW6tKPkx2hlYBzxMhEywM/tU72HrVZjgl5VCdRuMlA7pZ8Gw==",
879
+
"license": "MIT"
880
+
},
881
+
"node_modules/base64-js": {
882
+
"version": "1.5.1",
883
+
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
884
+
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
885
+
"funding": [
886
+
{
887
+
"type": "github",
888
+
"url": "https://github.com/sponsors/feross"
889
+
},
890
+
{
891
+
"type": "patreon",
892
+
"url": "https://www.patreon.com/feross"
893
+
},
894
+
{
895
+
"type": "consulting",
896
+
"url": "https://feross.org/support"
897
+
}
898
+
],
899
+
"license": "MIT"
900
+
},
901
+
"node_modules/better-sqlite3": {
902
+
"version": "12.5.0",
903
+
"resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-12.5.0.tgz",
904
+
"integrity": "sha512-WwCZ/5Diz7rsF29o27o0Gcc1Du+l7Zsv7SYtVPG0X3G/uUI1LqdxrQI7c9Hs2FWpqXXERjW9hp6g3/tH7DlVKg==",
905
+
"hasInstallScript": true,
906
+
"license": "MIT",
907
+
"dependencies": {
908
+
"bindings": "^1.5.0",
909
+
"prebuild-install": "^7.1.1"
910
+
},
911
+
"engines": {
912
+
"node": "20.x || 22.x || 23.x || 24.x || 25.x"
913
+
}
914
+
},
915
+
"node_modules/bindings": {
916
+
"version": "1.5.0",
917
+
"resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
918
+
"integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
919
+
"license": "MIT",
920
+
"dependencies": {
921
+
"file-uri-to-path": "1.0.0"
922
+
}
923
+
},
924
+
"node_modules/bl": {
925
+
"version": "4.1.0",
926
+
"resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
927
+
"integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
928
+
"license": "MIT",
929
+
"dependencies": {
930
+
"buffer": "^5.5.0",
931
+
"inherits": "^2.0.4",
932
+
"readable-stream": "^3.4.0"
933
+
}
934
+
},
935
+
"node_modules/body-parser": {
936
+
"version": "2.2.1",
937
+
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz",
938
+
"integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==",
939
+
"license": "MIT",
940
+
"dependencies": {
941
+
"bytes": "^3.1.2",
942
+
"content-type": "^1.0.5",
943
+
"debug": "^4.4.3",
944
+
"http-errors": "^2.0.0",
945
+
"iconv-lite": "^0.7.0",
946
+
"on-finished": "^2.4.1",
947
+
"qs": "^6.14.0",
948
+
"raw-body": "^3.0.1",
949
+
"type-is": "^2.0.1"
950
+
},
951
+
"engines": {
952
+
"node": ">=18"
953
+
},
954
+
"funding": {
955
+
"type": "opencollective",
956
+
"url": "https://opencollective.com/express"
957
+
}
958
+
},
959
+
"node_modules/buffer": {
960
+
"version": "5.7.1",
961
+
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
962
+
"integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
963
+
"funding": [
964
+
{
965
+
"type": "github",
966
+
"url": "https://github.com/sponsors/feross"
967
+
},
968
+
{
969
+
"type": "patreon",
970
+
"url": "https://www.patreon.com/feross"
971
+
},
972
+
{
973
+
"type": "consulting",
974
+
"url": "https://feross.org/support"
975
+
}
976
+
],
977
+
"license": "MIT",
978
+
"dependencies": {
979
+
"base64-js": "^1.3.1",
980
+
"ieee754": "^1.1.13"
981
+
}
982
+
},
983
+
"node_modules/bytes": {
984
+
"version": "3.1.2",
985
+
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
986
+
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
987
+
"license": "MIT",
988
+
"engines": {
989
+
"node": ">= 0.8"
990
+
}
991
+
},
992
+
"node_modules/call-bind-apply-helpers": {
993
+
"version": "1.0.2",
994
+
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
995
+
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
996
+
"license": "MIT",
997
+
"dependencies": {
998
+
"es-errors": "^1.3.0",
999
+
"function-bind": "^1.1.2"
1000
+
},
1001
+
"engines": {
1002
+
"node": ">= 0.4"
1003
+
}
1004
+
},
1005
+
"node_modules/call-bound": {
1006
+
"version": "1.0.4",
1007
+
"resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz",
1008
+
"integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==",
1009
+
"license": "MIT",
1010
+
"dependencies": {
1011
+
"call-bind-apply-helpers": "^1.0.2",
1012
+
"get-intrinsic": "^1.3.0"
1013
+
},
1014
+
"engines": {
1015
+
"node": ">= 0.4"
1016
+
},
1017
+
"funding": {
1018
+
"url": "https://github.com/sponsors/ljharb"
1019
+
}
1020
+
},
1021
+
"node_modules/chownr": {
1022
+
"version": "1.1.4",
1023
+
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
1024
+
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
1025
+
"license": "ISC"
1026
+
},
1027
+
"node_modules/content-disposition": {
1028
+
"version": "1.0.1",
1029
+
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz",
1030
+
"integrity": "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==",
1031
+
"license": "MIT",
1032
+
"engines": {
1033
+
"node": ">=18"
1034
+
},
1035
+
"funding": {
1036
+
"type": "opencollective",
1037
+
"url": "https://opencollective.com/express"
1038
+
}
1039
+
},
1040
+
"node_modules/content-type": {
1041
+
"version": "1.0.5",
1042
+
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
1043
+
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
1044
+
"license": "MIT",
1045
+
"engines": {
1046
+
"node": ">= 0.6"
1047
+
}
1048
+
},
1049
+
"node_modules/cookie": {
1050
+
"version": "0.7.2",
1051
+
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
1052
+
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
1053
+
"license": "MIT",
1054
+
"engines": {
1055
+
"node": ">= 0.6"
1056
+
}
1057
+
},
1058
+
"node_modules/cookie-signature": {
1059
+
"version": "1.2.2",
1060
+
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz",
1061
+
"integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==",
1062
+
"license": "MIT",
1063
+
"engines": {
1064
+
"node": ">=6.6.0"
1065
+
}
1066
+
},
1067
+
"node_modules/core-js": {
1068
+
"version": "3.47.0",
1069
+
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.47.0.tgz",
1070
+
"integrity": "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==",
1071
+
"hasInstallScript": true,
1072
+
"license": "MIT",
1073
+
"funding": {
1074
+
"type": "opencollective",
1075
+
"url": "https://opencollective.com/core-js"
1076
+
}
1077
+
},
1078
+
"node_modules/debug": {
1079
+
"version": "4.4.3",
1080
+
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
1081
+
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
1082
+
"license": "MIT",
1083
+
"dependencies": {
1084
+
"ms": "^2.1.3"
1085
+
},
1086
+
"engines": {
1087
+
"node": ">=6.0"
1088
+
},
1089
+
"peerDependenciesMeta": {
1090
+
"supports-color": {
1091
+
"optional": true
1092
+
}
1093
+
}
1094
+
},
1095
+
"node_modules/decompress-response": {
1096
+
"version": "6.0.0",
1097
+
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
1098
+
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
1099
+
"license": "MIT",
1100
+
"dependencies": {
1101
+
"mimic-response": "^3.1.0"
1102
+
},
1103
+
"engines": {
1104
+
"node": ">=10"
1105
+
},
1106
+
"funding": {
1107
+
"url": "https://github.com/sponsors/sindresorhus"
1108
+
}
1109
+
},
1110
+
"node_modules/deep-extend": {
1111
+
"version": "0.6.0",
1112
+
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
1113
+
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
1114
+
"license": "MIT",
1115
+
"engines": {
1116
+
"node": ">=4.0.0"
1117
+
}
1118
+
},
1119
+
"node_modules/depd": {
1120
+
"version": "2.0.0",
1121
+
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
1122
+
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
1123
+
"license": "MIT",
1124
+
"engines": {
1125
+
"node": ">= 0.8"
1126
+
}
1127
+
},
1128
+
"node_modules/detect-libc": {
1129
+
"version": "2.1.2",
1130
+
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
1131
+
"integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
1132
+
"license": "Apache-2.0",
1133
+
"engines": {
1134
+
"node": ">=8"
1135
+
}
1136
+
},
1137
+
"node_modules/dunder-proto": {
1138
+
"version": "1.0.1",
1139
+
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
1140
+
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
1141
+
"license": "MIT",
1142
+
"dependencies": {
1143
+
"call-bind-apply-helpers": "^1.0.1",
1144
+
"es-errors": "^1.3.0",
1145
+
"gopd": "^1.2.0"
1146
+
},
1147
+
"engines": {
1148
+
"node": ">= 0.4"
1149
+
}
1150
+
},
1151
+
"node_modules/ee-first": {
1152
+
"version": "1.1.1",
1153
+
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
1154
+
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
1155
+
"license": "MIT"
1156
+
},
1157
+
"node_modules/encodeurl": {
1158
+
"version": "2.0.0",
1159
+
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
1160
+
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
1161
+
"license": "MIT",
1162
+
"engines": {
1163
+
"node": ">= 0.8"
1164
+
}
1165
+
},
1166
+
"node_modules/end-of-stream": {
1167
+
"version": "1.4.5",
1168
+
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
1169
+
"integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
1170
+
"license": "MIT",
1171
+
"dependencies": {
1172
+
"once": "^1.4.0"
1173
+
}
1174
+
},
1175
+
"node_modules/es-define-property": {
1176
+
"version": "1.0.1",
1177
+
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
1178
+
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
1179
+
"license": "MIT",
1180
+
"engines": {
1181
+
"node": ">= 0.4"
1182
+
}
1183
+
},
1184
+
"node_modules/es-errors": {
1185
+
"version": "1.3.0",
1186
+
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
1187
+
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
1188
+
"license": "MIT",
1189
+
"engines": {
1190
+
"node": ">= 0.4"
1191
+
}
1192
+
},
1193
+
"node_modules/es-object-atoms": {
1194
+
"version": "1.1.1",
1195
+
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
1196
+
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
1197
+
"license": "MIT",
1198
+
"dependencies": {
1199
+
"es-errors": "^1.3.0"
1200
+
},
1201
+
"engines": {
1202
+
"node": ">= 0.4"
1203
+
}
1204
+
},
1205
+
"node_modules/esbuild": {
1206
+
"version": "0.25.12",
1207
+
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
1208
+
"integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
1209
+
"dev": true,
1210
+
"hasInstallScript": true,
1211
+
"license": "MIT",
1212
+
"bin": {
1213
+
"esbuild": "bin/esbuild"
1214
+
},
1215
+
"engines": {
1216
+
"node": ">=18"
1217
+
},
1218
+
"optionalDependencies": {
1219
+
"@esbuild/aix-ppc64": "0.25.12",
1220
+
"@esbuild/android-arm": "0.25.12",
1221
+
"@esbuild/android-arm64": "0.25.12",
1222
+
"@esbuild/android-x64": "0.25.12",
1223
+
"@esbuild/darwin-arm64": "0.25.12",
1224
+
"@esbuild/darwin-x64": "0.25.12",
1225
+
"@esbuild/freebsd-arm64": "0.25.12",
1226
+
"@esbuild/freebsd-x64": "0.25.12",
1227
+
"@esbuild/linux-arm": "0.25.12",
1228
+
"@esbuild/linux-arm64": "0.25.12",
1229
+
"@esbuild/linux-ia32": "0.25.12",
1230
+
"@esbuild/linux-loong64": "0.25.12",
1231
+
"@esbuild/linux-mips64el": "0.25.12",
1232
+
"@esbuild/linux-ppc64": "0.25.12",
1233
+
"@esbuild/linux-riscv64": "0.25.12",
1234
+
"@esbuild/linux-s390x": "0.25.12",
1235
+
"@esbuild/linux-x64": "0.25.12",
1236
+
"@esbuild/netbsd-arm64": "0.25.12",
1237
+
"@esbuild/netbsd-x64": "0.25.12",
1238
+
"@esbuild/openbsd-arm64": "0.25.12",
1239
+
"@esbuild/openbsd-x64": "0.25.12",
1240
+
"@esbuild/openharmony-arm64": "0.25.12",
1241
+
"@esbuild/sunos-x64": "0.25.12",
1242
+
"@esbuild/win32-arm64": "0.25.12",
1243
+
"@esbuild/win32-ia32": "0.25.12",
1244
+
"@esbuild/win32-x64": "0.25.12"
1245
+
}
1246
+
},
1247
+
"node_modules/escape-html": {
1248
+
"version": "1.0.3",
1249
+
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
1250
+
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
1251
+
"license": "MIT"
1252
+
},
1253
+
"node_modules/etag": {
1254
+
"version": "1.8.1",
1255
+
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
1256
+
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
1257
+
"license": "MIT",
1258
+
"engines": {
1259
+
"node": ">= 0.6"
1260
+
}
1261
+
},
1262
+
"node_modules/expand-template": {
1263
+
"version": "2.0.3",
1264
+
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
1265
+
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==",
1266
+
"license": "(MIT OR WTFPL)",
1267
+
"engines": {
1268
+
"node": ">=6"
1269
+
}
1270
+
},
1271
+
"node_modules/express": {
1272
+
"version": "5.1.0",
1273
+
"resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz",
1274
+
"integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
1275
+
"license": "MIT",
1276
+
"dependencies": {
1277
+
"accepts": "^2.0.0",
1278
+
"body-parser": "^2.2.0",
1279
+
"content-disposition": "^1.0.0",
1280
+
"content-type": "^1.0.5",
1281
+
"cookie": "^0.7.1",
1282
+
"cookie-signature": "^1.2.1",
1283
+
"debug": "^4.4.0",
1284
+
"encodeurl": "^2.0.0",
1285
+
"escape-html": "^1.0.3",
1286
+
"etag": "^1.8.1",
1287
+
"finalhandler": "^2.1.0",
1288
+
"fresh": "^2.0.0",
1289
+
"http-errors": "^2.0.0",
1290
+
"merge-descriptors": "^2.0.0",
1291
+
"mime-types": "^3.0.0",
1292
+
"on-finished": "^2.4.1",
1293
+
"once": "^1.4.0",
1294
+
"parseurl": "^1.3.3",
1295
+
"proxy-addr": "^2.0.7",
1296
+
"qs": "^6.14.0",
1297
+
"range-parser": "^1.2.1",
1298
+
"router": "^2.2.0",
1299
+
"send": "^1.1.0",
1300
+
"serve-static": "^2.2.0",
1301
+
"statuses": "^2.0.1",
1302
+
"type-is": "^2.0.1",
1303
+
"vary": "^1.1.2"
1304
+
},
1305
+
"engines": {
1306
+
"node": ">= 18"
1307
+
},
1308
+
"funding": {
1309
+
"type": "opencollective",
1310
+
"url": "https://opencollective.com/express"
1311
+
}
1312
+
},
1313
+
"node_modules/file-uri-to-path": {
1314
+
"version": "1.0.0",
1315
+
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
1316
+
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
1317
+
"license": "MIT"
1318
+
},
1319
+
"node_modules/finalhandler": {
1320
+
"version": "2.1.0",
1321
+
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz",
1322
+
"integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==",
1323
+
"license": "MIT",
1324
+
"dependencies": {
1325
+
"debug": "^4.4.0",
1326
+
"encodeurl": "^2.0.0",
1327
+
"escape-html": "^1.0.3",
1328
+
"on-finished": "^2.4.1",
1329
+
"parseurl": "^1.3.3",
1330
+
"statuses": "^2.0.1"
1331
+
},
1332
+
"engines": {
1333
+
"node": ">= 0.8"
1334
+
}
1335
+
},
1336
+
"node_modules/forwarded": {
1337
+
"version": "0.2.0",
1338
+
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
1339
+
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
1340
+
"license": "MIT",
1341
+
"engines": {
1342
+
"node": ">= 0.6"
1343
+
}
1344
+
},
1345
+
"node_modules/fresh": {
1346
+
"version": "2.0.0",
1347
+
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
1348
+
"integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
1349
+
"license": "MIT",
1350
+
"engines": {
1351
+
"node": ">= 0.8"
1352
+
}
1353
+
},
1354
+
"node_modules/fs-constants": {
1355
+
"version": "1.0.0",
1356
+
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
1357
+
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
1358
+
"license": "MIT"
1359
+
},
1360
+
"node_modules/fsevents": {
1361
+
"version": "2.3.3",
1362
+
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
1363
+
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
1364
+
"dev": true,
1365
+
"hasInstallScript": true,
1366
+
"license": "MIT",
1367
+
"optional": true,
1368
+
"os": [
1369
+
"darwin"
1370
+
],
1371
+
"engines": {
1372
+
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
1373
+
}
1374
+
},
1375
+
"node_modules/function-bind": {
1376
+
"version": "1.1.2",
1377
+
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
1378
+
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
1379
+
"license": "MIT",
1380
+
"funding": {
1381
+
"url": "https://github.com/sponsors/ljharb"
1382
+
}
1383
+
},
1384
+
"node_modules/get-intrinsic": {
1385
+
"version": "1.3.0",
1386
+
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
1387
+
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
1388
+
"license": "MIT",
1389
+
"dependencies": {
1390
+
"call-bind-apply-helpers": "^1.0.2",
1391
+
"es-define-property": "^1.0.1",
1392
+
"es-errors": "^1.3.0",
1393
+
"es-object-atoms": "^1.1.1",
1394
+
"function-bind": "^1.1.2",
1395
+
"get-proto": "^1.0.1",
1396
+
"gopd": "^1.2.0",
1397
+
"has-symbols": "^1.1.0",
1398
+
"hasown": "^2.0.2",
1399
+
"math-intrinsics": "^1.1.0"
1400
+
},
1401
+
"engines": {
1402
+
"node": ">= 0.4"
1403
+
},
1404
+
"funding": {
1405
+
"url": "https://github.com/sponsors/ljharb"
1406
+
}
1407
+
},
1408
+
"node_modules/get-proto": {
1409
+
"version": "1.0.1",
1410
+
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
1411
+
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
1412
+
"license": "MIT",
1413
+
"dependencies": {
1414
+
"dunder-proto": "^1.0.1",
1415
+
"es-object-atoms": "^1.0.0"
1416
+
},
1417
+
"engines": {
1418
+
"node": ">= 0.4"
1419
+
}
1420
+
},
1421
+
"node_modules/get-tsconfig": {
1422
+
"version": "4.13.0",
1423
+
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.0.tgz",
1424
+
"integrity": "sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==",
1425
+
"dev": true,
1426
+
"license": "MIT",
1427
+
"dependencies": {
1428
+
"resolve-pkg-maps": "^1.0.0"
1429
+
},
1430
+
"funding": {
1431
+
"url": "https://github.com/privatenumber/get-tsconfig?sponsor=1"
1432
+
}
1433
+
},
1434
+
"node_modules/github-from-package": {
1435
+
"version": "0.0.0",
1436
+
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
1437
+
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==",
1438
+
"license": "MIT"
1439
+
},
1440
+
"node_modules/gopd": {
1441
+
"version": "1.2.0",
1442
+
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
1443
+
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
1444
+
"license": "MIT",
1445
+
"engines": {
1446
+
"node": ">= 0.4"
1447
+
},
1448
+
"funding": {
1449
+
"url": "https://github.com/sponsors/ljharb"
1450
+
}
1451
+
},
1452
+
"node_modules/has-symbols": {
1453
+
"version": "1.1.0",
1454
+
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
1455
+
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
1456
+
"license": "MIT",
1457
+
"engines": {
1458
+
"node": ">= 0.4"
1459
+
},
1460
+
"funding": {
1461
+
"url": "https://github.com/sponsors/ljharb"
1462
+
}
1463
+
},
1464
+
"node_modules/hasown": {
1465
+
"version": "2.0.2",
1466
+
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
1467
+
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
1468
+
"license": "MIT",
1469
+
"dependencies": {
1470
+
"function-bind": "^1.1.2"
1471
+
},
1472
+
"engines": {
1473
+
"node": ">= 0.4"
1474
+
}
1475
+
},
1476
+
"node_modules/http-errors": {
1477
+
"version": "2.0.1",
1478
+
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz",
1479
+
"integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==",
1480
+
"license": "MIT",
1481
+
"dependencies": {
1482
+
"depd": "~2.0.0",
1483
+
"inherits": "~2.0.4",
1484
+
"setprototypeof": "~1.2.0",
1485
+
"statuses": "~2.0.2",
1486
+
"toidentifier": "~1.0.1"
1487
+
},
1488
+
"engines": {
1489
+
"node": ">= 0.8"
1490
+
},
1491
+
"funding": {
1492
+
"type": "opencollective",
1493
+
"url": "https://opencollective.com/express"
1494
+
}
1495
+
},
1496
+
"node_modules/iconv-lite": {
1497
+
"version": "0.7.0",
1498
+
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz",
1499
+
"integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==",
1500
+
"license": "MIT",
1501
+
"dependencies": {
1502
+
"safer-buffer": ">= 2.1.2 < 3.0.0"
1503
+
},
1504
+
"engines": {
1505
+
"node": ">=0.10.0"
1506
+
},
1507
+
"funding": {
1508
+
"type": "opencollective",
1509
+
"url": "https://opencollective.com/express"
1510
+
}
1511
+
},
1512
+
"node_modules/ieee754": {
1513
+
"version": "1.2.1",
1514
+
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
1515
+
"integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
1516
+
"funding": [
1517
+
{
1518
+
"type": "github",
1519
+
"url": "https://github.com/sponsors/feross"
1520
+
},
1521
+
{
1522
+
"type": "patreon",
1523
+
"url": "https://www.patreon.com/feross"
1524
+
},
1525
+
{
1526
+
"type": "consulting",
1527
+
"url": "https://feross.org/support"
1528
+
}
1529
+
],
1530
+
"license": "BSD-3-Clause"
1531
+
},
1532
+
"node_modules/inherits": {
1533
+
"version": "2.0.4",
1534
+
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
1535
+
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
1536
+
"license": "ISC"
1537
+
},
1538
+
"node_modules/ini": {
1539
+
"version": "1.3.8",
1540
+
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
1541
+
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
1542
+
"license": "ISC"
1543
+
},
1544
+
"node_modules/ipaddr.js": {
1545
+
"version": "2.3.0",
1546
+
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz",
1547
+
"integrity": "sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==",
1548
+
"license": "MIT",
1549
+
"engines": {
1550
+
"node": ">= 10"
1551
+
}
1552
+
},
1553
+
"node_modules/iron-session": {
1554
+
"version": "8.0.4",
1555
+
"resolved": "https://registry.npmjs.org/iron-session/-/iron-session-8.0.4.tgz",
1556
+
"integrity": "sha512-9ivNnaKOd08osD0lJ3i6If23GFS2LsxyMU8Gf/uBUEgm8/8CC1hrrCHFDpMo3IFbpBgwoo/eairRsaD3c5itxA==",
1557
+
"funding": [
1558
+
"https://github.com/sponsors/vvo",
1559
+
"https://github.com/sponsors/brc-dd"
1560
+
],
1561
+
"license": "MIT",
1562
+
"dependencies": {
1563
+
"cookie": "^0.7.2",
1564
+
"iron-webcrypto": "^1.2.1",
1565
+
"uncrypto": "^0.1.3"
1566
+
}
1567
+
},
1568
+
"node_modules/iron-webcrypto": {
1569
+
"version": "1.2.1",
1570
+
"resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz",
1571
+
"integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==",
1572
+
"license": "MIT",
1573
+
"funding": {
1574
+
"url": "https://github.com/sponsors/brc-dd"
1575
+
}
1576
+
},
1577
+
"node_modules/is-promise": {
1578
+
"version": "4.0.0",
1579
+
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz",
1580
+
"integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==",
1581
+
"license": "MIT"
1582
+
},
1583
+
"node_modules/iso-datestring-validator": {
1584
+
"version": "2.2.2",
1585
+
"resolved": "https://registry.npmjs.org/iso-datestring-validator/-/iso-datestring-validator-2.2.2.tgz",
1586
+
"integrity": "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==",
1587
+
"license": "MIT"
1588
+
},
1589
+
"node_modules/jose": {
1590
+
"version": "5.10.0",
1591
+
"resolved": "https://registry.npmjs.org/jose/-/jose-5.10.0.tgz",
1592
+
"integrity": "sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==",
1593
+
"license": "MIT",
1594
+
"funding": {
1595
+
"url": "https://github.com/sponsors/panva"
1596
+
}
1597
+
},
1598
+
"node_modules/lru-cache": {
1599
+
"version": "10.4.3",
1600
+
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
1601
+
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
1602
+
"license": "ISC"
1603
+
},
1604
+
"node_modules/math-intrinsics": {
1605
+
"version": "1.1.0",
1606
+
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
1607
+
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
1608
+
"license": "MIT",
1609
+
"engines": {
1610
+
"node": ">= 0.4"
1611
+
}
1612
+
},
1613
+
"node_modules/media-typer": {
1614
+
"version": "1.1.0",
1615
+
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
1616
+
"integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==",
1617
+
"license": "MIT",
1618
+
"engines": {
1619
+
"node": ">= 0.8"
1620
+
}
1621
+
},
1622
+
"node_modules/merge-descriptors": {
1623
+
"version": "2.0.0",
1624
+
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz",
1625
+
"integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==",
1626
+
"license": "MIT",
1627
+
"engines": {
1628
+
"node": ">=18"
1629
+
},
1630
+
"funding": {
1631
+
"url": "https://github.com/sponsors/sindresorhus"
1632
+
}
1633
+
},
1634
+
"node_modules/mime-db": {
1635
+
"version": "1.54.0",
1636
+
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
1637
+
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
1638
+
"license": "MIT",
1639
+
"engines": {
1640
+
"node": ">= 0.6"
1641
+
}
1642
+
},
1643
+
"node_modules/mime-types": {
1644
+
"version": "3.0.2",
1645
+
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz",
1646
+
"integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==",
1647
+
"license": "MIT",
1648
+
"dependencies": {
1649
+
"mime-db": "^1.54.0"
1650
+
},
1651
+
"engines": {
1652
+
"node": ">=18"
1653
+
},
1654
+
"funding": {
1655
+
"type": "opencollective",
1656
+
"url": "https://opencollective.com/express"
1657
+
}
1658
+
},
1659
+
"node_modules/mimic-response": {
1660
+
"version": "3.1.0",
1661
+
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
1662
+
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
1663
+
"license": "MIT",
1664
+
"engines": {
1665
+
"node": ">=10"
1666
+
},
1667
+
"funding": {
1668
+
"url": "https://github.com/sponsors/sindresorhus"
1669
+
}
1670
+
},
1671
+
"node_modules/minimist": {
1672
+
"version": "1.2.8",
1673
+
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
1674
+
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
1675
+
"license": "MIT",
1676
+
"funding": {
1677
+
"url": "https://github.com/sponsors/ljharb"
1678
+
}
1679
+
},
1680
+
"node_modules/mkdirp-classic": {
1681
+
"version": "0.5.3",
1682
+
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
1683
+
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==",
1684
+
"license": "MIT"
1685
+
},
1686
+
"node_modules/ms": {
1687
+
"version": "2.1.3",
1688
+
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1689
+
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
1690
+
"license": "MIT"
1691
+
},
1692
+
"node_modules/multiformats": {
1693
+
"version": "9.9.0",
1694
+
"resolved": "https://registry.npmjs.org/multiformats/-/multiformats-9.9.0.tgz",
1695
+
"integrity": "sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==",
1696
+
"license": "(Apache-2.0 AND MIT)"
1697
+
},
1698
+
"node_modules/napi-build-utils": {
1699
+
"version": "2.0.0",
1700
+
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz",
1701
+
"integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==",
1702
+
"license": "MIT"
1703
+
},
1704
+
"node_modules/negotiator": {
1705
+
"version": "1.0.0",
1706
+
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz",
1707
+
"integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==",
1708
+
"license": "MIT",
1709
+
"engines": {
1710
+
"node": ">= 0.6"
1711
+
}
1712
+
},
1713
+
"node_modules/node-abi": {
1714
+
"version": "3.85.0",
1715
+
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.85.0.tgz",
1716
+
"integrity": "sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==",
1717
+
"license": "MIT",
1718
+
"dependencies": {
1719
+
"semver": "^7.3.5"
1720
+
},
1721
+
"engines": {
1722
+
"node": ">=10"
1723
+
}
1724
+
},
1725
+
"node_modules/object-inspect": {
1726
+
"version": "1.13.4",
1727
+
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
1728
+
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
1729
+
"license": "MIT",
1730
+
"engines": {
1731
+
"node": ">= 0.4"
1732
+
},
1733
+
"funding": {
1734
+
"url": "https://github.com/sponsors/ljharb"
1735
+
}
1736
+
},
1737
+
"node_modules/on-finished": {
1738
+
"version": "2.4.1",
1739
+
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
1740
+
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
1741
+
"license": "MIT",
1742
+
"dependencies": {
1743
+
"ee-first": "1.1.1"
1744
+
},
1745
+
"engines": {
1746
+
"node": ">= 0.8"
1747
+
}
1748
+
},
1749
+
"node_modules/once": {
1750
+
"version": "1.4.0",
1751
+
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
1752
+
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
1753
+
"license": "ISC",
1754
+
"dependencies": {
1755
+
"wrappy": "1"
1756
+
}
1757
+
},
1758
+
"node_modules/parseurl": {
1759
+
"version": "1.3.3",
1760
+
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
1761
+
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
1762
+
"license": "MIT",
1763
+
"engines": {
1764
+
"node": ">= 0.8"
1765
+
}
1766
+
},
1767
+
"node_modules/path-to-regexp": {
1768
+
"version": "8.3.0",
1769
+
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.3.0.tgz",
1770
+
"integrity": "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==",
1771
+
"license": "MIT",
1772
+
"funding": {
1773
+
"type": "opencollective",
1774
+
"url": "https://opencollective.com/express"
1775
+
}
1776
+
},
1777
+
"node_modules/prebuild-install": {
1778
+
"version": "7.1.3",
1779
+
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz",
1780
+
"integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
1781
+
"license": "MIT",
1782
+
"dependencies": {
1783
+
"detect-libc": "^2.0.0",
1784
+
"expand-template": "^2.0.3",
1785
+
"github-from-package": "0.0.0",
1786
+
"minimist": "^1.2.3",
1787
+
"mkdirp-classic": "^0.5.3",
1788
+
"napi-build-utils": "^2.0.0",
1789
+
"node-abi": "^3.3.0",
1790
+
"pump": "^3.0.0",
1791
+
"rc": "^1.2.7",
1792
+
"simple-get": "^4.0.0",
1793
+
"tar-fs": "^2.0.0",
1794
+
"tunnel-agent": "^0.6.0"
1795
+
},
1796
+
"bin": {
1797
+
"prebuild-install": "bin.js"
1798
+
},
1799
+
"engines": {
1800
+
"node": ">=10"
1801
+
}
1802
+
},
1803
+
"node_modules/proxy-addr": {
1804
+
"version": "2.0.7",
1805
+
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
1806
+
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
1807
+
"license": "MIT",
1808
+
"dependencies": {
1809
+
"forwarded": "0.2.0",
1810
+
"ipaddr.js": "1.9.1"
1811
+
},
1812
+
"engines": {
1813
+
"node": ">= 0.10"
1814
+
}
1815
+
},
1816
+
"node_modules/proxy-addr/node_modules/ipaddr.js": {
1817
+
"version": "1.9.1",
1818
+
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
1819
+
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
1820
+
"license": "MIT",
1821
+
"engines": {
1822
+
"node": ">= 0.10"
1823
+
}
1824
+
},
1825
+
"node_modules/pump": {
1826
+
"version": "3.0.3",
1827
+
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz",
1828
+
"integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==",
1829
+
"license": "MIT",
1830
+
"dependencies": {
1831
+
"end-of-stream": "^1.1.0",
1832
+
"once": "^1.3.1"
1833
+
}
1834
+
},
1835
+
"node_modules/qs": {
1836
+
"version": "6.14.0",
1837
+
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
1838
+
"integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
1839
+
"license": "BSD-3-Clause",
1840
+
"dependencies": {
1841
+
"side-channel": "^1.1.0"
1842
+
},
1843
+
"engines": {
1844
+
"node": ">=0.6"
1845
+
},
1846
+
"funding": {
1847
+
"url": "https://github.com/sponsors/ljharb"
1848
+
}
1849
+
},
1850
+
"node_modules/range-parser": {
1851
+
"version": "1.2.1",
1852
+
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
1853
+
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
1854
+
"license": "MIT",
1855
+
"engines": {
1856
+
"node": ">= 0.6"
1857
+
}
1858
+
},
1859
+
"node_modules/raw-body": {
1860
+
"version": "3.0.2",
1861
+
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz",
1862
+
"integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==",
1863
+
"license": "MIT",
1864
+
"dependencies": {
1865
+
"bytes": "~3.1.2",
1866
+
"http-errors": "~2.0.1",
1867
+
"iconv-lite": "~0.7.0",
1868
+
"unpipe": "~1.0.0"
1869
+
},
1870
+
"engines": {
1871
+
"node": ">= 0.10"
1872
+
}
1873
+
},
1874
+
"node_modules/rc": {
1875
+
"version": "1.2.8",
1876
+
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
1877
+
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
1878
+
"license": "(BSD-2-Clause OR MIT OR Apache-2.0)",
1879
+
"dependencies": {
1880
+
"deep-extend": "^0.6.0",
1881
+
"ini": "~1.3.0",
1882
+
"minimist": "^1.2.0",
1883
+
"strip-json-comments": "~2.0.1"
1884
+
},
1885
+
"bin": {
1886
+
"rc": "cli.js"
1887
+
}
1888
+
},
1889
+
"node_modules/readable-stream": {
1890
+
"version": "3.6.2",
1891
+
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
1892
+
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
1893
+
"license": "MIT",
1894
+
"dependencies": {
1895
+
"inherits": "^2.0.3",
1896
+
"string_decoder": "^1.1.1",
1897
+
"util-deprecate": "^1.0.1"
1898
+
},
1899
+
"engines": {
1900
+
"node": ">= 6"
1901
+
}
1902
+
},
1903
+
"node_modules/resolve-pkg-maps": {
1904
+
"version": "1.0.0",
1905
+
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
1906
+
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
1907
+
"dev": true,
1908
+
"license": "MIT",
1909
+
"funding": {
1910
+
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
1911
+
}
1912
+
},
1913
+
"node_modules/router": {
1914
+
"version": "2.2.0",
1915
+
"resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz",
1916
+
"integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==",
1917
+
"license": "MIT",
1918
+
"dependencies": {
1919
+
"debug": "^4.4.0",
1920
+
"depd": "^2.0.0",
1921
+
"is-promise": "^4.0.0",
1922
+
"parseurl": "^1.3.3",
1923
+
"path-to-regexp": "^8.0.0"
1924
+
},
1925
+
"engines": {
1926
+
"node": ">= 18"
1927
+
}
1928
+
},
1929
+
"node_modules/safe-buffer": {
1930
+
"version": "5.2.1",
1931
+
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1932
+
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
1933
+
"funding": [
1934
+
{
1935
+
"type": "github",
1936
+
"url": "https://github.com/sponsors/feross"
1937
+
},
1938
+
{
1939
+
"type": "patreon",
1940
+
"url": "https://www.patreon.com/feross"
1941
+
},
1942
+
{
1943
+
"type": "consulting",
1944
+
"url": "https://feross.org/support"
1945
+
}
1946
+
],
1947
+
"license": "MIT"
1948
+
},
1949
+
"node_modules/safer-buffer": {
1950
+
"version": "2.1.2",
1951
+
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1952
+
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
1953
+
"license": "MIT"
1954
+
},
1955
+
"node_modules/semver": {
1956
+
"version": "7.7.3",
1957
+
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
1958
+
"integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
1959
+
"license": "ISC",
1960
+
"bin": {
1961
+
"semver": "bin/semver.js"
1962
+
},
1963
+
"engines": {
1964
+
"node": ">=10"
1965
+
}
1966
+
},
1967
+
"node_modules/send": {
1968
+
"version": "1.2.0",
1969
+
"resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
1970
+
"integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
1971
+
"license": "MIT",
1972
+
"dependencies": {
1973
+
"debug": "^4.3.5",
1974
+
"encodeurl": "^2.0.0",
1975
+
"escape-html": "^1.0.3",
1976
+
"etag": "^1.8.1",
1977
+
"fresh": "^2.0.0",
1978
+
"http-errors": "^2.0.0",
1979
+
"mime-types": "^3.0.1",
1980
+
"ms": "^2.1.3",
1981
+
"on-finished": "^2.4.1",
1982
+
"range-parser": "^1.2.1",
1983
+
"statuses": "^2.0.1"
1984
+
},
1985
+
"engines": {
1986
+
"node": ">= 18"
1987
+
}
1988
+
},
1989
+
"node_modules/serve-static": {
1990
+
"version": "2.2.0",
1991
+
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
1992
+
"integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
1993
+
"license": "MIT",
1994
+
"dependencies": {
1995
+
"encodeurl": "^2.0.0",
1996
+
"escape-html": "^1.0.3",
1997
+
"parseurl": "^1.3.3",
1998
+
"send": "^1.2.0"
1999
+
},
2000
+
"engines": {
2001
+
"node": ">= 18"
2002
+
}
2003
+
},
2004
+
"node_modules/setprototypeof": {
2005
+
"version": "1.2.0",
2006
+
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
2007
+
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
2008
+
"license": "ISC"
2009
+
},
2010
+
"node_modules/side-channel": {
2011
+
"version": "1.1.0",
2012
+
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
2013
+
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
2014
+
"license": "MIT",
2015
+
"dependencies": {
2016
+
"es-errors": "^1.3.0",
2017
+
"object-inspect": "^1.13.3",
2018
+
"side-channel-list": "^1.0.0",
2019
+
"side-channel-map": "^1.0.1",
2020
+
"side-channel-weakmap": "^1.0.2"
2021
+
},
2022
+
"engines": {
2023
+
"node": ">= 0.4"
2024
+
},
2025
+
"funding": {
2026
+
"url": "https://github.com/sponsors/ljharb"
2027
+
}
2028
+
},
2029
+
"node_modules/side-channel-list": {
2030
+
"version": "1.0.0",
2031
+
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
2032
+
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
2033
+
"license": "MIT",
2034
+
"dependencies": {
2035
+
"es-errors": "^1.3.0",
2036
+
"object-inspect": "^1.13.3"
2037
+
},
2038
+
"engines": {
2039
+
"node": ">= 0.4"
2040
+
},
2041
+
"funding": {
2042
+
"url": "https://github.com/sponsors/ljharb"
2043
+
}
2044
+
},
2045
+
"node_modules/side-channel-map": {
2046
+
"version": "1.0.1",
2047
+
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
2048
+
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
2049
+
"license": "MIT",
2050
+
"dependencies": {
2051
+
"call-bound": "^1.0.2",
2052
+
"es-errors": "^1.3.0",
2053
+
"get-intrinsic": "^1.2.5",
2054
+
"object-inspect": "^1.13.3"
2055
+
},
2056
+
"engines": {
2057
+
"node": ">= 0.4"
2058
+
},
2059
+
"funding": {
2060
+
"url": "https://github.com/sponsors/ljharb"
2061
+
}
2062
+
},
2063
+
"node_modules/side-channel-weakmap": {
2064
+
"version": "1.0.2",
2065
+
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
2066
+
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
2067
+
"license": "MIT",
2068
+
"dependencies": {
2069
+
"call-bound": "^1.0.2",
2070
+
"es-errors": "^1.3.0",
2071
+
"get-intrinsic": "^1.2.5",
2072
+
"object-inspect": "^1.13.3",
2073
+
"side-channel-map": "^1.0.1"
2074
+
},
2075
+
"engines": {
2076
+
"node": ">= 0.4"
2077
+
},
2078
+
"funding": {
2079
+
"url": "https://github.com/sponsors/ljharb"
2080
+
}
2081
+
},
2082
+
"node_modules/simple-concat": {
2083
+
"version": "1.0.1",
2084
+
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz",
2085
+
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==",
2086
+
"funding": [
2087
+
{
2088
+
"type": "github",
2089
+
"url": "https://github.com/sponsors/feross"
2090
+
},
2091
+
{
2092
+
"type": "patreon",
2093
+
"url": "https://www.patreon.com/feross"
2094
+
},
2095
+
{
2096
+
"type": "consulting",
2097
+
"url": "https://feross.org/support"
2098
+
}
2099
+
],
2100
+
"license": "MIT"
2101
+
},
2102
+
"node_modules/simple-get": {
2103
+
"version": "4.0.1",
2104
+
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
2105
+
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
2106
+
"funding": [
2107
+
{
2108
+
"type": "github",
2109
+
"url": "https://github.com/sponsors/feross"
2110
+
},
2111
+
{
2112
+
"type": "patreon",
2113
+
"url": "https://www.patreon.com/feross"
2114
+
},
2115
+
{
2116
+
"type": "consulting",
2117
+
"url": "https://feross.org/support"
2118
+
}
2119
+
],
2120
+
"license": "MIT",
2121
+
"dependencies": {
2122
+
"decompress-response": "^6.0.0",
2123
+
"once": "^1.3.1",
2124
+
"simple-concat": "^1.0.0"
2125
+
}
2126
+
},
2127
+
"node_modules/statuses": {
2128
+
"version": "2.0.2",
2129
+
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
2130
+
"integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
2131
+
"license": "MIT",
2132
+
"engines": {
2133
+
"node": ">= 0.8"
2134
+
}
2135
+
},
2136
+
"node_modules/string_decoder": {
2137
+
"version": "1.3.0",
2138
+
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
2139
+
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
2140
+
"license": "MIT",
2141
+
"dependencies": {
2142
+
"safe-buffer": "~5.2.0"
2143
+
}
2144
+
},
2145
+
"node_modules/strip-json-comments": {
2146
+
"version": "2.0.1",
2147
+
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
2148
+
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
2149
+
"license": "MIT",
2150
+
"engines": {
2151
+
"node": ">=0.10.0"
2152
+
}
2153
+
},
2154
+
"node_modules/tar-fs": {
2155
+
"version": "2.1.4",
2156
+
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz",
2157
+
"integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==",
2158
+
"license": "MIT",
2159
+
"dependencies": {
2160
+
"chownr": "^1.1.1",
2161
+
"mkdirp-classic": "^0.5.2",
2162
+
"pump": "^3.0.0",
2163
+
"tar-stream": "^2.1.4"
2164
+
}
2165
+
},
2166
+
"node_modules/tar-stream": {
2167
+
"version": "2.2.0",
2168
+
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
2169
+
"integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
2170
+
"license": "MIT",
2171
+
"dependencies": {
2172
+
"bl": "^4.0.3",
2173
+
"end-of-stream": "^1.4.1",
2174
+
"fs-constants": "^1.0.0",
2175
+
"inherits": "^2.0.3",
2176
+
"readable-stream": "^3.1.1"
2177
+
},
2178
+
"engines": {
2179
+
"node": ">=6"
2180
+
}
2181
+
},
2182
+
"node_modules/tlds": {
2183
+
"version": "1.261.0",
2184
+
"resolved": "https://registry.npmjs.org/tlds/-/tlds-1.261.0.tgz",
2185
+
"integrity": "sha512-QXqwfEl9ddlGBaRFXIvNKK6OhipSiLXuRuLJX5DErz0o0Q0rYxulWLdFryTkV5PkdZct5iMInwYEGe/eR++1AA==",
2186
+
"license": "MIT",
2187
+
"bin": {
2188
+
"tlds": "bin.js"
2189
+
}
2190
+
},
2191
+
"node_modules/toidentifier": {
2192
+
"version": "1.0.1",
2193
+
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
2194
+
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
2195
+
"license": "MIT",
2196
+
"engines": {
2197
+
"node": ">=0.6"
2198
+
}
2199
+
},
2200
+
"node_modules/tslib": {
2201
+
"version": "2.8.1",
2202
+
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
2203
+
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
2204
+
"license": "0BSD"
2205
+
},
2206
+
"node_modules/tsx": {
2207
+
"version": "4.20.6",
2208
+
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.6.tgz",
2209
+
"integrity": "sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==",
2210
+
"dev": true,
2211
+
"license": "MIT",
2212
+
"dependencies": {
2213
+
"esbuild": "~0.25.0",
2214
+
"get-tsconfig": "^4.7.5"
2215
+
},
2216
+
"bin": {
2217
+
"tsx": "dist/cli.mjs"
2218
+
},
2219
+
"engines": {
2220
+
"node": ">=18.0.0"
2221
+
},
2222
+
"optionalDependencies": {
2223
+
"fsevents": "~2.3.3"
2224
+
}
2225
+
},
2226
+
"node_modules/tunnel-agent": {
2227
+
"version": "0.6.0",
2228
+
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
2229
+
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
2230
+
"license": "Apache-2.0",
2231
+
"dependencies": {
2232
+
"safe-buffer": "^5.0.1"
2233
+
},
2234
+
"engines": {
2235
+
"node": "*"
2236
+
}
2237
+
},
2238
+
"node_modules/type-is": {
2239
+
"version": "2.0.1",
2240
+
"resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz",
2241
+
"integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==",
2242
+
"license": "MIT",
2243
+
"dependencies": {
2244
+
"content-type": "^1.0.5",
2245
+
"media-typer": "^1.1.0",
2246
+
"mime-types": "^3.0.0"
2247
+
},
2248
+
"engines": {
2249
+
"node": ">= 0.6"
2250
+
}
2251
+
},
2252
+
"node_modules/typescript": {
2253
+
"version": "5.9.3",
2254
+
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
2255
+
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
2256
+
"dev": true,
2257
+
"license": "Apache-2.0",
2258
+
"bin": {
2259
+
"tsc": "bin/tsc",
2260
+
"tsserver": "bin/tsserver"
2261
+
},
2262
+
"engines": {
2263
+
"node": ">=14.17"
2264
+
}
2265
+
},
2266
+
"node_modules/uint8arrays": {
2267
+
"version": "3.0.0",
2268
+
"resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-3.0.0.tgz",
2269
+
"integrity": "sha512-HRCx0q6O9Bfbp+HHSfQQKD7wU70+lydKVt4EghkdOvlK/NlrF90z+eXV34mUd48rNvVJXwkrMSPpCATkct8fJA==",
2270
+
"license": "MIT",
2271
+
"dependencies": {
2272
+
"multiformats": "^9.4.2"
2273
+
}
2274
+
},
2275
+
"node_modules/uncrypto": {
2276
+
"version": "0.1.3",
2277
+
"resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz",
2278
+
"integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==",
2279
+
"license": "MIT"
2280
+
},
2281
+
"node_modules/undici": {
2282
+
"version": "6.22.0",
2283
+
"resolved": "https://registry.npmjs.org/undici/-/undici-6.22.0.tgz",
2284
+
"integrity": "sha512-hU/10obOIu62MGYjdskASR3CUAiYaFTtC9Pa6vHyf//mAipSvSQg6od2CnJswq7fvzNS3zJhxoRkgNVaHurWKw==",
2285
+
"license": "MIT",
2286
+
"engines": {
2287
+
"node": ">=18.17"
2288
+
}
2289
+
},
2290
+
"node_modules/undici-types": {
2291
+
"version": "7.16.0",
2292
+
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
2293
+
"integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
2294
+
"dev": true,
2295
+
"license": "MIT"
2296
+
},
2297
+
"node_modules/unicode-segmenter": {
2298
+
"version": "0.14.0",
2299
+
"resolved": "https://registry.npmjs.org/unicode-segmenter/-/unicode-segmenter-0.14.0.tgz",
2300
+
"integrity": "sha512-AH4lhPCJANUnSLEKnM4byboctePJzltF4xj8b+NbNiYeAkAXGh7px2K/4NANFp7dnr6+zB3e6HLu8Jj8SKyvYg==",
2301
+
"license": "MIT"
2302
+
},
2303
+
"node_modules/unpipe": {
2304
+
"version": "1.0.0",
2305
+
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
2306
+
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
2307
+
"license": "MIT",
2308
+
"engines": {
2309
+
"node": ">= 0.8"
2310
+
}
2311
+
},
2312
+
"node_modules/util-deprecate": {
2313
+
"version": "1.0.2",
2314
+
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
2315
+
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
2316
+
"license": "MIT"
2317
+
},
2318
+
"node_modules/vary": {
2319
+
"version": "1.1.2",
2320
+
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
2321
+
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
2322
+
"license": "MIT",
2323
+
"engines": {
2324
+
"node": ">= 0.8"
2325
+
}
2326
+
},
2327
+
"node_modules/wrappy": {
2328
+
"version": "1.0.2",
2329
+
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
2330
+
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
2331
+
"license": "ISC"
2332
+
},
2333
+
"node_modules/zod": {
2334
+
"version": "3.25.76",
2335
+
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
2336
+
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
2337
+
"license": "MIT",
2338
+
"funding": {
2339
+
"url": "https://github.com/sponsors/colinhacks"
2340
+
}
2341
+
}
2342
+
}
2343
+
}
+28
package.json
+28
package.json
···
1
+
{
2
+
"name": "anproto-over-atproto",
3
+
"version": "1.0.0",
4
+
"description": "",
5
+
"main": "index.js",
6
+
"scripts": {
7
+
"dev": "tsx watch src/index.ts",
8
+
"test": "echo \"Error: no test specified\" && exit 1"
9
+
},
10
+
"keywords": [],
11
+
"author": "",
12
+
"license": "ISC",
13
+
"type": "commonjs",
14
+
"dependencies": {
15
+
"@atproto/api": "^0.18.3",
16
+
"@atproto/oauth-client-node": "^0.3.11",
17
+
"better-sqlite3": "^12.5.0",
18
+
"express": "^5.1.0",
19
+
"iron-session": "^8.0.4"
20
+
},
21
+
"devDependencies": {
22
+
"@types/better-sqlite3": "^7.6.13",
23
+
"@types/express": "^5.0.5",
24
+
"@types/node": "^24.10.1",
25
+
"tsx": "^4.20.6",
26
+
"typescript": "^5.9.3"
27
+
}
28
+
}
+27
src/client.ts
+27
src/client.ts
···
1
+
import { NodeOAuthClient } from '@atproto/oauth-client-node'
2
+
import { SessionStore, StateStore } from './storage'
3
+
4
+
export const createClient = async () => {
5
+
return new NodeOAuthClient({
6
+
// This metadata describes your OAuth client to the PDS.
7
+
clientMetadata: {
8
+
client_name: 'ATProto OAuth Test',
9
+
// For localhost development, we use a "Loopback Client ID".
10
+
// This allows us to test without a public domain or https.
11
+
// In production, this should be the URL where your metadata is served (e.g., https://myapp.com/client-metadata.json).
12
+
client_id: 'http://localhost?redirect_uri=http%3A%2F%2F127.0.0.1%3A3000%2Foauth%2Fcallback&scope=atproto%20repo%3Acom.anproto.message.v1%3Faction%3Dcreate',
13
+
client_uri: 'http://localhost:3000',
14
+
redirect_uris: ['http://127.0.0.1:3000/oauth/callback'],
15
+
scope: 'atproto repo:com.anproto.message.v1?action=create',
16
+
grant_types: ['authorization_code', 'refresh_token'],
17
+
response_types: ['code'],
18
+
application_type: 'web',
19
+
token_endpoint_auth_method: 'none',
20
+
// DPoP (Demonstrating Proof-of-Possession) binds tokens to a private key, preventing replay attacks if the token is stolen.
21
+
// This is highly recommended for security.
22
+
dpop_bound_access_tokens: true,
23
+
},
24
+
stateStore: new StateStore(),
25
+
sessionStore: new SessionStore(),
26
+
})
27
+
}
+16
src/db.ts
+16
src/db.ts
···
1
+
import Database from 'better-sqlite3'
2
+
3
+
// A simple SQLite database for persisting sessions and auth state.
4
+
// In a production environment, you might use PostgreSQL, Redis, or another durable store.
5
+
export const db = new Database('db.sqlite')
6
+
7
+
db.exec(`
8
+
CREATE TABLE IF NOT EXISTS auth_state (
9
+
key TEXT PRIMARY KEY,
10
+
state TEXT NOT NULL
11
+
);
12
+
CREATE TABLE IF NOT EXISTS auth_session (
13
+
key TEXT PRIMARY KEY,
14
+
session TEXT NOT NULL
15
+
);
16
+
`)
+583
src/index.ts
+583
src/index.ts
···
1
+
import express from 'express'
2
+
import { createClient } from './client'
3
+
import { getIronSession } from 'iron-session'
4
+
import { Agent } from '@atproto/api'
5
+
import { Lexicons, LexiconDoc, ValidationError } from '@atproto/lexicon'
6
+
import path from 'path'
7
+
import fs from 'fs'
8
+
import { pathToFileURL } from 'url'
9
+
10
+
// Types for the session data stored in the browser cookie
11
+
declare module 'iron-session' {
12
+
interface IronSessionData {
13
+
did?: string
14
+
}
15
+
}
16
+
17
+
const app = express()
18
+
const port = 3000
19
+
const messageLexiconPath = path.join(__dirname, '../lexicons/com.anproto.message.json')
20
+
const messageLexicon = JSON.parse(fs.readFileSync(messageLexiconPath, 'utf8')) as LexiconDoc
21
+
const lexicons = new Lexicons([messageLexicon])
22
+
const messageLexUri = 'com.anproto.message.v1'
23
+
24
+
// Session configuration (cookie settings)
25
+
const sessionConfig = {
26
+
cookieName: 'atproto-oauth-session',
27
+
password: 'complex_password_at_least_32_characters_long', // REPLACE THIS in production!
28
+
cookieOptions: {
29
+
secure: process.env.NODE_ENV === 'production',
30
+
},
31
+
}
32
+
33
+
app.use(express.json({ limit: '10mb' }))
34
+
app.use(express.urlencoded({ extended: true, limit: '2mb' }))
35
+
app.use('/apds', express.static('apds'))
36
+
37
+
const run = async () => {
38
+
const client = await createClient()
39
+
40
+
app.get('/', async (req, res) => {
41
+
const session = await getIronSession(req, res, sessionConfig)
42
+
let profile: any = {}
43
+
let avatarUrl = ''
44
+
let handle = session.handle || ''
45
+
46
+
if (session.did) {
47
+
try {
48
+
const oauthSession = await client.restore(session.did)
49
+
if (!oauthSession) {
50
+
throw new Error('Could not restore OAuth session')
51
+
}
52
+
const agent = new Agent(oauthSession)
53
+
54
+
try {
55
+
const prof = await agent.getProfile({ actor: session.did })
56
+
profile = prof.data
57
+
handle = profile.handle ?? ''
58
+
avatarUrl = profile.avatar ?? ''
59
+
} catch (e) {
60
+
console.warn('Could not fetch profile via getProfile, falling back to record:', e)
61
+
}
62
+
63
+
if (!avatarUrl || !handle) {
64
+
try {
65
+
const { data } = await agent.com.atproto.repo.getRecord({
66
+
repo: session.did,
67
+
collection: 'app.bsky.actor.profile',
68
+
rkey: 'self',
69
+
})
70
+
const rec = data.value
71
+
profile = { ...rec, ...(profile || {}) }
72
+
if (rec?.avatar && !avatarUrl) {
73
+
const serviceUrl = new URL((agent as any).service?.toString() ?? 'https://bsky.social/')
74
+
const cid = rec.avatar.ref?.toString() ?? ''
75
+
if (cid) {
76
+
avatarUrl = new URL(`xrpc/com.atproto.sync.getBlob`, serviceUrl).toString()
77
+
avatarUrl += `?did=${encodeURIComponent(session.did!)}&cid=${encodeURIComponent(cid)}`
78
+
}
79
+
}
80
+
} catch (e) {
81
+
console.warn('Could not fetch profile record or construct avatar:', e)
82
+
}
83
+
}
84
+
} catch (err) {
85
+
console.error('Error processing session:', err)
86
+
session.destroy()
87
+
res.send(renderError(err))
88
+
return
89
+
}
90
+
}
91
+
92
+
res.send(
93
+
renderHome({
94
+
did: session.did,
95
+
handle,
96
+
avatarUrl,
97
+
}),
98
+
)
99
+
})
100
+
101
+
app.get('/oauth-client-metadata.json', (req, res) => {
102
+
res.json(client.clientMetadata)
103
+
})
104
+
105
+
app.post('/login', async (req, res) => {
106
+
const handle = req.body.handle
107
+
if (typeof handle !== 'string' || !handle) {
108
+
return res.status(400).send('Handle is required')
109
+
}
110
+
111
+
try {
112
+
const sess = await getIronSession(req, res, sessionConfig)
113
+
sess.pendingHandle = handle
114
+
await sess.save()
115
+
116
+
const url = await client.authorize(handle, {
117
+
// Request full atproto plus explicit write scope for com.anproto.message.v1
118
+
scope: 'atproto repo:com.anproto.message.v1?action=create',
119
+
})
120
+
res.redirect(url.toString())
121
+
} catch (err) {
122
+
console.error(err)
123
+
res.status(500).send('Error initiating login: ' + err)
124
+
}
125
+
})
126
+
127
+
app.get('/oauth/callback', async (req, res) => {
128
+
const params = new URLSearchParams(req.url.split('?')[1])
129
+
try {
130
+
const { session } = await client.callback(params)
131
+
132
+
const reqSession = await getIronSession(req, res, sessionConfig)
133
+
reqSession.did = session.did
134
+
if (!reqSession.handle && reqSession.pendingHandle) {
135
+
reqSession.handle = reqSession.pendingHandle
136
+
}
137
+
reqSession.pendingHandle = undefined
138
+
await reqSession.save()
139
+
140
+
res.redirect('/')
141
+
} catch (err) {
142
+
console.error(err)
143
+
res.status(500).send('Callback failed: ' + err)
144
+
}
145
+
})
146
+
147
+
app.post('/logout', async (req, res) => {
148
+
const session = await getIronSession(req, res, sessionConfig)
149
+
session.destroy()
150
+
res.redirect('/')
151
+
})
152
+
153
+
app.post('/publish', async (req, res) => {
154
+
const session = await getIronSession(req, res, sessionConfig)
155
+
if (!session.did) {
156
+
return res.status(401).json({ error: 'Not logged in' })
157
+
}
158
+
159
+
const { anmsg, blob, rkey, anhash: providedAnhash, blobhash: providedBlobhash } = req.body ?? {}
160
+
if (typeof anmsg !== 'string' || !anmsg.trim()) {
161
+
return res.status(400).json({ error: 'anmsg is required' })
162
+
}
163
+
const maxAnmsgLen = 20000
164
+
if (anmsg.length > maxAnmsgLen) {
165
+
return res.status(400).json({ error: 'anmsg too large' })
166
+
}
167
+
168
+
try {
169
+
const oauthSession = await client.restore(session.did)
170
+
if (!oauthSession) {
171
+
session.destroy()
172
+
return res.status(401).json({ error: 'Session expired' })
173
+
}
174
+
175
+
const agent = new Agent(oauthSession)
176
+
const an = await loadAn()
177
+
let finalBlobhash: string | undefined
178
+
let anblob: string | undefined
179
+
180
+
if (blob) {
181
+
if (typeof blob !== 'string') {
182
+
return res.status(400).json({ error: 'blob must be base64 string' })
183
+
}
184
+
const buf = Buffer.from(blob, 'base64')
185
+
if (!buf.length) {
186
+
return res.status(400).json({ error: 'blob decode failed' })
187
+
}
188
+
const maxBlobBytes = 6 * 1024 * 1024
189
+
if (buf.length > maxBlobBytes) {
190
+
return res.status(400).json({ error: 'blob too large (max 6MB)' })
191
+
}
192
+
anblob = blob
193
+
finalBlobhash = await an.hash(blob)
194
+
} else if (typeof providedBlobhash === 'string' && providedBlobhash.trim()) {
195
+
finalBlobhash = providedBlobhash.trim()
196
+
}
197
+
198
+
const anhash = await an.hash(anmsg)
199
+
if (providedAnhash && providedAnhash !== anhash) {
200
+
return res.status(400).json({ error: 'anhash does not match anmsg hash' })
201
+
}
202
+
const computedRkey = toBase64Url(anhash)
203
+
if (typeof rkey === 'string' && rkey.trim() && rkey.trim() !== computedRkey) {
204
+
return res.status(400).json({ error: 'rkey does not match anmsg hash' })
205
+
}
206
+
207
+
const record = {
208
+
$type: messageLexUri,
209
+
anmsg,
210
+
anhash,
211
+
...(anblob ? { anblob } : {}),
212
+
...(finalBlobhash ? { blobhash: finalBlobhash } : {}),
213
+
}
214
+
215
+
try {
216
+
lexicons.assertValidRecord(messageLexUri, record)
217
+
} catch (err) {
218
+
const message =
219
+
err instanceof ValidationError
220
+
? err.message
221
+
: err instanceof Error
222
+
? err.message
223
+
: 'Record failed lexicon validation'
224
+
return res.status(400).json({ error: message })
225
+
}
226
+
227
+
await agent.com.atproto.repo.createRecord({
228
+
repo: session.did,
229
+
collection: messageLexUri,
230
+
rkey: computedRkey,
231
+
record,
232
+
})
233
+
234
+
res.json({ ok: true, rkey: computedRkey })
235
+
} catch (err) {
236
+
console.error('Publish failed:', err)
237
+
res.status(500).json({ error: 'Publish failed', detail: String(err) })
238
+
}
239
+
})
240
+
241
+
app.listen(port, () => {
242
+
console.log(`Server running at http://localhost:${port}`)
243
+
})
244
+
}
245
+
246
+
function renderHome({
247
+
did,
248
+
handle,
249
+
avatarUrl,
250
+
}: {
251
+
did?: string
252
+
handle?: string
253
+
avatarUrl?: string
254
+
}) {
255
+
const loggedIn = Boolean(did)
256
+
const displayHandle =
257
+
handle ||
258
+
(did ? `${did.slice(0, 16)}…` : '')
259
+
260
+
return `
261
+
<!DOCTYPE html>
262
+
<html>
263
+
<head>
264
+
<title>ANProto over ATProto</title>
265
+
<style>
266
+
:root { --bg:#f7f7f8; --card:#fff; --border:#e3e3e6; --text:#111; --muted:#666; --accent:#111; }
267
+
* { box-sizing: border-box; }
268
+
body { font-family: "Inter", system-ui, -apple-system, sans-serif; background: var(--bg); color: var(--text); margin: 0; padding: 0; }
269
+
header { display: flex; justify-content: space-between; align-items: center; padding: 14px 18px; border-bottom: 1px solid var(--border); background: var(--card); position: sticky; top: 0; }
270
+
.brand { font-weight: 700; letter-spacing: -0.01em; }
271
+
.auth { display: flex; align-items: center; gap: 12px; }
272
+
.login-form { display: flex; align-items: center; gap: 8px; }
273
+
.login-form input { padding: 8px 10px; border: 1px solid var(--border); border-radius: 8px; min-width: 200px; }
274
+
.btn { cursor: pointer; border: 1px solid var(--border); background: var(--text); color: #fff; border-radius: 10px; padding: 8px 12px; font-weight: 600; }
275
+
.btn.secondary { background: #fff; color: var(--text); }
276
+
.user-chip { display: flex; align-items: center; gap: 10px; background: #fff; border: 1px solid var(--border); border-radius: 999px; padding: 6px 10px; }
277
+
.avatar { width: 32px; height: 32px; border-radius: 50%; object-fit: cover; border: 1px solid var(--border); background: #ddd; }
278
+
main { max-width: 960px; margin: 0 auto; padding: 24px 18px 40px; display: grid; gap: 20px; }
279
+
.card { background: var(--card); border: 1px solid var(--border); border-radius: 12px; padding: 16px; }
280
+
.composer textarea { width: 100%; min-height: 140px; padding: 12px; border: 1px solid var(--border); border-radius: 10px; font-size: 1rem; }
281
+
.composer .actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-top: 10px; }
282
+
.status { margin-top: 8px; font-size: 0.92rem; color: var(--muted); }
283
+
.muted { color: var(--muted); }
284
+
.feed-list { display: flex; flex-direction: column; gap: 12px; }
285
+
.feed-item { border: 1px solid var(--border); border-radius: 12px; padding: 12px; background: #fff; }
286
+
.feed-head { display: flex; justify-content: space-between; align-items: center; font-size: 0.9rem; color: var(--muted); }
287
+
.pill { background: #f0f0f2; border: 1px solid var(--border); border-radius: 999px; padding: 4px 10px; font-size: 0.85rem; }
288
+
.logout { margin-left: 8px; }
289
+
.row { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
290
+
</style>
291
+
</head>
292
+
<body>
293
+
<header>
294
+
<div class="brand">ANProto over ATProto</div>
295
+
<div class="auth">
296
+
${
297
+
loggedIn
298
+
? `
299
+
<div class="user-chip">
300
+
${
301
+
avatarUrl
302
+
? `<img class="avatar" src="${avatarUrl}" alt="avatar">`
303
+
: `<div class="avatar"></div>`
304
+
}
305
+
<div>
306
+
<div style="font-weight:600">${displayHandle}</div>
307
+
<div style="font-size:0.85rem" class="muted">${did}</div>
308
+
</div>
309
+
<form class="logout" action="/logout" method="POST">
310
+
<button class="btn secondary" type="submit">Logout</button>
311
+
</form>
312
+
</div>
313
+
`
314
+
: `
315
+
<form class="login-form" action="/login" method="POST">
316
+
<input name="handle" type="text" placeholder="handle.bsky.social" required />
317
+
<button class="btn" type="submit">Login with Bluesky</button>
318
+
</form>
319
+
`
320
+
}
321
+
</div>
322
+
</header>
323
+
<main>
324
+
<section class="card composer">
325
+
<div class="row" style="justify-content: space-between; align-items: flex-start;">
326
+
<div>
327
+
<h2 style="margin:0 0 6px 0;">Compose ANProto</h2>
328
+
<p class="muted" style="margin:0;">Sign locally with APDS, then save to your PDS.</p>
329
+
</div>
330
+
<div id="pubkey-display" class="muted" style="font-size:0.9rem; text-align:right;">Loading key...</div>
331
+
</div>
332
+
<form id="composer-form">
333
+
<textarea id="composer-text" name="anmsg" placeholder="Write or paste your ANProto content..."></textarea>
334
+
<div class="actions">
335
+
<label class="muted">Attach blob (optional): <input type="file" id="composer-blob" /></label>
336
+
<button class="btn" type="submit">${loggedIn ? 'Sign & Publish' : 'Sign (login to publish)'}</button>
337
+
<button class="btn secondary" type="button" id="regen-key">New keypair</button>
338
+
</div>
339
+
<div class="status" id="composer-status"></div>
340
+
</form>
341
+
</section>
342
+
343
+
<section class="card feed">
344
+
<div class="feed-head">
345
+
<h3 style="margin:0;">Your ANProto feed</h3>
346
+
<span class="pill">Local APDS</span>
347
+
</div>
348
+
<div id="feed-list" class="feed-list">
349
+
<div class="muted">Loading feed...</div>
350
+
</div>
351
+
</section>
352
+
</main>
353
+
354
+
<script type="module">
355
+
import { apds } from '/apds/apds.js'
356
+
357
+
(async () => {
358
+
const form = document.getElementById('composer-form')
359
+
const statusEl = document.getElementById('composer-status')
360
+
const fileInput = document.getElementById('composer-blob')
361
+
const textArea = document.getElementById('composer-text')
362
+
const pubkeyEl = document.getElementById('pubkey-display')
363
+
const regenBtn = document.getElementById('regen-key')
364
+
const feedList = document.getElementById('feed-list')
365
+
366
+
const setStatus = (text, isError) => {
367
+
if (!statusEl) return
368
+
statusEl.textContent = text
369
+
statusEl.style.color = isError ? 'crimson' : 'inherit'
370
+
}
371
+
372
+
const fileToBase64 = async (file) => {
373
+
const buf = await file.arrayBuffer()
374
+
let binary = ''
375
+
const bytes = new Uint8Array(buf)
376
+
const chunk = 0x8000
377
+
for (let i = 0; i < bytes.length; i += chunk) {
378
+
const slice = bytes.subarray(i, i + chunk)
379
+
binary += String.fromCharCode.apply(null, Array.from(slice))
380
+
}
381
+
return btoa(binary)
382
+
}
383
+
384
+
const ensureKeypair = async () => {
385
+
let pub = await apds.pubkey()
386
+
if (!pub) {
387
+
const kp = await apds.generate()
388
+
await apds.put('keypair', kp)
389
+
pub = await apds.pubkey()
390
+
}
391
+
return pub
392
+
}
393
+
394
+
const renderPubkey = async () => {
395
+
if (!pubkeyEl) return
396
+
const pub = await apds.pubkey()
397
+
pubkeyEl.textContent = pub ? 'ANProto pubkey: ' + pub : 'No keypair'
398
+
}
399
+
400
+
await apds.start('anproto-ui')
401
+
await ensureKeypair()
402
+
await renderPubkey()
403
+
404
+
regenBtn?.addEventListener('click', async () => {
405
+
const kp = await apds.generate()
406
+
await apds.put('keypair', kp)
407
+
await renderPubkey()
408
+
setStatus('New keypair generated', false)
409
+
})
410
+
411
+
form?.addEventListener('submit', async (e) => {
412
+
e.preventDefault()
413
+
setStatus('Signing and publishing...', false)
414
+
const content = (textArea?.value || '').trim()
415
+
if (!content) {
416
+
setStatus('Message is required', true)
417
+
return
418
+
}
419
+
420
+
let payload = {}
421
+
let derivedBlob
422
+
let derivedBlobHash
423
+
424
+
try {
425
+
const protocolHash = await apds.compose(content)
426
+
const anmsg = await apds.get(protocolHash)
427
+
if (!anmsg) {
428
+
setStatus('Could not load signed message', true)
429
+
return
430
+
}
431
+
payload.anmsg = anmsg
432
+
try {
433
+
const anhash = await apds.hash(anmsg)
434
+
payload.anhash = anhash
435
+
} catch (err) {
436
+
console.warn('Could not compute anhash', err)
437
+
}
438
+
439
+
try {
440
+
const opened = await apds.open(anmsg)
441
+
const contentHash = opened?.substring(13)
442
+
if (contentHash) {
443
+
const body = await apds.get(contentHash)
444
+
if (body) {
445
+
derivedBlob = body
446
+
derivedBlobHash = contentHash
447
+
}
448
+
}
449
+
} catch (err) {
450
+
console.warn('Could not derive message body from anmsg', err)
451
+
}
452
+
} catch (err) {
453
+
setStatus('Signing failed', true)
454
+
return
455
+
}
456
+
457
+
const file = fileInput?.files?.[0]
458
+
if (file) {
459
+
if (file.size > 2 * 1024 * 1024) {
460
+
setStatus('Blob too large (max 2MB)', true)
461
+
return
462
+
}
463
+
try {
464
+
const b64 = await fileToBase64(file)
465
+
let blobhash
466
+
try {
467
+
blobhash = await apds.hash(b64)
468
+
} catch (err) {
469
+
console.warn('Could not hash blob', err)
470
+
}
471
+
payload = { ...payload, blob: b64, ...(blobhash ? { blobhash } : {}) }
472
+
} catch (err) {
473
+
setStatus('Failed to read blob', true)
474
+
return
475
+
}
476
+
} else if (derivedBlob) {
477
+
payload = { ...payload, blob: derivedBlob, blobhash: derivedBlobHash }
478
+
}
479
+
480
+
try {
481
+
const res = await fetch('/publish', {
482
+
method: 'POST',
483
+
headers: { 'Content-Type': 'application/json' },
484
+
body: JSON.stringify(payload),
485
+
})
486
+
const data = await res.json()
487
+
if (!res.ok) {
488
+
throw new Error(data?.error || 'Publish failed')
489
+
}
490
+
setStatus('Saved with rkey ' + data.rkey, false)
491
+
if (textArea) textArea.value = ''
492
+
if (fileInput) fileInput.value = ''
493
+
} catch (err) {
494
+
setStatus(err?.message || 'Publish failed', true)
495
+
}
496
+
await refreshFeed()
497
+
})
498
+
499
+
const renderFeedItems = (items) => {
500
+
if (!feedList) return
501
+
if (!items || !items.length) {
502
+
feedList.innerHTML = '<div class="muted">No ANProto messages yet.</div>'
503
+
return
504
+
}
505
+
const html = items
506
+
.map((item) => {
507
+
const author = item.author || 'unknown author'
508
+
const time = item.time || ''
509
+
const text = item.text || ''
510
+
const hash = item.hash || ''
511
+
return (
512
+
'<div class="feed-item">' +
513
+
'<div class="feed-head">' +
514
+
'<span class="pill">' + author + '</span>' +
515
+
'<span class="muted">' + time + '</span>' +
516
+
'</div>' +
517
+
'<div style="margin-top:6px; white-space: pre-wrap;">' + text + '</div>' +
518
+
'<div class="muted" style="font-size:0.85rem; margin-top:6px;">' + hash + '</div>' +
519
+
'</div>'
520
+
)
521
+
})
522
+
.join('')
523
+
feedList.innerHTML = html
524
+
}
525
+
526
+
async function refreshFeed() {
527
+
if (!feedList) return
528
+
feedList.innerHTML = '<div class="muted">Loading feed...</div>'
529
+
try {
530
+
const entries = (await apds.query()) || []
531
+
if (!entries.length) {
532
+
renderFeedItems([])
533
+
return
534
+
}
535
+
const mapped = await Promise.all(
536
+
[...entries]
537
+
.reverse()
538
+
.map(async (msg) => ({
539
+
hash: msg.hash,
540
+
text: msg.text || '',
541
+
author: msg.author || '',
542
+
time: msg.ts ? await apds.human(msg.ts) : '',
543
+
})),
544
+
)
545
+
renderFeedItems(mapped)
546
+
} catch (err) {
547
+
console.warn('Failed to render feed', err)
548
+
feedList.innerHTML = '<div class="muted">Could not load feed.</div>'
549
+
}
550
+
}
551
+
552
+
await refreshFeed()
553
+
setInterval(refreshFeed, 20000)
554
+
})()
555
+
</script>
556
+
</body>
557
+
</html>
558
+
`
559
+
}
560
+
561
+
function renderError(err: any) {
562
+
return `
563
+
<h1>Error</h1>
564
+
<p>Something went wrong.</p>
565
+
<pre>${err}</pre>
566
+
<a href="/">Go Back</a>
567
+
`
568
+
}
569
+
570
+
run()
571
+
572
+
let anModulePromise: Promise<{ an: { hash: (d: string) => Promise<string> } }> | null = null
573
+
async function loadAn() {
574
+
if (!anModulePromise) {
575
+
const url = pathToFileURL(path.join(__dirname, '../apds/an.js')).href
576
+
anModulePromise = import(url)
577
+
}
578
+
return (await anModulePromise).an
579
+
}
580
+
581
+
function toBase64Url(b64: string) {
582
+
return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '')
583
+
}
+55
src/storage.ts
+55
src/storage.ts
···
1
+
import type {
2
+
NodeSavedSession,
3
+
NodeSavedSessionStore,
4
+
NodeSavedState,
5
+
NodeSavedStateStore,
6
+
} from '@atproto/oauth-client-node'
7
+
import { db } from './db'
8
+
9
+
/**
10
+
* StateStore:
11
+
* Stores temporary "state" parameters used during the initial OAuth handshake (authorize -> callback).
12
+
* This prevents CSRF attacks by ensuring the callback comes from the same flow we started.
13
+
* These are short-lived and can be deleted after the callback is processed.
14
+
*/
15
+
export class StateStore implements NodeSavedStateStore {
16
+
async get(key: string): Promise<NodeSavedState | undefined> {
17
+
const result = db.prepare('SELECT state FROM auth_state WHERE key = ?').get(key) as { state: string } | undefined
18
+
if (!result) return
19
+
return JSON.parse(result.state) as NodeSavedState
20
+
}
21
+
async set(key: string, val: NodeSavedState) {
22
+
const state = JSON.stringify(val)
23
+
db.prepare(`
24
+
INSERT INTO auth_state (key, state) VALUES (?, ?)
25
+
ON CONFLICT(key) DO UPDATE SET state = excluded.state
26
+
`).run(key, state)
27
+
}
28
+
async del(key: string) {
29
+
db.prepare('DELETE FROM auth_state WHERE key = ?').run(key)
30
+
}
31
+
}
32
+
33
+
/**
34
+
* SessionStore:
35
+
* Persists the long-term OAuth session data (Access Token, Refresh Token, DID).
36
+
* This allows the user to stay logged in even if the server restarts.
37
+
* Keys are usually mapped to the user's DID.
38
+
*/
39
+
export class SessionStore implements NodeSavedSessionStore {
40
+
async get(key: string): Promise<NodeSavedSession | undefined> {
41
+
const result = db.prepare('SELECT session FROM auth_session WHERE key = ?').get(key) as { session: string } | undefined
42
+
if (!result) return
43
+
return JSON.parse(result.session) as NodeSavedSession
44
+
}
45
+
async set(key: string, val: NodeSavedSession) {
46
+
const session = JSON.stringify(val)
47
+
db.prepare(`
48
+
INSERT INTO auth_session (key, session) VALUES (?, ?)
49
+
ON CONFLICT(key) DO UPDATE SET session = excluded.session
50
+
`).run(key, session)
51
+
}
52
+
async del(key: string) {
53
+
db.prepare('DELETE FROM auth_session WHERE key = ?').run(key)
54
+
}
55
+
}
+9
src/types/iron-session.d.ts
+9
src/types/iron-session.d.ts