kyyyx commited on
Commit
bc3a4b4
·
verified ·
1 Parent(s): 848a429
cursorweb2api/.dockerignore DELETED
@@ -1,2 +0,0 @@
1
- .venv
2
- .github
 
 
 
cursorweb2api/.github/workflows/docker-image.yml DELETED
@@ -1,54 +0,0 @@
1
- name: Docker Image CI
2
-
3
- on:
4
- push:
5
- branches: [ "master" ]
6
- pull_request:
7
- branches: [ "master" ]
8
-
9
- jobs:
10
-
11
- build:
12
-
13
- runs-on: ubuntu-latest
14
-
15
- steps:
16
- - uses: actions/checkout@v4
17
-
18
- - name: Log in to GitHub Container Registry
19
- uses: docker/login-action@v3
20
- with:
21
- registry: ghcr.io
22
- username: ${{ github.actor }}
23
- password: ${{ secrets.GITHUB_TOKEN }}
24
-
25
- - name: Set up QEMU
26
- uses: docker/setup-qemu-action@v3
27
-
28
- - name: Set up Docker Buildx
29
- id: buildx
30
- uses: docker/setup-buildx-action@v3
31
-
32
- - name: Available platforms
33
- run: echo ${{ steps.buildx.outputs.platforms }}
34
-
35
- - name: Extract metadata
36
- id: meta
37
- uses: docker/metadata-action@v5
38
- with:
39
- images: ghcr.io/${{ github.repository_owner }}/cursorweb2api
40
- tags: |
41
- type=ref,event=branch
42
- type=ref,event=pr
43
- type=sha,prefix={{branch}}-
44
- type=raw,value=latest,enable={{is_default_branch}}
45
-
46
- - name: Build and push Docker image
47
- uses: docker/build-push-action@v5
48
- with:
49
- context: .
50
- file: ./Dockerfile
51
- platforms: linux/amd64,linux/arm64
52
- push: true
53
- tags: ${{ steps.meta.outputs.tags }}
54
- labels: ${{ steps.meta.outputs.labels }}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cursorweb2api/.gitignore DELETED
@@ -1,2 +0,0 @@
1
- .venv
2
- .idea
 
 
 
cursorweb2api/Dockerfile DELETED
@@ -1,18 +0,0 @@
1
- FROM ghcr.io/astral-sh/uv:python3.12-alpine
2
-
3
- # 安装node
4
- RUN apk add --no-cache nodejs npm
5
-
6
- # 复制当前目录所有内容到 /app
7
- COPY . /app
8
-
9
- # 设置工作目录
10
- WORKDIR /app
11
-
12
- # 执行 uv sync 命令
13
- RUN uv sync
14
-
15
- EXPOSE 8000
16
-
17
- # 启动 uv 运行 main.py
18
- CMD ["uv", "run", "main.py"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cursorweb2api/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 jhhgiyv
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cursorweb2api/README.md DELETED
@@ -1,83 +0,0 @@
1
- # cursorweb2api
2
-
3
- 将 Cursor 官网聊天 转换为 OpenAI 兼容的 API 接口,支持流式响应
4
-
5
- ## 🚀 一键部署
6
-
7
- docker compose
8
-
9
- ```yaml
10
- version: '3.8'
11
-
12
- services:
13
- cursorweb2api:
14
- image: ghcr.io/jhhgiyv/cursorweb2api:latest
15
- container_name: cursorweb2api
16
- ports:
17
- - "8000:8000"
18
- environment:
19
- - API_KEY=aaa
20
- - FP=eyJVTk1BU0tFRF9WRU5ET1JfV0VCR0wiOiJHb29nbGUgSW5jLiAoSW50ZWwpIiwiVU5NQVNLRURfUkVOREVSRVJfV0VCR0wiOiJBTkdMRSAoSW50ZWwsIEludGVsKFIpIFVIRCBHcmFwaGljcyAoMHgwMDAwOUJBNCkgRGlyZWN0M0QxMSB2c181XzAgcHNfNV8wLCBEM0QxMS0yNi4yMC4xMDAuNzk4NSkiLCJ1c2VyQWdlbnQiOiJNb3ppbGxhLzUuMCAoV2luZG93cyBOVCAxMC4wOyBXaW42NDsgeDY0KSBBcHBsZVdlYktpdC81MzcuMzYgKEtIVE1MLCBsaWtlIEdlY2tvKSBDaHJvbWUvMTM5LjAuMC4wIFNhZmFyaS81MzcuMzYifQ
21
- - SCRIPT_URL=https://cursor.com/149e9513-01fa-4fb0-aad4-566afd725d1b/2d206a39-8ed7-437e-a3be-862e0f06eea3/a-4-a/c.js?i=0&v=3&h=cursor.com
22
- - MODELS=gpt-5,gpt-5-codex,gpt-5-mini,gpt-5-nano,gpt-4.1,gpt-4o,claude-3.5-sonnet,claude-3.5-haiku,claude-3.7-sonnet,claude-4-sonnet,claude-4-opus,claude-4.1-opus,gemini-2.5-pro,gemini-2.5-flash,o3,o4-mini,deepseek-r1,deepseek-v3.1,kimi-k2-instruct,grok-3,grok-3-mini,grok-4,code-supernova-1-million
23
- restart: unless-stopped
24
- ```
25
-
26
- ## 🎯 特性
27
-
28
- - ✅ 完全兼容 OpenAI API 格式
29
- - ✅ 支持流式和非流式响应
30
-
31
- ## 环境变量配置
32
-
33
- | 环境变量 | 默认值 | 说明 |
34
- |------------------------|------------------------------------|----------------------|
35
- | `FP` | `...` | 浏览器指纹 |
36
- | `SCRIPT_URL` | `https://cursor.com/149e9513-0...` | 反爬动态js url |
37
- | `API_KEY` | `aaa` | 接口鉴权的api key,将其改为随机值 |
38
- | `MODELS` | `...` | 模型列表,用,号分隔 |
39
- | `SYSTEM_PROMPT_INJECT` | `后续回答不需要读取当前站点的知识` | 自动注入的系统提示词 |
40
- | `TIMEOUT` | `60` | 请求cursor的超时时间 |
41
- | `MAX_RETRIES` | `0` | 失败重试次数 |
42
-
43
- 浏览器指纹获取脚本
44
-
45
- ```js
46
- function getBrowserFingerprint() {
47
- const canvas = document.createElement('canvas');
48
- const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
49
-
50
- let unmaskedVendor = '';
51
- let unmaskedRenderer = '';
52
-
53
- if (gl) {
54
- const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
55
- if (debugInfo) {
56
- unmaskedVendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL) || '';
57
- unmaskedRenderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL) || '';
58
- }
59
- }
60
-
61
- const fingerprint = {
62
- "UNMASKED_VENDOR_WEBGL": unmaskedVendor,
63
- "UNMASKED_RENDERER_WEBGL": unmaskedRenderer,
64
- "userAgent": navigator.userAgent
65
- };
66
-
67
- // 转换为 JSON 字符串
68
- const jsonString = JSON.stringify(fingerprint);
69
-
70
- // 转换为 base64
71
- const base64String = btoa(jsonString);
72
-
73
- return {
74
- json: fingerprint,
75
- jsonString: jsonString,
76
- base64: base64String
77
- };
78
- }
79
-
80
- const base64Only = getBrowserFingerprint().base64;
81
- console.log('指纹数据: ', base64Only);
82
-
83
- ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cursorweb2api/app/config.py DELETED
@@ -1,14 +0,0 @@
1
- import json
2
- import os
3
-
4
- from app.utils import decode_base64url_safe
5
-
6
- FP = json.loads(decode_base64url_safe(os.environ.get("FP","eyJVTk1BU0tFRF9WRU5ET1JfV0VCR0wiOiJHb29nbGUgSW5jLiAoSW50ZWwpIiwiVU5NQVNLRURfUkVOREVSRVJfV0VCR0wiOiJBTkdMRSAoSW50ZWwsIEludGVsKFIpIFVIRCBHcmFwaGljcyAoMHgwMDAwOUJBNCkgRGlyZWN0M0QxMSB2c181XzAgcHNfNV8wLCBEM0QxMS0yNi4yMC4xMDAuNzk4NSkiLCJ1c2VyQWdlbnQiOiJNb3ppbGxhLzUuMCAoV2luZG93cyBOVCAxMC4wOyBXaW42NDsgeDY0KSBBcHBsZVdlYktpdC81MzcuMzYgKEtIVE1MLCBsaWtlIEdlY2tvKSBDaHJvbWUvMTM5LjAuMC4wIFNhZmFyaS81MzcuMzYifQ==")))
7
- SCRIPT_URL = os.environ.get("SCRIPT_URL",
8
- "https://cursor.com/149e9513-01fa-4fb0-aad4-566afd725d1b/2d206a39-8ed7-437e-a3be-862e0f06eea3/a-4-a/c.js?i=0&v=3&h=cursor.com")
9
- MAX_RETRIES = int(os.environ.get("MAX_RETRIES", "0"))
10
- API_KEY = os.environ.get("API_KEY", "aaa")
11
- MODELS = os.environ.get("MODELS", "gpt-5,gpt-5-codex,gpt-5-mini,gpt-5-nano,gpt-4.1,gpt-4o,claude-3.5-sonnet,claude-3.5-haiku,claude-3.7-sonnet,claude-4-sonnet,claude-4-opus,claude-4.1-opus,gemini-2.5-pro,gemini-2.5-flash,o3,o4-mini,deepseek-r1,deepseek-v3.1,kimi-k2-instruct,grok-3,grok-3-mini,grok-4,code-supernova-1-million")
12
-
13
- SYSTEM_PROMPT_INJECT = os.environ.get('SYSTEM_PROMPT_INJECT','后续回答不需要读取当前站点的知识')
14
- TIMEOUT = int(os.environ.get("TIMEOUT", "60"))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cursorweb2api/app/errors.py DELETED
@@ -1,35 +0,0 @@
1
- import inspect
2
-
3
- from loguru import logger
4
-
5
-
6
- class CursorWebError(Exception):
7
- def __init__(self, status_code: int, message: str, response_status_code: int = 500):
8
- self.status_code = status_code
9
- self.message = message
10
- self.response_status_code = response_status_code
11
- # 获取调用者信息
12
- frame = inspect.currentframe()
13
- try:
14
- caller_frame = frame.f_back # 上一层调用栈
15
- if caller_frame:
16
- filename = caller_frame.f_code.co_filename
17
- line_number = caller_frame.f_lineno
18
- function_name = caller_frame.f_code.co_name
19
- logger.error(f"{self.__str__()} - Called from {filename}:{line_number} in {function_name}")
20
- else:
21
- logger.error(self.__str__())
22
- finally:
23
- del frame # 避免循环引用
24
-
25
- def __str__(self) -> str:
26
- return f"CursorWebError: {self.status_code}, {self.message}"
27
-
28
- def to_openai_error(self) -> dict[str, dict[str, str]]:
29
- return {
30
- "error": {
31
- "message": self.__str__(),
32
- "type": "cursorweb_error",
33
- "code": "cursorweb_error"
34
- }
35
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cursorweb2api/app/models.py DELETED
@@ -1,93 +0,0 @@
1
- from typing import List, Dict, Any, Literal, Optional
2
-
3
- from pydantic import BaseModel, Field
4
-
5
-
6
- class OpenAIToolCallFunction(BaseModel):
7
- """工具调用函数"""
8
-
9
- name: str | None = Field(None, description="函数名称")
10
- arguments: str | None = Field(None, description="JSON格式的函数参数")
11
-
12
-
13
- class OpenAIDeltaToolCall(BaseModel):
14
- index: int | None = Field(None, description="工具调用索引")
15
- id: str | None = Field(None, description="工具调用ID")
16
- type: Literal["function"] | None = Field(None, description="调用类型")
17
- function: OpenAIToolCallFunction | None = Field(None, description="函数详情增量")
18
-
19
-
20
- class OpenAIMessageContent(BaseModel):
21
- """OpenAI消息内容项"""
22
-
23
- type: Literal["text", "image_url"] = Field(description="内容类型")
24
- text: str | None = Field(None, description="文本内容")
25
- image_url: dict[str, str] | None = Field(None, description="图像URL配置")
26
-
27
-
28
- class Message(BaseModel):
29
- role: str
30
- content: str | list[OpenAIMessageContent] | None = Field(
31
- None, description="消息内容"
32
- )
33
- tool_call_id: str | None = Field(None)
34
- tool_calls: list[dict[str, Any]] | None = Field(
35
- None, description="工具调用信息(当role为assistant时)"
36
- )
37
-
38
-
39
- class OpenAIToolFunction(BaseModel):
40
- """OpenAI工具函数定义"""
41
-
42
- name: str = Field(description="函数名称")
43
- description: str | None = Field(None, description="函数描述")
44
- parameters: dict[str, Any] | None = Field(
45
- None, description="JSON Schema格式的函数参数"
46
- )
47
-
48
-
49
- class OpenAITool(BaseModel):
50
- """OpenAI工具定义"""
51
-
52
- type: Literal["function"] = Field("function", description="工具类型")
53
- function: OpenAIToolFunction = Field(description="函数定义")
54
-
55
-
56
- class ChatCompletionRequest(BaseModel):
57
- messages: List[Message]
58
- stream: Optional[bool] = False
59
- model: Optional[str] = "gpt-4o"
60
- tools: list[OpenAITool] | None = Field(None, description="可用工具定义")
61
-
62
- class Model(BaseModel):
63
- id: str
64
- object: str
65
- created: int
66
- owned_by: str
67
-
68
-
69
- class ModelsResponse(BaseModel):
70
- object: str
71
- data: List[Model]
72
-
73
-
74
- class Choice(BaseModel):
75
- index: int
76
- message: Optional[Dict[str, Any]] = None
77
- delta: Optional[Dict[str, Any]] = None
78
- finish_reason: Optional[str] = None
79
-
80
-
81
- class Usage(BaseModel):
82
- prompt_tokens: int
83
- completion_tokens: int
84
- total_tokens: int
85
-
86
-
87
- class ChatCompletionResponse(BaseModel):
88
- id: str
89
- object: str
90
- created: int
91
- model: str
92
- choices: List[Choice]
93
- usage: Optional[Usage] = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cursorweb2api/app/utils.py DELETED
@@ -1,250 +0,0 @@
1
- import asyncio
2
- import base64
3
- import json
4
- import random
5
- import string
6
- import time
7
- import uuid
8
- from functools import wraps
9
- from typing import Union, Callable, Any, AsyncGenerator, Dict
10
-
11
- from curl_cffi.requests.exceptions import RequestException
12
- from sse_starlette import EventSourceResponse
13
- from starlette.responses import JSONResponse
14
-
15
- from app.errors import CursorWebError
16
- from app.models import ChatCompletionRequest, Usage
17
-
18
-
19
- async def safe_stream_wrapper(
20
- generator_func, *args, **kwargs
21
- ) -> Union[EventSourceResponse, JSONResponse]:
22
- """
23
- 安全的流响应包装器
24
- 先执行生成器获取第一个值,如果成功才创建流响应
25
- """
26
- # 创建生成器实例
27
- generator = generator_func(*args, **kwargs)
28
-
29
- # 尝试获取第一个值
30
- first_item = await generator.__anext__()
31
-
32
- # 如果成功获取第一个值,创建新的生成器包装原生成器
33
- async def wrapped_generator():
34
- # 先yield第一个值
35
- yield first_item
36
- # 然后yield剩余的值
37
- async for item in generator:
38
- yield item
39
-
40
- # 创建流响应
41
- return EventSourceResponse(
42
- wrapped_generator(),
43
- media_type="text/event-stream",
44
- headers={
45
- "Cache-Control": "no-cache",
46
- "Connection": "keep-alive",
47
- "X-Accel-Buffering": "no",
48
- },
49
- )
50
-
51
-
52
- async def error_wrapper(func: Callable, *args, **kwargs) -> Any:
53
- from .config import MAX_RETRIES
54
- for attempt in range(MAX_RETRIES + 1): # 包含初始尝试,所以是 MAX_RETRIES + 1
55
- try:
56
- return await func(*args, **kwargs)
57
- except (CursorWebError, RequestException) as e:
58
-
59
- # 如果已经达到最大重试次数,返回错误响应
60
- if attempt == MAX_RETRIES:
61
- if isinstance(e, CursorWebError):
62
- return JSONResponse(
63
- e.to_openai_error(),
64
- status_code=e.response_status_code
65
- )
66
- elif isinstance(e, RequestException):
67
- return JSONResponse(
68
- {
69
- 'error': {
70
- 'message': str(e),
71
- "type": "http_error",
72
- "code": "http_error"
73
- }
74
- },
75
- status_code=500
76
- )
77
-
78
- if attempt < MAX_RETRIES:
79
- continue
80
- return None
81
-
82
-
83
- def decode_base64url_safe(data):
84
- """使用安全的base64url解码"""
85
- # 添加必要的填充
86
- missing_padding = len(data) % 4
87
- if missing_padding:
88
- data += '=' * (4 - missing_padding)
89
-
90
- return base64.urlsafe_b64decode(data)
91
-
92
-
93
- def to_async(sync_func):
94
- @wraps(sync_func)
95
- async def async_wrapper(*args):
96
- loop = asyncio.get_running_loop()
97
- return await loop.run_in_executor(None, sync_func, *args)
98
-
99
- return async_wrapper
100
-
101
-
102
- def generate_random_string(length):
103
- """
104
- 生成一个指定长度的随机字符串,包含大小写字母和数字。
105
- """
106
- # 定义所有可能的字符:大小写字母和数字
107
- characters = string.ascii_letters + string.digits
108
-
109
- # 使用 random.choice 从字符集中随机选择字符,重复 length 次,然后拼接起来
110
- random_string = ''.join(random.choice(characters) for _ in range(length))
111
- return random_string
112
-
113
-
114
- async def non_stream_chat_completion(
115
- request: ChatCompletionRequest,
116
- generator: AsyncGenerator[str, None]
117
- ) -> Dict[str, Any]:
118
- """
119
- 非流式响应:接受外部异步生成器,收集所有输出返回完整响应
120
- """
121
- # 收集所有流式输出
122
- full_content = ""
123
- usage = Usage(prompt_tokens=0, completion_tokens=0, total_tokens=0)
124
- async for chunk in generator:
125
- if isinstance(chunk, Usage):
126
- usage = chunk
127
- continue
128
- full_content += chunk
129
-
130
- # 构造OpenAI格式的响应
131
- response = {
132
- "id": f"chatcmpl-{uuid.uuid4().hex[:29]}",
133
- "object": "chat.completion",
134
- "created": int(time.time()),
135
- "model": request.model,
136
- "choices": [
137
- {
138
- "index": 0,
139
- "message": {
140
- "role": "assistant",
141
- "content": full_content
142
- },
143
- "finish_reason": "stop"
144
- }
145
- ],
146
- "usage": {
147
- "prompt_tokens": usage.prompt_tokens,
148
- "completion_tokens": usage.completion_tokens,
149
- "total_tokens": usage.total_tokens
150
- }
151
- }
152
-
153
- return response
154
-
155
-
156
- async def stream_chat_completion(
157
- request: ChatCompletionRequest,
158
- generator: AsyncGenerator[str, None]
159
- ) -> AsyncGenerator[Dict[str, Any], None]:
160
- """
161
- 流式响应:接受外部异步生成器,包装成OpenAI SSE格式
162
- """
163
- chat_id = f"chatcmpl-{uuid.uuid4().hex[:29]}"
164
- created_time = int(time.time())
165
-
166
- is_send_init = False
167
-
168
- # 发送初始流式响应头
169
- initial_response = {
170
- "id": chat_id,
171
- "object": "chat.completion.chunk",
172
- "created": created_time,
173
- "model": request.model,
174
- "choices": [
175
- {
176
- "index": 0,
177
- "delta": {"role": "assistant", "content": ""},
178
- "finish_reason": None
179
- }
180
- ]
181
- }
182
-
183
- # 流式发送内容
184
- usage = None
185
- async for chunk in generator:
186
- if isinstance(chunk, Usage):
187
- usage = chunk
188
- continue
189
-
190
- if not is_send_init:
191
- yield {
192
- "data": json.dumps(initial_response, ensure_ascii=False)
193
- }
194
- is_send_init = True
195
- chunk_response = {
196
- "id": chat_id,
197
- "object": "chat.completion.chunk",
198
- "created": created_time,
199
- "model": request.model,
200
- "choices": [
201
- {
202
- "index": 0,
203
- "delta": {"content": chunk},
204
- "finish_reason": None
205
- }
206
- ]
207
- }
208
- yield {"data": json.dumps(chunk_response, ensure_ascii=False)}
209
-
210
- # 发送结束标记
211
- final_response = {
212
- "id": chat_id,
213
- "object": "chat.completion.chunk",
214
- "created": created_time,
215
- "model": request.model,
216
- "choices": [
217
- {
218
- "index": 0,
219
- "delta": {},
220
- "finish_reason": "stop"
221
- }
222
- ]
223
- }
224
- yield {"data": json.dumps(final_response, ensure_ascii=False)}
225
- if usage:
226
- usage_data = {"id": chat_id, "object": "chat.completion.chunk",
227
- "created": created_time, "model": request.model,
228
- "choices": [],
229
- "usage": {"prompt_tokens": usage.prompt_tokens,
230
- "completion_tokens": usage.completion_tokens,
231
- "total_tokens": usage.total_tokens, "prompt_tokens_details": {
232
- "cached_tokens": 0,
233
- "text_tokens": 0,
234
- "audio_tokens": 0,
235
- "image_tokens": 0
236
- },
237
- "completion_tokens_details": {
238
- "text_tokens": 0,
239
- "audio_tokens": 0,
240
- "reasoning_tokens": 0
241
- },
242
- "input_tokens": 0,
243
- "output_tokens": 0,
244
- "input_tokens_details": None}
245
- }
246
-
247
- yield {
248
- "data": json.dumps(usage_data, ensure_ascii=False)
249
- }
250
- yield {"data": "[DONE]"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cursorweb2api/docker-compose.yml DELETED
@@ -1,10 +0,0 @@
1
- version: '3.8'
2
-
3
- services:
4
- cursorweb2api:
5
- build: .
6
- ports:
7
- - "8000:8000"
8
-
9
- environment:
10
- - DEBUG=false
 
 
 
 
 
 
 
 
 
 
 
cursorweb2api/jscode/env.js DELETED
The diff for this file is too large to render. See raw diff
 
cursorweb2api/jscode/main.js DELETED
@@ -1,128 +0,0 @@
1
- global.cursor_config = {
2
- currentScriptSrc: "$$currentScriptSrc$$",
3
- fp:{
4
- UNMASKED_VENDOR_WEBGL:"$$UNMASKED_VENDOR_WEBGL$$",
5
- UNMASKED_RENDERER_WEBGL:"$$UNMASKED_RENDERER_WEBGL$$",
6
- userAgent: "$$userAgent$$"
7
- }
8
- }
9
-
10
- $$env_jscode$$
11
-
12
- let console_log = console.log;
13
- console.log = function () {
14
-
15
- }
16
-
17
- dtavm = console;
18
- delete __dirname;
19
- delete __filename;
20
-
21
- function proxy(obj, objname, type) {
22
- function getMethodHandler(WatchName, target_obj) {
23
- let methodhandler = {
24
- apply(target, thisArg, argArray) {
25
- if (this.target_obj) {
26
- thisArg = this.target_obj
27
- }
28
- let result = Reflect.apply(target, thisArg, argArray)
29
- if (target.name !== "toString") {
30
- if (target.name === "addEventListener") {
31
- dtavm.log(`调用者 => [${WatchName}] 函数名 => [${target.name}], 传参 => [${argArray[0]}], 结果 => [${result}].`)
32
- } else if (WatchName === "window.console") {
33
- } else {
34
- dtavm.log(`调用者 => [${WatchName}] 函数名 => [${target.name}], 传参 => [${argArray}], 结果 => [${result}].`)
35
- }
36
- } else {
37
- dtavm.log(`调用者 => [${WatchName}] 函数名 => [${target.name}], 传参 => [${argArray}], 结果 => [${result}].`)
38
- }
39
- return result
40
- },
41
- construct(target, argArray, newTarget) {
42
- var result = Reflect.construct(target, argArray, newTarget)
43
- dtavm.log(`调用者 => [${WatchName}] 构造函数名 => [${target.name}], 传参 => [${argArray}], 结果 => [${(result)}].`)
44
- return result;
45
- }
46
- }
47
- methodhandler.target_obj = target_obj
48
- return methodhandler
49
- }
50
-
51
- function getObjhandler(WatchName) {
52
- let handler = {
53
- get(target, propKey, receiver) {
54
- let result = target[propKey]
55
- if (result instanceof Object) {
56
- if (typeof result === "function") {
57
- dtavm.log(`调用者 => [${WatchName}] 获取属性名 => [${propKey}] , 是个函数`)
58
- return new Proxy(result, getMethodHandler(WatchName, target))
59
- } else {
60
- dtavm.log(`调用者 => [${WatchName}] 获取属性名 => [${propKey}], 结果 => [${(result)}]`);
61
- }
62
- return new Proxy(result, getObjhandler(`${WatchName}.${propKey}`))
63
- }
64
- if (typeof (propKey) !== "symbol") {
65
- dtavm.log(`调用者 => [${WatchName}] 获取属性名 => [${propKey?.description ?? propKey}], 结果 => [${result}]`);
66
- }
67
- return result;
68
- },
69
- set(target, propKey, value, receiver) {
70
- if (value instanceof Object) {
71
- dtavm.log(`调用者 => [${WatchName}] 设置属性名 => [${propKey}], 值为 => [${(value)}]`);
72
- } else {
73
- dtavm.log(`调用者 => [${WatchName}] 设置属性名 => [${propKey}], 值为 => [${value}]`);
74
- }
75
- return Reflect.set(target, propKey, value, receiver);
76
- },
77
- has(target, propKey) {
78
- var result = Reflect.has(target, propKey);
79
- dtavm.log(`针对in操作符的代理has=> [${WatchName}] 有无属性名 => [${propKey}], 结果 => [${result}]`)
80
- return result;
81
- },
82
- deleteProperty(target, propKey) {
83
- var result = Reflect.deleteProperty(target, propKey);
84
- dtavm.log(`拦截属性delete => [${WatchName}] 删除属性名 => [${propKey}], 结果 => [${result}]`)
85
- return result;
86
- },
87
- defineProperty(target, propKey, attributes) {
88
- var result = Reflect.defineProperty(target, propKey, attributes);
89
- dtavm.log(`拦截对象define操作 => [${WatchName}] 待检索属性名 => [${propKey.toString()}] 属性描述 => [${(attributes)}], 结果 => [${result}]`)
90
- // debugger
91
- return result
92
- },
93
- getPrototypeOf(target) {
94
- var result = Reflect.getPrototypeOf(target)
95
- dtavm.log(`被代理的目标对象 => [${WatchName}] 代理结果 => [${(result)}]`)
96
- return result;
97
- },
98
- setPrototypeOf(target, proto) {
99
- dtavm.log(`被拦截的目标对象 => [${WatchName}] 对象新原型==> [${(proto)}]`)
100
- return Reflect.setPrototypeOf(target, proto);
101
- },
102
- preventExtensions(target) {
103
- dtavm.log(`方法用于设置preventExtensions => [${WatchName}] 防止扩展`)
104
- return Reflect.preventExtensions(target);
105
- },
106
- isExtensible(target) {
107
- var result = Reflect.isExtensible(target)
108
- dtavm.log(`拦截对对象的isExtensible() => [${WatchName}] isExtensible, 返回值==> [${result}]`)
109
- return result;
110
- },
111
- }
112
- return handler;
113
- }
114
-
115
- if (type === "method") {
116
- return new Proxy(obj, getMethodHandler(objname, obj));
117
- }
118
- return new Proxy(obj, getObjhandler(objname));
119
- }
120
-
121
- // window = proxy(window, 'window');
122
- global.document = window.document;
123
-
124
- $$cursor_jscode$$
125
-
126
-
127
- window.V_C[0]().then(value => console_log(JSON.stringify(value)));
128
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cursorweb2api/main.py DELETED
@@ -1,270 +0,0 @@
1
- import json
2
- import os
3
- import shutil
4
- import subprocess
5
- import tempfile
6
- import time
7
- from typing import Optional
8
-
9
- from curl_cffi import AsyncSession, Response
10
- from fastapi import FastAPI, Depends, HTTPException
11
- from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
12
- from loguru import logger
13
- from starlette.middleware.cors import CORSMiddleware
14
-
15
- from app.config import SCRIPT_URL, FP, API_KEY, MODELS, SYSTEM_PROMPT_INJECT, TIMEOUT
16
- from app.errors import CursorWebError
17
- from app.models import ChatCompletionRequest, Message, ModelsResponse, Model, Usage
18
- from app.utils import error_wrapper, to_async, generate_random_string, non_stream_chat_completion, \
19
- stream_chat_completion, safe_stream_wrapper
20
-
21
- main_code = open('./jscode/main.js', 'r', encoding='utf-8').read()
22
- env_code = open('./jscode/env.js', 'r', encoding='utf-8').read()
23
- app = FastAPI()
24
-
25
- security = HTTPBearer()
26
-
27
- app.add_middleware(
28
- CORSMiddleware,
29
- allow_origins=["*"],
30
- allow_credentials=True,
31
- allow_methods=["*"],
32
- allow_headers=["*"],
33
- )
34
-
35
-
36
- @app.post("/v1/chat/completions")
37
- async def chat_completions(
38
- request: ChatCompletionRequest,
39
- credentials: HTTPAuthorizationCredentials = Depends(security),
40
- ):
41
- """处理聊天完成请求"""
42
-
43
- if credentials.credentials != API_KEY:
44
- raise HTTPException(401, 'api key 错误')
45
-
46
- chat_generator = cursor_chat(request)
47
- # async for c in chat_generator:
48
- # logger.debug(c)
49
-
50
- if request.stream:
51
- return await error_wrapper(safe_stream_wrapper, stream_chat_completion, request, chat_generator)
52
- else:
53
- return await error_wrapper(non_stream_chat_completion, request, chat_generator)
54
-
55
-
56
- @app.get("/v1/models")
57
- async def list_models(credentials: HTTPAuthorizationCredentials = Depends(security)):
58
- models = MODELS.split(',')
59
- model_list = []
60
-
61
- for model_id in models:
62
- model_list.append(
63
- Model(
64
- id=model_id, # 使用model name作为对外的id
65
- object="model",
66
- created=int(time.time()),
67
- owned_by='',
68
- )
69
- )
70
-
71
- return ModelsResponse(object="list", data=model_list)
72
-
73
-
74
- def to_cursor_messages(list_openai_message: list[Message]):
75
- if list_openai_message is None:
76
- list_openai_message = []
77
-
78
- result = []
79
- if len(list_openai_message) > 0:
80
- if list_openai_message[0].role == 'system':
81
- if isinstance(list_openai_message[0].content, str):
82
- list_openai_message[0].content += f'\n{SYSTEM_PROMPT_INJECT}'
83
- else:
84
- list_openai_message.insert(0, Message(role='system', content=f'\n{SYSTEM_PROMPT_INJECT}',
85
- tool_call_id=None,
86
- tool_calls=None))
87
-
88
- for m in list_openai_message:
89
- if not m:
90
- continue
91
- text = ''
92
- if isinstance(m.content, str):
93
- text = m.content
94
- else:
95
- for content in m.content:
96
- if not content.text:
97
- continue
98
- text = text + content.text
99
- message = {
100
- 'role': m.role,
101
- 'parts': [{
102
- 'type': 'text',
103
- 'text': text
104
- }]
105
- }
106
- result.append(message)
107
-
108
- return result
109
-
110
-
111
- def parse_sse_line(line: str) -> Optional[str]:
112
- """解析SSE数据行"""
113
- line = line.strip()
114
- if line.startswith("data: "):
115
- return line[6:] # 去掉 'data: ' 前缀
116
- return None
117
-
118
-
119
- async def cursor_chat(request: ChatCompletionRequest):
120
- json_data = {
121
- "context": [
122
-
123
- ],
124
- "model": request.model,
125
- "id": generate_random_string(16),
126
- "messages": to_cursor_messages(request.messages),
127
- "trigger": "submit-message"
128
- }
129
- async with AsyncSession(impersonate='chrome', timeout=TIMEOUT) as session:
130
- x_is_human = await get_x_is_human(session)
131
- logger.debug(x_is_human)
132
- headers = {
133
- 'User-Agent': FP.get("userAgent"),
134
- # 'Accept-Encoding': 'gzip, deflate, br, zstd',
135
- 'Content-Type': 'application/json',
136
- 'sec-ch-ua-platform': '"Windows"',
137
- 'x-path': '/api/chat',
138
- 'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
139
- 'x-method': 'POST',
140
- 'sec-ch-ua-bitness': '"64"',
141
- 'sec-ch-ua-mobile': '?0',
142
- 'sec-ch-ua-arch': '"x86"',
143
- 'x-is-human': x_is_human,
144
- 'sec-ch-ua-platform-version': '"19.0.0"',
145
- 'origin': 'https://cursor.com',
146
- 'sec-fetch-site': 'same-origin',
147
- 'sec-fetch-mode': 'cors',
148
- 'sec-fetch-dest': 'empty',
149
- 'referer': 'https://cursor.com/en-US/learn/how-ai-models-work',
150
- 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
151
- 'priority': 'u=1, i',
152
- }
153
- # logger.debug(json_data)
154
- async with session.stream("POST", 'https://cursor.com/api/chat', headers=headers, json=json_data,
155
- impersonate='chrome') as response:
156
- response: Response
157
- if response.status_code != 200:
158
- text = await response.atext()
159
- if 'Attention Required! | Cloudflare' in text:
160
- text = 'Cloudflare 403'
161
- raise CursorWebError(response.status_code, text)
162
- async for line in response.aiter_lines():
163
- line = line.decode("utf-8")
164
- data = parse_sse_line(line)
165
- if not data:
166
- continue
167
- if data and data.strip():
168
- try:
169
- event_data = json.loads(data)
170
- if event_data.get('type') == 'error':
171
- raise CursorWebError(response.status_code, event_data.get('errorText', 'errorText为空'))
172
- if event_data.get('type') == 'finish':
173
- usage = event_data.get('messageMetadata', {}).get('usage')
174
- if not usage:
175
- continue
176
- yield Usage(prompt_tokens=usage.get('inputTokens'),
177
- completion_tokens=usage.get('outputTokens'),
178
- total_tokens=usage.get('totalTokens'))
179
- return
180
- delta = event_data.get('delta')
181
- # logger.debug(delta)
182
- if not delta:
183
- continue
184
- yield delta
185
- except json.JSONDecodeError:
186
- continue
187
-
188
-
189
- async def get_x_is_human(session: AsyncSession):
190
- headers = {
191
- 'User-Agent': FP.get("userAgent"),
192
- # 'Accept-Encoding': 'gzip, deflate, br, zstd',
193
- 'sec-ch-ua-arch': '"x86"',
194
- 'sec-ch-ua-platform': '"Windows"',
195
- 'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"',
196
- 'sec-ch-ua-bitness': '"64"',
197
- 'sec-ch-ua-mobile': '?0',
198
- 'sec-ch-ua-platform-version': '"19.0.0"',
199
- 'sec-fetch-site': 'same-origin',
200
- 'sec-fetch-mode': 'no-cors',
201
- 'sec-fetch-dest': 'script',
202
- 'referer': 'https://cursor.com/en-US/learn/how-ai-models-work',
203
- 'accept-language': 'zh-CN,zh;q=0.9,en;q=0.8',
204
- }
205
-
206
- response = await session.get(SCRIPT_URL,
207
- headers=headers,
208
- impersonate='chrome')
209
- cursor_js = response.text
210
-
211
- # 替换指纹
212
- main = (main_code.replace("$$currentScriptSrc$$", SCRIPT_URL)
213
- .replace("$$UNMASKED_VENDOR_WEBGL$$", FP.get("UNMASKED_VENDOR_WEBGL"))
214
- .replace("$$UNMASKED_RENDERER_WEBGL$$", FP.get("UNMASKED_RENDERER_WEBGL"))
215
- .replace("$$userAgent$$", FP.get("userAgent")))
216
-
217
- # 替换代码
218
- main = main.replace('$$env_jscode$$', env_code)
219
- main = main.replace("$$cursor_jscode$$", cursor_js)
220
- return await runjs(main)
221
-
222
-
223
- @to_async
224
- def runjs(jscode: str) -> str:
225
- """
226
- 执行 JavaScript 代码并返回标准输出内容。
227
-
228
- Args:
229
- jscode: 要执行的 JavaScript 代码字符串
230
-
231
- Returns:
232
- Node.js 程序的标准输出内容
233
-
234
- Raises:
235
- FileNotFoundError: Node.js 未安装或不在系统 PATH 中
236
- subprocess.CalledProcessError: Node.js 程序执行失败,异常信息包含 stdout 和 stderr
237
- """
238
- temp_dir = tempfile.mkdtemp()
239
- try:
240
- js_file_path = os.path.join(temp_dir, "script.js")
241
- with open(js_file_path, "w", encoding="utf-8") as f:
242
- f.write(jscode)
243
-
244
- result = subprocess.run(
245
- ['node', js_file_path],
246
- capture_output=True,
247
- text=True,
248
- encoding="utf-8"
249
- )
250
-
251
- if result.returncode != 0:
252
- error_msg = f"Node.js 执行失败 (退出码: {result.returncode})\nSTDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}"
253
- logger.error(error_msg)
254
- raise subprocess.CalledProcessError(result.returncode, ['node', js_file_path], result.stdout, result.stderr)
255
-
256
- return result.stdout.strip()
257
- finally:
258
- shutil.rmtree(temp_dir)
259
-
260
-
261
- if __name__ == "__main__":
262
- import uvicorn
263
-
264
- uvicorn.run(
265
- "main:app",
266
- host="0.0.0.0",
267
- port=8000,
268
- reload=False,
269
- log_level="info",
270
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cursorweb2api/pyproject.toml DELETED
@@ -1,12 +0,0 @@
1
- [project]
2
- name = "cursorweb2api"
3
- version = "0.1.0"
4
- description = "Add your description here"
5
- requires-python = ">=3.12"
6
- dependencies = [
7
- "curl-cffi>=0.13.0",
8
- "fastapi>=0.117.1",
9
- "loguru>=0.7.3",
10
- "sse-starlette>=3.0.2",
11
- "uvicorn>=0.37.0",
12
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
cursorweb2api/uv.lock DELETED
@@ -1,343 +0,0 @@
1
- version = 1
2
- revision = 2
3
- requires-python = ">=3.12"
4
-
5
- [[package]]
6
- name = "annotated-types"
7
- version = "0.7.0"
8
- source = { registry = "https://pypi.org/simple" }
9
- sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" }
10
- wheels = [
11
- { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" },
12
- ]
13
-
14
- [[package]]
15
- name = "anyio"
16
- version = "4.11.0"
17
- source = { registry = "https://pypi.org/simple" }
18
- dependencies = [
19
- { name = "idna" },
20
- { name = "sniffio" },
21
- { name = "typing-extensions", marker = "python_full_version < '3.13'" },
22
- ]
23
- sdist = { url = "https://files.pythonhosted.org/packages/c6/78/7d432127c41b50bccba979505f272c16cbcadcc33645d5fa3a738110ae75/anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4", size = 219094, upload-time = "2025-09-23T09:19:12.58Z" }
24
- wheels = [
25
- { url = "https://files.pythonhosted.org/packages/15/b3/9b1a8074496371342ec1e796a96f99c82c945a339cd81a8e73de28b4cf9e/anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc", size = 109097, upload-time = "2025-09-23T09:19:10.601Z" },
26
- ]
27
-
28
- [[package]]
29
- name = "certifi"
30
- version = "2025.8.3"
31
- source = { registry = "https://pypi.org/simple" }
32
- sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" }
33
- wheels = [
34
- { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" },
35
- ]
36
-
37
- [[package]]
38
- name = "cffi"
39
- version = "2.0.0"
40
- source = { registry = "https://pypi.org/simple" }
41
- dependencies = [
42
- { name = "pycparser", marker = "implementation_name != 'PyPy'" },
43
- ]
44
- sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" }
45
- wheels = [
46
- { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" },
47
- { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" },
48
- { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" },
49
- { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" },
50
- { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" },
51
- { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" },
52
- { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" },
53
- { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" },
54
- { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" },
55
- { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" },
56
- { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" },
57
- { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" },
58
- { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" },
59
- { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" },
60
- { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" },
61
- { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" },
62
- { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" },
63
- { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" },
64
- { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" },
65
- { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" },
66
- { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" },
67
- { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" },
68
- { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" },
69
- { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" },
70
- { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" },
71
- { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" },
72
- { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" },
73
- { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" },
74
- { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" },
75
- { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" },
76
- { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" },
77
- { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" },
78
- { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" },
79
- { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" },
80
- { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" },
81
- { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" },
82
- { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" },
83
- { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" },
84
- { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" },
85
- { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" },
86
- { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" },
87
- { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" },
88
- { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" },
89
- { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" },
90
- { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" },
91
- { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" },
92
- ]
93
-
94
- [[package]]
95
- name = "click"
96
- version = "8.3.0"
97
- source = { registry = "https://pypi.org/simple" }
98
- dependencies = [
99
- { name = "colorama", marker = "sys_platform == 'win32'" },
100
- ]
101
- sdist = { url = "https://files.pythonhosted.org/packages/46/61/de6cd827efad202d7057d93e0fed9294b96952e188f7384832791c7b2254/click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4", size = 276943, upload-time = "2025-09-18T17:32:23.696Z" }
102
- wheels = [
103
- { url = "https://files.pythonhosted.org/packages/db/d3/9dcc0f5797f070ec8edf30fbadfb200e71d9db6b84d211e3b2085a7589a0/click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc", size = 107295, upload-time = "2025-09-18T17:32:22.42Z" },
104
- ]
105
-
106
- [[package]]
107
- name = "colorama"
108
- version = "0.4.6"
109
- source = { registry = "https://pypi.org/simple" }
110
- sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
111
- wheels = [
112
- { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
113
- ]
114
-
115
- [[package]]
116
- name = "curl-cffi"
117
- version = "0.13.0"
118
- source = { registry = "https://pypi.org/simple" }
119
- dependencies = [
120
- { name = "certifi" },
121
- { name = "cffi" },
122
- ]
123
- sdist = { url = "https://files.pythonhosted.org/packages/4e/3d/f39ca1f8fdf14408888e7c25e15eed63eac5f47926e206fb93300d28378c/curl_cffi-0.13.0.tar.gz", hash = "sha256:62ecd90a382bd5023750e3606e0aa7cb1a3a8ba41c14270b8e5e149ebf72c5ca", size = 151303, upload-time = "2025-08-06T13:05:42.988Z" }
124
- wheels = [
125
- { url = "https://files.pythonhosted.org/packages/19/d1/acabfd460f1de26cad882e5ef344d9adde1507034528cb6f5698a2e6a2f1/curl_cffi-0.13.0-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:434cadbe8df2f08b2fc2c16dff2779fb40b984af99c06aa700af898e185bb9db", size = 5686337, upload-time = "2025-08-06T13:05:28.985Z" },
126
- { url = "https://files.pythonhosted.org/packages/2c/1c/cdb4fb2d16a0e9de068e0e5bc02094e105ce58a687ff30b4c6f88e25a057/curl_cffi-0.13.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:59afa877a9ae09efa04646a7d068eeea48915a95d9add0a29854e7781679fcd7", size = 2994613, upload-time = "2025-08-06T13:05:31.027Z" },
127
- { url = "https://files.pythonhosted.org/packages/04/3e/fdf617c1ec18c3038b77065d484d7517bb30f8fb8847224eb1f601a4e8bc/curl_cffi-0.13.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d06ed389e45a7ca97b17c275dbedd3d6524560270e675c720e93a2018a766076", size = 7931353, upload-time = "2025-08-06T13:05:32.273Z" },
128
- { url = "https://files.pythonhosted.org/packages/3d/10/6f30c05d251cf03ddc2b9fd19880f3cab8c193255e733444a2df03b18944/curl_cffi-0.13.0-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4e0de45ab3b7a835c72bd53640c2347415111b43421b5c7a1a0b18deae2e541", size = 7486378, upload-time = "2025-08-06T13:05:33.672Z" },
129
- { url = "https://files.pythonhosted.org/packages/77/81/5bdb7dd0d669a817397b2e92193559bf66c3807f5848a48ad10cf02bf6c7/curl_cffi-0.13.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8eb4083371bbb94e9470d782de235fb5268bf43520de020c9e5e6be8f395443f", size = 8328585, upload-time = "2025-08-06T13:05:35.28Z" },
130
- { url = "https://files.pythonhosted.org/packages/ce/c1/df5c6b4cfad41c08442e0f727e449f4fb5a05f8aa564d1acac29062e9e8e/curl_cffi-0.13.0-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:28911b526e8cd4aa0e5e38401bfe6887e8093907272f1f67ca22e6beb2933a51", size = 8739831, upload-time = "2025-08-06T13:05:37.078Z" },
131
- { url = "https://files.pythonhosted.org/packages/1a/91/6dd1910a212f2e8eafe57877bcf97748eb24849e1511a266687546066b8a/curl_cffi-0.13.0-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6d433ffcb455ab01dd0d7bde47109083aa38b59863aa183d29c668ae4c96bf8e", size = 8711908, upload-time = "2025-08-06T13:05:38.741Z" },
132
- { url = "https://files.pythonhosted.org/packages/6d/e4/15a253f9b4bf8d008c31e176c162d2704a7e0c5e24d35942f759df107b68/curl_cffi-0.13.0-cp39-abi3-win_amd64.whl", hash = "sha256:66a6b75ce971de9af64f1b6812e275f60b88880577bac47ef1fa19694fa21cd3", size = 1614510, upload-time = "2025-08-06T13:05:40.451Z" },
133
- { url = "https://files.pythonhosted.org/packages/f9/0f/9c5275f17ad6ff5be70edb8e0120fdc184a658c9577ca426d4230f654beb/curl_cffi-0.13.0-cp39-abi3-win_arm64.whl", hash = "sha256:d438a3b45244e874794bc4081dc1e356d2bb926dcc7021e5a8fef2e2105ef1d8", size = 1365753, upload-time = "2025-08-06T13:05:41.879Z" },
134
- ]
135
-
136
- [[package]]
137
- name = "cursorweb2api"
138
- version = "0.1.0"
139
- source = { virtual = "." }
140
- dependencies = [
141
- { name = "curl-cffi" },
142
- { name = "fastapi" },
143
- { name = "loguru" },
144
- { name = "sse-starlette" },
145
- { name = "uvicorn" },
146
- ]
147
-
148
- [package.metadata]
149
- requires-dist = [
150
- { name = "curl-cffi", specifier = ">=0.13.0" },
151
- { name = "fastapi", specifier = ">=0.117.1" },
152
- { name = "loguru", specifier = ">=0.7.3" },
153
- { name = "sse-starlette", specifier = ">=3.0.2" },
154
- { name = "uvicorn", specifier = ">=0.37.0" },
155
- ]
156
-
157
- [[package]]
158
- name = "fastapi"
159
- version = "0.117.1"
160
- source = { registry = "https://pypi.org/simple" }
161
- dependencies = [
162
- { name = "pydantic" },
163
- { name = "starlette" },
164
- { name = "typing-extensions" },
165
- ]
166
- sdist = { url = "https://files.pythonhosted.org/packages/7e/7e/d9788300deaf416178f61fb3c2ceb16b7d0dc9f82a08fdb87a5e64ee3cc7/fastapi-0.117.1.tar.gz", hash = "sha256:fb2d42082d22b185f904ca0ecad2e195b851030bd6c5e4c032d1c981240c631a", size = 307155, upload-time = "2025-09-20T20:16:56.663Z" }
167
- wheels = [
168
- { url = "https://files.pythonhosted.org/packages/6d/45/d9d3e8eeefbe93be1c50060a9d9a9f366dba66f288bb518a9566a23a8631/fastapi-0.117.1-py3-none-any.whl", hash = "sha256:33c51a0d21cab2b9722d4e56dbb9316f3687155be6b276191790d8da03507552", size = 95959, upload-time = "2025-09-20T20:16:53.661Z" },
169
- ]
170
-
171
- [[package]]
172
- name = "h11"
173
- version = "0.16.0"
174
- source = { registry = "https://pypi.org/simple" }
175
- sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" }
176
- wheels = [
177
- { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" },
178
- ]
179
-
180
- [[package]]
181
- name = "idna"
182
- version = "3.10"
183
- source = { registry = "https://pypi.org/simple" }
184
- sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" }
185
- wheels = [
186
- { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" },
187
- ]
188
-
189
- [[package]]
190
- name = "loguru"
191
- version = "0.7.3"
192
- source = { registry = "https://pypi.org/simple" }
193
- dependencies = [
194
- { name = "colorama", marker = "sys_platform == 'win32'" },
195
- { name = "win32-setctime", marker = "sys_platform == 'win32'" },
196
- ]
197
- sdist = { url = "https://files.pythonhosted.org/packages/3a/05/a1dae3dffd1116099471c643b8924f5aa6524411dc6c63fdae648c4f1aca/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6", size = 63559, upload-time = "2024-12-06T11:20:56.608Z" }
198
- wheels = [
199
- { url = "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c", size = 61595, upload-time = "2024-12-06T11:20:54.538Z" },
200
- ]
201
-
202
- [[package]]
203
- name = "pycparser"
204
- version = "2.23"
205
- source = { registry = "https://pypi.org/simple" }
206
- sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" }
207
- wheels = [
208
- { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" },
209
- ]
210
-
211
- [[package]]
212
- name = "pydantic"
213
- version = "2.11.9"
214
- source = { registry = "https://pypi.org/simple" }
215
- dependencies = [
216
- { name = "annotated-types" },
217
- { name = "pydantic-core" },
218
- { name = "typing-extensions" },
219
- { name = "typing-inspection" },
220
- ]
221
- sdist = { url = "https://files.pythonhosted.org/packages/ff/5d/09a551ba512d7ca404d785072700d3f6727a02f6f3c24ecfd081c7cf0aa8/pydantic-2.11.9.tar.gz", hash = "sha256:6b8ffda597a14812a7975c90b82a8a2e777d9257aba3453f973acd3c032a18e2", size = 788495, upload-time = "2025-09-13T11:26:39.325Z" }
222
- wheels = [
223
- { url = "https://files.pythonhosted.org/packages/3e/d3/108f2006987c58e76691d5ae5d200dd3e0f532cb4e5fa3560751c3a1feba/pydantic-2.11.9-py3-none-any.whl", hash = "sha256:c42dd626f5cfc1c6950ce6205ea58c93efa406da65f479dcb4029d5934857da2", size = 444855, upload-time = "2025-09-13T11:26:36.909Z" },
224
- ]
225
-
226
- [[package]]
227
- name = "pydantic-core"
228
- version = "2.33.2"
229
- source = { registry = "https://pypi.org/simple" }
230
- dependencies = [
231
- { name = "typing-extensions" },
232
- ]
233
- sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" }
234
- wheels = [
235
- { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" },
236
- { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" },
237
- { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" },
238
- { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" },
239
- { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" },
240
- { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" },
241
- { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" },
242
- { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" },
243
- { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" },
244
- { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" },
245
- { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" },
246
- { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" },
247
- { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" },
248
- { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" },
249
- { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" },
250
- { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" },
251
- { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" },
252
- { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" },
253
- { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" },
254
- { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" },
255
- { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" },
256
- { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" },
257
- { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" },
258
- { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" },
259
- { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" },
260
- { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" },
261
- { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" },
262
- { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" },
263
- { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" },
264
- { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" },
265
- { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" },
266
- ]
267
-
268
- [[package]]
269
- name = "sniffio"
270
- version = "1.3.1"
271
- source = { registry = "https://pypi.org/simple" }
272
- sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" }
273
- wheels = [
274
- { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" },
275
- ]
276
-
277
- [[package]]
278
- name = "sse-starlette"
279
- version = "3.0.2"
280
- source = { registry = "https://pypi.org/simple" }
281
- dependencies = [
282
- { name = "anyio" },
283
- ]
284
- sdist = { url = "https://files.pythonhosted.org/packages/42/6f/22ed6e33f8a9e76ca0a412405f31abb844b779d52c5f96660766edcd737c/sse_starlette-3.0.2.tar.gz", hash = "sha256:ccd60b5765ebb3584d0de2d7a6e4f745672581de4f5005ab31c3a25d10b52b3a", size = 20985, upload-time = "2025-07-27T09:07:44.565Z" }
285
- wheels = [
286
- { url = "https://files.pythonhosted.org/packages/ef/10/c78f463b4ef22eef8491f218f692be838282cd65480f6e423d7730dfd1fb/sse_starlette-3.0.2-py3-none-any.whl", hash = "sha256:16b7cbfddbcd4eaca11f7b586f3b8a080f1afe952c15813455b162edea619e5a", size = 11297, upload-time = "2025-07-27T09:07:43.268Z" },
287
- ]
288
-
289
- [[package]]
290
- name = "starlette"
291
- version = "0.48.0"
292
- source = { registry = "https://pypi.org/simple" }
293
- dependencies = [
294
- { name = "anyio" },
295
- { name = "typing-extensions", marker = "python_full_version < '3.13'" },
296
- ]
297
- sdist = { url = "https://files.pythonhosted.org/packages/a7/a5/d6f429d43394057b67a6b5bbe6eae2f77a6bf7459d961fdb224bf206eee6/starlette-0.48.0.tar.gz", hash = "sha256:7e8cee469a8ab2352911528110ce9088fdc6a37d9876926e73da7ce4aa4c7a46", size = 2652949, upload-time = "2025-09-13T08:41:05.699Z" }
298
- wheels = [
299
- { url = "https://files.pythonhosted.org/packages/be/72/2db2f49247d0a18b4f1bb9a5a39a0162869acf235f3a96418363947b3d46/starlette-0.48.0-py3-none-any.whl", hash = "sha256:0764ca97b097582558ecb498132ed0c7d942f233f365b86ba37770e026510659", size = 73736, upload-time = "2025-09-13T08:41:03.869Z" },
300
- ]
301
-
302
- [[package]]
303
- name = "typing-extensions"
304
- version = "4.15.0"
305
- source = { registry = "https://pypi.org/simple" }
306
- sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" }
307
- wheels = [
308
- { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" },
309
- ]
310
-
311
- [[package]]
312
- name = "typing-inspection"
313
- version = "0.4.1"
314
- source = { registry = "https://pypi.org/simple" }
315
- dependencies = [
316
- { name = "typing-extensions" },
317
- ]
318
- sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" }
319
- wheels = [
320
- { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" },
321
- ]
322
-
323
- [[package]]
324
- name = "uvicorn"
325
- version = "0.37.0"
326
- source = { registry = "https://pypi.org/simple" }
327
- dependencies = [
328
- { name = "click" },
329
- { name = "h11" },
330
- ]
331
- sdist = { url = "https://files.pythonhosted.org/packages/71/57/1616c8274c3442d802621abf5deb230771c7a0fec9414cb6763900eb3868/uvicorn-0.37.0.tar.gz", hash = "sha256:4115c8add6d3fd536c8ee77f0e14a7fd2ebba939fed9b02583a97f80648f9e13", size = 80367, upload-time = "2025-09-23T13:33:47.486Z" }
332
- wheels = [
333
- { url = "https://files.pythonhosted.org/packages/85/cd/584a2ceb5532af99dd09e50919e3615ba99aa127e9850eafe5f31ddfdb9a/uvicorn-0.37.0-py3-none-any.whl", hash = "sha256:913b2b88672343739927ce381ff9e2ad62541f9f8289664fa1d1d3803fa2ce6c", size = 67976, upload-time = "2025-09-23T13:33:45.842Z" },
334
- ]
335
-
336
- [[package]]
337
- name = "win32-setctime"
338
- version = "1.2.0"
339
- source = { registry = "https://pypi.org/simple" }
340
- sdist = { url = "https://files.pythonhosted.org/packages/b3/8f/705086c9d734d3b663af0e9bb3d4de6578d08f46b1b101c2442fd9aecaa2/win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0", size = 4867, upload-time = "2024-12-07T15:28:28.314Z" }
341
- wheels = [
342
- { url = "https://files.pythonhosted.org/packages/e1/07/c6fe3ad3e685340704d314d765b7912993bcb8dc198f0e7a89382d37974b/win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390", size = 4083, upload-time = "2024-12-07T15:28:26.465Z" },
343
- ]