chore: update workspace config and memory
This commit is contained in:
1
projects/KisStock
Submodule
1
projects/KisStock
Submodule
Submodule projects/KisStock added at 86c1c54126
1
projects/SimpleMarcEditorWeb
Submodule
1
projects/SimpleMarcEditorWeb
Submodule
Submodule projects/SimpleMarcEditorWeb added at 05667a424e
27
projects/auto-trader/LIVE_ENABLE_CHECKLIST.md
Normal file
27
projects/auto-trader/LIVE_ENABLE_CHECKLIST.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# 실주문 전환 체크리스트
|
||||
|
||||
## 현재 상태
|
||||
- 계좌 타입: VIRTUAL
|
||||
- 실주문: 비활성 (`enable_orders=false`)
|
||||
- 알림: 활성 가능
|
||||
- API 호출 간격: 300ms
|
||||
|
||||
## 실주문 전환 전 필수 확인
|
||||
1. 최소 2~5 거래일 동안 모의투자 로그 확인
|
||||
2. `signals.jsonl`, `orders.jsonl`, `alerts.jsonl` 검토
|
||||
3. 중복 주문 없는지 확인
|
||||
4. 손절/익절 기준이 의도대로 동작하는지 확인
|
||||
5. 장 시작 직후/장 마감 직전 오작동 없는지 확인
|
||||
6. 종목당 최대금액, 1일 매수 횟수 제한 확인
|
||||
7. 텔레그램 알림이 정상 수신되는지 확인
|
||||
8. 실계좌 전환 시 `KIS_ACCOUNT_TYPE=REAL` 변경 여부 확인
|
||||
9. 실계좌에서는 최초 하루는 소액/1주만 테스트
|
||||
|
||||
## 실주문 전환 방법
|
||||
- `strategy_config.json`에서 `enable_orders`를 `true`로 변경
|
||||
- KIS 설정이 실계좌라면 주문이 실제로 나감
|
||||
|
||||
## 권장 순서
|
||||
1. 모의투자 검증
|
||||
2. 소액 실주문 시험
|
||||
3. 한도 점진 확대
|
||||
82
projects/auto-trader/README.md
Normal file
82
projects/auto-trader/README.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# Auto Trader (KIS MCP / Virtual-safe)
|
||||
|
||||
모의투자 계좌 기준으로 자동매매 골격을 만든 프로젝트입니다.
|
||||
기본값은 **신호는 생성하지만 실제 주문은 넣지 않는 안전 모드**입니다.
|
||||
|
||||
## 현재 탑재한 조건 5개
|
||||
|
||||
### 매수 조건 3개
|
||||
1. **buy_gap_strength**
|
||||
- 현재가가 전일종가 대비 +1.0% 이상
|
||||
- 현재가가 시가 위
|
||||
|
||||
2. **buy_reclaim_after_dip**
|
||||
- 장중 저가가 시가 대비 -0.5% 이하로 밀린 적 있음
|
||||
- 현재가가 다시 시가 위로 회복
|
||||
- 현재가가 저가 대비 +1.0% 이상 반등
|
||||
|
||||
3. **buy_near_day_high**
|
||||
- 현재가가 당일 고가에서 0.5% 이내
|
||||
- 당일 등락률 플러스
|
||||
|
||||
### 매도 조건 2개
|
||||
4. **sell_take_profit**
|
||||
- 평가수익률 +3.0% 이상이면 매도 신호
|
||||
|
||||
5. **sell_stop_loss_or_fade**
|
||||
- 평가수익률 -2.0% 이하이면 손절 신호
|
||||
- 또는 현재가가 시가 대비 -1.5% 이하로 밀리면 약세 이탈로 매도 신호
|
||||
|
||||
## 안전장치
|
||||
- `enable_orders: false` 기본값
|
||||
- API 호출 간격 기본 300ms
|
||||
- API 오류 시 재시도
|
||||
- 종목당 최대 포지션 금액 제한
|
||||
- 1일 1회 매수 제한
|
||||
- 장 시간 외 주문 차단
|
||||
|
||||
## 감시 종목
|
||||
- SK하이닉스 (000660)
|
||||
- 삼성전자 (005930)
|
||||
- 이오테크닉스 (039030)
|
||||
|
||||
## 실행
|
||||
```bash
|
||||
cd /home/arin/.openclaw/workspace/projects/auto-trader
|
||||
/home/arin/.openclaw/workspace/KIS_MCP_Server/.venv/bin/python auto_trader.py
|
||||
```
|
||||
|
||||
## 1회 실행 + 텔레그램 알림
|
||||
```bash
|
||||
cd /home/arin/.openclaw/workspace/projects/auto-trader
|
||||
./run_cycle.sh
|
||||
```
|
||||
|
||||
## 백그라운드 실행
|
||||
```bash
|
||||
cd /home/arin/.openclaw/workspace/projects/auto-trader
|
||||
./start_trader.sh
|
||||
./stop_trader.sh
|
||||
```
|
||||
|
||||
백그라운드 실행은 `trader_daemon.py`를 돌리며,
|
||||
- 신호 생성
|
||||
- 로그 저장
|
||||
- 새 알림 발견 시 텔레그램 전송
|
||||
을 한 번에 처리합니다.
|
||||
|
||||
## 설정 파일
|
||||
- `strategy_config.json`
|
||||
|
||||
실주문으로 전환하려면:
|
||||
- `enable_orders`를 `true`로 변경
|
||||
- 먼저 반드시 모의투자에서 충분히 검증
|
||||
|
||||
## 로그 파일
|
||||
- `signals.jsonl`: 신호 기록
|
||||
- `orders.jsonl`: 주문 실행 또는 드라이런 기록
|
||||
- `state.json`: 일일 매수 횟수 등 상태 저장
|
||||
|
||||
## 주의
|
||||
이 전략은 수익 보장용이 아니라 **자동매매 인프라 시작점**입니다.
|
||||
조건 수치는 이후 백테스트/실시간 관찰로 조정해야 합니다.
|
||||
BIN
projects/auto-trader/__pycache__/auto_trader.cpython-313.pyc
Normal file
BIN
projects/auto-trader/__pycache__/auto_trader.cpython-313.pyc
Normal file
Binary file not shown.
371
projects/auto-trader/auto_trader.py
Normal file
371
projects/auto-trader/auto_trader.py
Normal file
@@ -0,0 +1,371 @@
|
||||
import asyncio
|
||||
import json
|
||||
import time
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Tuple
|
||||
|
||||
BASE = Path('/home/arin/.openclaw/workspace/projects/auto-trader')
|
||||
CONFIG_PATH = BASE / 'strategy_config.json'
|
||||
STATE_PATH = BASE / 'state.json'
|
||||
SIGNALS_PATH = BASE / 'signals.jsonl'
|
||||
ORDERS_PATH = BASE / 'orders.jsonl'
|
||||
ALERTS_PATH = BASE / 'alerts.jsonl'
|
||||
|
||||
import sys
|
||||
sys.path.insert(0, '/home/arin/.openclaw/workspace/KIS_MCP_Server')
|
||||
from server import inquery_stock_price, inquery_balance, order_stock # type: ignore
|
||||
|
||||
LAST_API_CALL_AT = 0.0
|
||||
|
||||
|
||||
def load_json(path: Path, default: Any):
|
||||
if not path.exists():
|
||||
return default
|
||||
try:
|
||||
return json.loads(path.read_text(encoding='utf-8'))
|
||||
except Exception:
|
||||
return default
|
||||
|
||||
|
||||
def save_json(path: Path, data: Any) -> None:
|
||||
path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding='utf-8')
|
||||
|
||||
|
||||
def append_jsonl(path: Path, row: Dict[str, Any]) -> None:
|
||||
with open(path, 'a', encoding='utf-8') as f:
|
||||
f.write(json.dumps(row, ensure_ascii=False) + '\n')
|
||||
|
||||
|
||||
def to_int(v: Any) -> int:
|
||||
try:
|
||||
return int(str(v).replace(',', '').strip())
|
||||
except Exception:
|
||||
return 0
|
||||
|
||||
|
||||
def to_float(v: Any) -> float:
|
||||
try:
|
||||
return float(str(v).replace(',', '').strip())
|
||||
except Exception:
|
||||
return 0.0
|
||||
|
||||
|
||||
def now_ts() -> str:
|
||||
return datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
|
||||
def get_api_interval_seconds(cfg: Dict[str, Any]) -> float:
|
||||
return max(0.0, float(cfg.get('api_call_interval_ms', 300)) / 1000.0)
|
||||
|
||||
|
||||
def get_retry_count(cfg: Dict[str, Any]) -> int:
|
||||
return max(0, int(cfg.get('api_retry_count', 2)))
|
||||
|
||||
|
||||
def get_retry_backoff_seconds(cfg: Dict[str, Any]) -> float:
|
||||
return max(0.0, float(cfg.get('api_retry_backoff_ms', 600)) / 1000.0)
|
||||
|
||||
|
||||
async def throttle_api_call(cfg: Dict[str, Any]) -> None:
|
||||
global LAST_API_CALL_AT
|
||||
interval = get_api_interval_seconds(cfg)
|
||||
now = time.monotonic()
|
||||
wait_for = interval - (now - LAST_API_CALL_AT)
|
||||
if wait_for > 0:
|
||||
await asyncio.sleep(wait_for)
|
||||
LAST_API_CALL_AT = time.monotonic()
|
||||
|
||||
|
||||
async def call_with_retry(func, *args, cfg: Dict[str, Any], **kwargs):
|
||||
retries = get_retry_count(cfg)
|
||||
backoff = get_retry_backoff_seconds(cfg)
|
||||
last_error = None
|
||||
for attempt in range(retries + 1):
|
||||
try:
|
||||
await throttle_api_call(cfg)
|
||||
return await func(*args, **kwargs)
|
||||
except Exception as e:
|
||||
last_error = e
|
||||
if attempt >= retries:
|
||||
break
|
||||
await asyncio.sleep(backoff * (attempt + 1))
|
||||
raise last_error
|
||||
|
||||
|
||||
def market_is_open(now: datetime | None = None) -> bool:
|
||||
now = now or datetime.now()
|
||||
if now.weekday() >= 5:
|
||||
return False
|
||||
hhmm = now.hour * 100 + now.minute
|
||||
return 900 <= hhmm <= 1530
|
||||
|
||||
|
||||
async def fetch_balance_map(cfg: Dict[str, Any]) -> Dict[str, Dict[str, Any]]:
|
||||
raw = await call_with_retry(inquery_balance, cfg=cfg)
|
||||
items = raw.get('output1', []) if isinstance(raw, dict) else []
|
||||
result = {}
|
||||
for item in items:
|
||||
qty = to_int(item.get('hldg_qty', 0))
|
||||
if qty <= 0:
|
||||
continue
|
||||
symbol = item.get('pdno')
|
||||
if not symbol:
|
||||
continue
|
||||
result[symbol] = {
|
||||
'symbol': symbol,
|
||||
'name': item.get('prdt_name', ''),
|
||||
'qty': qty,
|
||||
'avg_price': to_float(item.get('pchs_avg_pric', 0)),
|
||||
'profit_rate': to_float(item.get('evlu_pfls_rt', 0)),
|
||||
'profit_amount': to_int(item.get('evlu_pfls_amt', 0)),
|
||||
'position_value': to_int(item.get('evlu_amt', 0)),
|
||||
}
|
||||
return result
|
||||
|
||||
|
||||
async def fetch_quote(symbol: str, cfg: Dict[str, Any]) -> Dict[str, Any]:
|
||||
q = await call_with_retry(inquery_stock_price, symbol, cfg=cfg)
|
||||
return {
|
||||
'symbol': symbol,
|
||||
'name': q.get('hts_kor_isnm', ''),
|
||||
'price': to_int(q.get('stck_prpr', 0)),
|
||||
'open': to_int(q.get('stck_oprc', 0)),
|
||||
'high': to_int(q.get('stck_mxpr', 0)),
|
||||
'low': to_int(q.get('stck_llam', 0)),
|
||||
'prev_close': to_int(q.get('stck_prdy_clpr', 0)),
|
||||
'change_pct': to_float(q.get('prdy_ctrt', 0)),
|
||||
'volume': to_int(q.get('acml_vol', 0)),
|
||||
'trading_value': to_int(q.get('acml_tr_pbmn', 0)),
|
||||
}
|
||||
|
||||
|
||||
def pct(a: float, b: float) -> float:
|
||||
if not b:
|
||||
return 0.0
|
||||
return (a - b) / b * 100.0
|
||||
|
||||
|
||||
def eval_buy_rules(quote: Dict[str, Any], holding: Dict[str, Any] | None, cfg: Dict[str, Any], state: Dict[str, Any]) -> List[str]:
|
||||
rules = cfg['rules']
|
||||
signals: List[str] = []
|
||||
price = quote['price']
|
||||
open_ = quote['open']
|
||||
high = quote['high']
|
||||
low = quote['low']
|
||||
prev_close = quote['prev_close']
|
||||
|
||||
if holding:
|
||||
return signals
|
||||
|
||||
r1 = rules['buy_gap_strength']
|
||||
if r1['enabled']:
|
||||
if pct(price, prev_close) >= r1['min_pct_vs_prev_close'] and (not r1['require_above_open'] or price > open_):
|
||||
signals.append('buy_gap_strength')
|
||||
|
||||
r2 = rules['buy_reclaim_after_dip']
|
||||
if r2['enabled']:
|
||||
dipped = pct(low, open_) <= -abs(r2['dip_below_open_pct'])
|
||||
reclaimed = price > open_ if r2['reclaim_above_open'] else True
|
||||
rebound = pct(price, low) >= r2['rebound_from_low_pct']
|
||||
if dipped and reclaimed and rebound:
|
||||
signals.append('buy_reclaim_after_dip')
|
||||
|
||||
r3 = rules['buy_near_day_high']
|
||||
if r3['enabled'] and high > 0:
|
||||
distance_from_high = (high - price) / high * 100.0
|
||||
positive = quote['change_pct'] > 0 if r3['require_positive_day'] else True
|
||||
if distance_from_high <= r3['max_distance_from_high_pct'] and positive:
|
||||
signals.append('buy_near_day_high')
|
||||
|
||||
symbol_state = state.setdefault(quote['symbol'], {'buy_count_today': 0, 'last_buy_date': None})
|
||||
today = datetime.now().strftime('%Y-%m-%d')
|
||||
if symbol_state.get('last_buy_date') != today:
|
||||
symbol_state['buy_count_today'] = 0
|
||||
if symbol_state.get('buy_count_today', 0) >= cfg['max_daily_buys_per_symbol']:
|
||||
return []
|
||||
|
||||
return signals
|
||||
|
||||
|
||||
def eval_sell_rules(quote: Dict[str, Any], holding: Dict[str, Any] | None, cfg: Dict[str, Any]) -> List[str]:
|
||||
if not holding:
|
||||
return []
|
||||
rules = cfg['rules']
|
||||
signals: List[str] = []
|
||||
|
||||
profit_rate = holding.get('profit_rate', 0.0)
|
||||
price = quote['price']
|
||||
open_ = quote['open']
|
||||
|
||||
r4 = rules['sell_take_profit']
|
||||
if r4['enabled'] and profit_rate >= r4['take_profit_pct']:
|
||||
signals.append('sell_take_profit')
|
||||
|
||||
r5 = rules['sell_stop_loss_or_fade']
|
||||
fade_pct = pct(price, open_)
|
||||
if r5['enabled'] and (profit_rate <= r5['stop_loss_pct'] or fade_pct <= r5['fade_from_open_pct']):
|
||||
signals.append('sell_stop_loss_or_fade')
|
||||
|
||||
return signals
|
||||
|
||||
|
||||
def calc_buy_qty(price: int, cfg: Dict[str, Any], holding: Dict[str, Any] | None) -> int:
|
||||
if price <= 0:
|
||||
return 0
|
||||
budget = int(cfg['buy_budget_per_trade'])
|
||||
max_pos = int(cfg['max_position_value_per_symbol'])
|
||||
current_value = int(holding['position_value']) if holding else 0
|
||||
room = max(0, max_pos - current_value)
|
||||
usable = min(budget, room)
|
||||
qty = usable // price
|
||||
return max(0, qty)
|
||||
|
||||
|
||||
def make_alert_key(symbol: str, side: str, reasons: List[str], ts: str) -> str:
|
||||
minute = ts[:16]
|
||||
return f"{minute}|{symbol}|{side}|{'/'.join(sorted(reasons))}"
|
||||
|
||||
|
||||
def maybe_record_alert(symbol: str, name: str, side: str, reasons: List[str], quote: Dict[str, Any], state: Dict[str, Any]) -> Dict[str, Any] | None:
|
||||
if not reasons:
|
||||
return None
|
||||
ts = now_ts()
|
||||
key = make_alert_key(symbol, side, reasons, ts)
|
||||
alert_state = state.setdefault('_alerts', {})
|
||||
if alert_state.get('last_key') == key:
|
||||
return None
|
||||
alert = {
|
||||
'time': ts,
|
||||
'key': key,
|
||||
'symbol': symbol,
|
||||
'name': name,
|
||||
'side': side,
|
||||
'reasons': reasons,
|
||||
'price': quote.get('price', 0),
|
||||
'change_pct': quote.get('change_pct', 0),
|
||||
}
|
||||
append_jsonl(ALERTS_PATH, alert)
|
||||
alert_state['last_key'] = key
|
||||
return alert
|
||||
|
||||
|
||||
async def execute_buy(symbol: str, quote: Dict[str, Any], reasons: List[str], cfg: Dict[str, Any], state: Dict[str, Any]) -> Dict[str, Any]:
|
||||
qty = calc_buy_qty(quote['price'], cfg, None)
|
||||
if qty <= 0:
|
||||
return {'action': 'buy_skipped', 'symbol': symbol, 'reason': 'budget_or_position_limit', 'time': now_ts()}
|
||||
|
||||
row = {
|
||||
'time': now_ts(),
|
||||
'action': 'buy',
|
||||
'symbol': symbol,
|
||||
'name': quote['name'],
|
||||
'qty': qty,
|
||||
'price': quote['price'],
|
||||
'reasons': reasons,
|
||||
'dry_run': not cfg['enable_orders'],
|
||||
}
|
||||
if cfg['enable_orders']:
|
||||
row['result'] = await call_with_retry(order_stock, symbol, qty, 0, 'buy', cfg=cfg)
|
||||
append_jsonl(ORDERS_PATH, row)
|
||||
symbol_state = state.setdefault(symbol, {'buy_count_today': 0, 'last_buy_date': None})
|
||||
symbol_state['buy_count_today'] = int(symbol_state.get('buy_count_today', 0)) + 1
|
||||
symbol_state['last_buy_date'] = datetime.now().strftime('%Y-%m-%d')
|
||||
return row
|
||||
|
||||
|
||||
async def execute_sell(symbol: str, quote: Dict[str, Any], holding: Dict[str, Any], reasons: List[str], cfg: Dict[str, Any]) -> Dict[str, Any]:
|
||||
qty = int(holding['qty']) if cfg.get('sell_all_on_signal', True) else 1
|
||||
row = {
|
||||
'time': now_ts(),
|
||||
'action': 'sell',
|
||||
'symbol': symbol,
|
||||
'name': quote['name'],
|
||||
'qty': qty,
|
||||
'price': quote['price'],
|
||||
'reasons': reasons,
|
||||
'dry_run': not cfg['enable_orders'],
|
||||
}
|
||||
if cfg['enable_orders']:
|
||||
row['result'] = await call_with_retry(order_stock, symbol, qty, 0, 'sell', cfg=cfg)
|
||||
append_jsonl(ORDERS_PATH, row)
|
||||
return row
|
||||
|
||||
|
||||
async def run_once() -> Dict[str, Any]:
|
||||
cfg = load_json(CONFIG_PATH, {})
|
||||
state = load_json(STATE_PATH, {})
|
||||
balance_map = await fetch_balance_map(cfg)
|
||||
|
||||
results = []
|
||||
for item in cfg.get('symbols', []):
|
||||
if not item.get('enabled', True):
|
||||
continue
|
||||
symbol = item['symbol']
|
||||
holding = balance_map.get(symbol)
|
||||
|
||||
try:
|
||||
quote = await fetch_quote(symbol, cfg)
|
||||
except Exception as e:
|
||||
error_row = {
|
||||
'time': now_ts(),
|
||||
'symbol': symbol,
|
||||
'name': item.get('name', ''),
|
||||
'error': str(e),
|
||||
}
|
||||
append_jsonl(SIGNALS_PATH, error_row)
|
||||
results.append(error_row)
|
||||
continue
|
||||
|
||||
buy_reasons = eval_buy_rules(quote, holding, cfg, state)
|
||||
sell_reasons = eval_sell_rules(quote, holding, cfg)
|
||||
|
||||
signal_row = {
|
||||
'time': now_ts(),
|
||||
'symbol': symbol,
|
||||
'name': quote['name'],
|
||||
'quote': quote,
|
||||
'holding': holding,
|
||||
'buy_reasons': buy_reasons,
|
||||
'sell_reasons': sell_reasons,
|
||||
}
|
||||
append_jsonl(SIGNALS_PATH, signal_row)
|
||||
|
||||
action = None
|
||||
if market_is_open():
|
||||
if sell_reasons and holding:
|
||||
maybe_record_alert(symbol, quote['name'], 'sell', sell_reasons, quote, state)
|
||||
action = await execute_sell(symbol, quote, holding, sell_reasons, cfg)
|
||||
elif buy_reasons and not holding:
|
||||
maybe_record_alert(symbol, quote['name'], 'buy', buy_reasons, quote, state)
|
||||
action = await execute_buy(symbol, quote, buy_reasons, cfg, state)
|
||||
else:
|
||||
action = {'action': 'market_closed', 'symbol': symbol, 'time': now_ts()}
|
||||
|
||||
results.append({
|
||||
'symbol': symbol,
|
||||
'name': quote['name'],
|
||||
'price': quote['price'],
|
||||
'buy_reasons': buy_reasons,
|
||||
'sell_reasons': sell_reasons,
|
||||
'action': action,
|
||||
})
|
||||
|
||||
save_json(STATE_PATH, state)
|
||||
return {'time': now_ts(), 'mode': cfg.get('mode'), 'enable_orders': cfg.get('enable_orders'), 'results': results}
|
||||
|
||||
|
||||
async def main():
|
||||
cfg = load_json(CONFIG_PATH, {})
|
||||
poll_seconds = int(cfg.get('poll_seconds', 60))
|
||||
while True:
|
||||
try:
|
||||
result = await run_once()
|
||||
print(json.dumps(result, ensure_ascii=False))
|
||||
except Exception as e:
|
||||
print(json.dumps({'time': now_ts(), 'error': str(e)}, ensure_ascii=False))
|
||||
await asyncio.sleep(poll_seconds)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
asyncio.run(main())
|
||||
5350
projects/auto-trader/logs/trader-2026-03-23-172428.log
Normal file
5350
projects/auto-trader/logs/trader-2026-03-23-172428.log
Normal file
File diff suppressed because it is too large
Load Diff
3
projects/auto-trader/notify_state.json
Normal file
3
projects/auto-trader/notify_state.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"last_key": null
|
||||
}
|
||||
94
projects/auto-trader/notify_telegram.py
Normal file
94
projects/auto-trader/notify_telegram.py
Normal file
@@ -0,0 +1,94 @@
|
||||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
BASE = Path('/home/arin/.openclaw/workspace/projects/auto-trader')
|
||||
ALERTS_PATH = BASE / 'alerts.jsonl'
|
||||
NOTIFY_STATE_PATH = BASE / 'notify_state.json'
|
||||
CONFIG_PATH = BASE / 'telegram_notify_config.json'
|
||||
|
||||
|
||||
def load_json(path: Path, default):
|
||||
if not path.exists():
|
||||
return default
|
||||
try:
|
||||
return json.loads(path.read_text(encoding='utf-8'))
|
||||
except Exception:
|
||||
return default
|
||||
|
||||
|
||||
def save_json(path: Path, data):
|
||||
path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding='utf-8')
|
||||
|
||||
|
||||
def load_alerts():
|
||||
if not ALERTS_PATH.exists():
|
||||
return []
|
||||
rows = []
|
||||
for line in ALERTS_PATH.read_text(encoding='utf-8').splitlines():
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
try:
|
||||
rows.append(json.loads(line))
|
||||
except Exception:
|
||||
pass
|
||||
return rows
|
||||
|
||||
|
||||
def format_msg(alert: dict) -> str:
|
||||
side = '매수' if alert.get('side') == 'buy' else '매도'
|
||||
reasons = ', '.join(alert.get('reasons', []))
|
||||
return (
|
||||
f"[자동매매 알림]\n"
|
||||
f"시간: {alert.get('time')}\n"
|
||||
f"종목: {alert.get('name')}({alert.get('symbol')})\n"
|
||||
f"신호: {side}\n"
|
||||
f"현재가: {alert.get('price'):,}원\n"
|
||||
f"등락률: {alert.get('change_pct')}%\n"
|
||||
f"조건: {reasons}"
|
||||
)
|
||||
|
||||
|
||||
def send_message(cfg: dict, text: str):
|
||||
cmd = [
|
||||
'openclaw', 'message', 'send',
|
||||
'--channel', cfg['channel'],
|
||||
'--target', cfg['target'],
|
||||
'--message', text,
|
||||
]
|
||||
if cfg.get('account'):
|
||||
cmd.extend(['--account', cfg['account']])
|
||||
subprocess.run(cmd, check=True)
|
||||
|
||||
|
||||
def main():
|
||||
cfg = load_json(CONFIG_PATH, {})
|
||||
if not cfg.get('enabled'):
|
||||
print(json.dumps({'status': 'disabled'}, ensure_ascii=False))
|
||||
return
|
||||
|
||||
alerts = load_alerts()
|
||||
state = load_json(NOTIFY_STATE_PATH, {'last_key': None})
|
||||
last_key = state.get('last_key')
|
||||
|
||||
if last_key is None:
|
||||
new_alerts = alerts[-1:] if alerts else []
|
||||
else:
|
||||
keys = [a.get('key') for a in alerts]
|
||||
if last_key in keys:
|
||||
idx = keys.index(last_key)
|
||||
new_alerts = alerts[idx + 1:]
|
||||
else:
|
||||
new_alerts = alerts[-1:] if alerts else []
|
||||
|
||||
for alert in new_alerts:
|
||||
send_message(cfg, format_msg(alert))
|
||||
state['last_key'] = alert.get('key')
|
||||
|
||||
save_json(NOTIFY_STATE_PATH, state)
|
||||
print(json.dumps({'sent': len(new_alerts), 'last_key': state.get('last_key')}, ensure_ascii=False))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
10
projects/auto-trader/run_cycle.sh
Executable file
10
projects/auto-trader/run_cycle.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd /home/arin/.openclaw/workspace/projects/auto-trader
|
||||
PY=/home/arin/.openclaw/workspace/KIS_MCP_Server/.venv/bin/python
|
||||
$PY - <<'PY'
|
||||
import asyncio, json, auto_trader
|
||||
result = asyncio.run(auto_trader.run_once())
|
||||
print(json.dumps(result, ensure_ascii=False))
|
||||
PY
|
||||
$PY notify_telegram.py
|
||||
227
projects/auto-trader/signals.jsonl
Normal file
227
projects/auto-trader/signals.jsonl
Normal file
@@ -0,0 +1,227 @@
|
||||
{"time": "2026-03-23 17:11:31", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:11:31", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:11:32", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:12:32", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:12:32", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:13:30", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:13:30", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:13:30", "symbol": "039030", "name": "이오테크닉스", "error": "Failed to get stock price: {\"rt_cd\":\"1\",\"msg1\":\"초당 거래건수를 초과하였습니다.\",\"message\":\"EGW00201\"}"}
|
||||
{"time": "2026-03-23 17:20:09", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:20:10", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:20:10", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:23:53", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:23:53", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:23:54", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:24:28", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:24:29", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:24:29", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:25:29", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:25:30", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:25:30", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:26:30", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:26:31", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:26:31", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:27:32", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:27:32", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:27:33", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:28:33", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:28:34", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:28:34", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:29:34", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:29:35", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:29:35", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:30:36", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:30:36", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:30:37", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:31:37", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:31:38", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:31:38", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:32:38", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:32:39", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:32:39", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:33:39", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:33:40", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:33:40", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:34:41", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:34:41", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:34:42", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:35:42", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:35:43", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:35:43", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:36:43", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:36:44", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:36:44", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:37:44", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:37:45", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:37:45", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:38:46", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:38:46", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:38:47", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:39:47", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:39:48", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:39:48", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:40:49", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:40:49", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:40:50", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:41:51", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:41:51", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:41:52", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:42:52", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:42:53", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:42:53", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:43:53", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:43:54", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:43:54", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:44:55", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:44:55", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:44:56", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:45:57", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:45:57", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:45:58", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:46:58", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:46:59", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:46:59", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:47:59", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:48:00", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:48:00", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:49:00", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:49:01", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:49:01", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:50:02", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:50:02", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:50:03", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:51:03", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:51:04", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:51:04", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:52:04", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:52:05", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:52:05", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:53:06", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:53:06", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:53:07", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:54:07", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:54:08", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:54:08", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:55:08", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:55:09", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:55:09", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:56:09", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:56:10", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:56:10", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:57:11", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:57:11", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:57:12", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:58:12", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:58:13", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:58:13", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:59:13", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:59:14", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 17:59:14", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:00:15", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:00:15", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:00:16", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:01:16", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:01:17", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:01:17", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:02:17", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:02:18", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:02:18", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:03:19", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:03:19", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:03:20", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:04:20", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:04:21", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:04:21", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:05:21", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:05:22", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:05:22", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:06:23", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:06:23", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:06:24", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:07:24", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:07:25", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:07:25", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:08:25", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3908718, "trading_value": 3679875155000}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:08:26", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30258064, "trading_value": 5704694379250}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:08:26", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:09:26", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:09:27", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:09:27", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:10:28", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:10:28", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:10:29", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:11:29", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:11:30", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:11:30", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:12:30", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:12:31", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:12:31", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:13:32", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:13:32", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:13:33", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:14:33", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:14:34", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:14:34", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:15:34", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:15:35", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:15:35", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:16:35", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:16:36", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:16:36", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:17:37", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:17:37", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:17:38", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:18:38", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:18:39", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:18:39", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:19:39", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:19:40", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:19:40", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:20:41", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:20:41", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:20:42", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:21:42", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:21:43", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:21:43", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:22:43", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:22:44", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:22:44", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:23:44", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:23:45", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:23:46", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:24:46", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:24:46", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:24:47", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:25:47", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:25:48", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:25:48", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:26:48", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:26:49", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:26:49", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:27:49", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:27:50", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:27:50", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:28:50", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:28:51", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:28:51", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:29:52", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:29:52", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:29:53", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:30:53", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:30:54", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:30:54", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:31:54", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:31:55", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:31:55", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:32:55", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:32:56", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:32:56", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:33:57", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:33:57", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:33:58", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:34:58", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:34:59", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:34:59", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:35:59", "symbol": "000660", "name": "", "quote": {"symbol": "000660", "name": "", "price": 933000, "open": 952000, "high": 1309000, "low": 705000, "prev_close": 0, "change_pct": -7.35, "volume": 3911813, "trading_value": 3682788964415}, "holding": {"symbol": "000660", "name": "SK하이닉스", "qty": 1, "avg_price": 937000.0, "profit_rate": -0.43, "profit_amount": -4000, "position_value": 933000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:36:00", "symbol": "005930", "name": "", "quote": {"symbol": "005930", "name": "", "price": 186300, "open": 190500, "high": 259000, "low": 139600, "prev_close": 0, "change_pct": -6.57, "volume": 30268173, "trading_value": 5706605720650}, "holding": {"symbol": "005930", "name": "삼성전자", "qty": 1, "avg_price": 188100.0, "profit_rate": -0.96, "profit_amount": -1800, "position_value": 186300}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
{"time": "2026-03-23 18:36:00", "symbol": "039030", "name": "", "quote": {"symbol": "039030", "name": "", "price": 419000, "open": 414500, "high": 558000, "low": 301000, "prev_close": 0, "change_pct": -2.44, "volume": 112861, "trading_value": 47503718000}, "holding": {"symbol": "039030", "name": "이오테크닉스", "qty": 1, "avg_price": 428000.0, "profit_rate": -2.1, "profit_amount": -9000, "position_value": 419000}, "buy_reasons": [], "sell_reasons": ["sell_stop_loss_or_fade"]}
|
||||
9
projects/auto-trader/start_trader.sh
Executable file
9
projects/auto-trader/start_trader.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd /home/arin/.openclaw/workspace/projects/auto-trader
|
||||
LOG_DIR=logs
|
||||
mkdir -p "$LOG_DIR"
|
||||
STAMP=$(date +%F-%H%M%S)
|
||||
nohup /home/arin/.openclaw/workspace/KIS_MCP_Server/.venv/bin/python trader_daemon.py >> "$LOG_DIR/trader-$STAMP.log" 2>&1 &
|
||||
echo $! > trader.pid
|
||||
echo "started trader pid $(cat trader.pid)"
|
||||
1
projects/auto-trader/state.json
Normal file
1
projects/auto-trader/state.json
Normal file
@@ -0,0 +1 @@
|
||||
{}
|
||||
15
projects/auto-trader/stop_trader.sh
Executable file
15
projects/auto-trader/stop_trader.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
cd /home/arin/.openclaw/workspace/projects/auto-trader
|
||||
if [ ! -f trader.pid ]; then
|
||||
echo "no trader.pid"
|
||||
exit 0
|
||||
fi
|
||||
PID=$(cat trader.pid)
|
||||
if kill -0 "$PID" 2>/dev/null; then
|
||||
kill "$PID"
|
||||
echo "stopped pid $PID"
|
||||
else
|
||||
echo "pid $PID not running"
|
||||
fi
|
||||
rm -f trader.pid
|
||||
45
projects/auto-trader/strategy_config.json
Normal file
45
projects/auto-trader/strategy_config.json
Normal file
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"mode": "virtual-safe",
|
||||
"enable_orders": false,
|
||||
"poll_seconds": 60,
|
||||
"api_call_interval_ms": 300,
|
||||
"api_retry_count": 2,
|
||||
"api_retry_backoff_ms": 600,
|
||||
"max_symbols": 5,
|
||||
"buy_budget_per_trade": 1000000,
|
||||
"max_position_value_per_symbol": 1200000,
|
||||
"max_daily_buys_per_symbol": 1,
|
||||
"sell_all_on_signal": true,
|
||||
"symbols": [
|
||||
{"symbol": "000660", "name": "SK하이닉스", "enabled": true},
|
||||
{"symbol": "005930", "name": "삼성전자", "enabled": true},
|
||||
{"symbol": "039030", "name": "이오테크닉스", "enabled": true}
|
||||
],
|
||||
"rules": {
|
||||
"buy_gap_strength": {
|
||||
"enabled": true,
|
||||
"min_pct_vs_prev_close": 1.0,
|
||||
"require_above_open": true
|
||||
},
|
||||
"buy_reclaim_after_dip": {
|
||||
"enabled": true,
|
||||
"dip_below_open_pct": 0.5,
|
||||
"reclaim_above_open": true,
|
||||
"rebound_from_low_pct": 1.0
|
||||
},
|
||||
"buy_near_day_high": {
|
||||
"enabled": true,
|
||||
"max_distance_from_high_pct": 0.5,
|
||||
"require_positive_day": true
|
||||
},
|
||||
"sell_take_profit": {
|
||||
"enabled": true,
|
||||
"take_profit_pct": 3.0
|
||||
},
|
||||
"sell_stop_loss_or_fade": {
|
||||
"enabled": true,
|
||||
"stop_loss_pct": -2.0,
|
||||
"fade_from_open_pct": -1.5
|
||||
}
|
||||
}
|
||||
}
|
||||
6
projects/auto-trader/telegram_notify_config.json
Normal file
6
projects/auto-trader/telegram_notify_config.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"enabled": true,
|
||||
"channel": "telegram",
|
||||
"target": "5897670258",
|
||||
"account": "default"
|
||||
}
|
||||
1
projects/auto-trader/trader.pid
Normal file
1
projects/auto-trader/trader.pid
Normal file
@@ -0,0 +1 @@
|
||||
24420
|
||||
33
projects/auto-trader/trader_daemon.py
Normal file
33
projects/auto-trader/trader_daemon.py
Normal file
@@ -0,0 +1,33 @@
|
||||
import asyncio
|
||||
import json
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import auto_trader
|
||||
|
||||
BASE = Path('/home/arin/.openclaw/workspace/projects/auto-trader')
|
||||
PY = '/home/arin/.openclaw/workspace/KIS_MCP_Server/.venv/bin/python'
|
||||
|
||||
|
||||
def load_config():
|
||||
return auto_trader.load_json(auto_trader.CONFIG_PATH, {})
|
||||
|
||||
|
||||
def run_notifier():
|
||||
subprocess.run([PY, str(BASE / 'notify_telegram.py')], check=False)
|
||||
|
||||
|
||||
async def main():
|
||||
while True:
|
||||
try:
|
||||
result = await auto_trader.run_once()
|
||||
print(json.dumps(result, ensure_ascii=False), flush=True)
|
||||
run_notifier()
|
||||
except Exception as e:
|
||||
print(json.dumps({'error': str(e)}, ensure_ascii=False), flush=True)
|
||||
cfg = load_config()
|
||||
await asyncio.sleep(int(cfg.get('poll_seconds', 60)))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
asyncio.run(main())
|
||||
1
projects/browser-mvp
Submodule
1
projects/browser-mvp
Submodule
Submodule projects/browser-mvp added at 53df977b6a
1
projects/kis-trader
Submodule
1
projects/kis-trader
Submodule
Submodule projects/kis-trader added at 29e2c745f5
1
projects/marc-platform
Submodule
1
projects/marc-platform
Submodule
Submodule projects/marc-platform added at f453a5bc57
1
projects/mcp_keyboardmouse
Submodule
1
projects/mcp_keyboardmouse
Submodule
Submodule projects/mcp_keyboardmouse added at ecdd8c553b
1
projects/mcp_sshterminal
Submodule
1
projects/mcp_sshterminal
Submodule
Submodule projects/mcp_sshterminal added at a228f6c046
1
projects/stt-mcp/node_modules/.bin/node-which
generated
vendored
Symbolic link
1
projects/stt-mcp/node_modules/.bin/node-which
generated
vendored
Symbolic link
@@ -0,0 +1 @@
|
||||
../which/bin/node-which
|
||||
1131
projects/stt-mcp/node_modules/.package-lock.json
generated
vendored
Normal file
1131
projects/stt-mcp/node_modules/.package-lock.json
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
21
projects/stt-mcp/node_modules/@hono/node-server/LICENSE
generated
vendored
Normal file
21
projects/stt-mcp/node_modules/@hono/node-server/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 - present, Yusuke Wada and Hono contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
358
projects/stt-mcp/node_modules/@hono/node-server/README.md
generated
vendored
Normal file
358
projects/stt-mcp/node_modules/@hono/node-server/README.md
generated
vendored
Normal file
@@ -0,0 +1,358 @@
|
||||
# Node.js Adapter for Hono
|
||||
|
||||
This adapter `@hono/node-server` allows you to run your Hono application on Node.js.
|
||||
Initially, Hono wasn't designed for Node.js, but with this adapter, you can now use Hono on Node.js.
|
||||
It utilizes web standard APIs implemented in Node.js version 18 or higher.
|
||||
|
||||
## Benchmarks
|
||||
|
||||
Hono is 3.5 times faster than Express.
|
||||
|
||||
Express:
|
||||
|
||||
```txt
|
||||
$ bombardier -d 10s --fasthttp http://localhost:3000/
|
||||
|
||||
Statistics Avg Stdev Max
|
||||
Reqs/sec 16438.94 1603.39 19155.47
|
||||
Latency 7.60ms 7.51ms 559.89ms
|
||||
HTTP codes:
|
||||
1xx - 0, 2xx - 164494, 3xx - 0, 4xx - 0, 5xx - 0
|
||||
others - 0
|
||||
Throughput: 4.55MB/s
|
||||
```
|
||||
|
||||
Hono + `@hono/node-server`:
|
||||
|
||||
```txt
|
||||
$ bombardier -d 10s --fasthttp http://localhost:3000/
|
||||
|
||||
Statistics Avg Stdev Max
|
||||
Reqs/sec 58296.56 5512.74 74403.56
|
||||
Latency 2.14ms 1.46ms 190.92ms
|
||||
HTTP codes:
|
||||
1xx - 0, 2xx - 583059, 3xx - 0, 4xx - 0, 5xx - 0
|
||||
others - 0
|
||||
Throughput: 12.56MB/s
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
It works on Node.js versions greater than 18.x. The specific required Node.js versions are as follows:
|
||||
|
||||
- 18.x => 18.14.1+
|
||||
- 19.x => 19.7.0+
|
||||
- 20.x => 20.0.0+
|
||||
|
||||
Essentially, you can simply use the latest version of each major release.
|
||||
|
||||
## Installation
|
||||
|
||||
You can install it from the npm registry with `npm` command:
|
||||
|
||||
```sh
|
||||
npm install @hono/node-server
|
||||
```
|
||||
|
||||
Or use `yarn`:
|
||||
|
||||
```sh
|
||||
yarn add @hono/node-server
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Just import `@hono/node-server` at the top and write the code as usual.
|
||||
The same code that runs on Cloudflare Workers, Deno, and Bun will work.
|
||||
|
||||
```ts
|
||||
import { serve } from '@hono/node-server'
|
||||
import { Hono } from 'hono'
|
||||
|
||||
const app = new Hono()
|
||||
app.get('/', (c) => c.text('Hono meets Node.js'))
|
||||
|
||||
serve(app, (info) => {
|
||||
console.log(`Listening on http://localhost:${info.port}`) // Listening on http://localhost:3000
|
||||
})
|
||||
```
|
||||
|
||||
For example, run it using `ts-node`. Then an HTTP server will be launched. The default port is `3000`.
|
||||
|
||||
```sh
|
||||
ts-node ./index.ts
|
||||
```
|
||||
|
||||
Open `http://localhost:3000` with your browser.
|
||||
|
||||
## Options
|
||||
|
||||
### `port`
|
||||
|
||||
```ts
|
||||
serve({
|
||||
fetch: app.fetch,
|
||||
port: 8787, // Port number, default is 3000
|
||||
})
|
||||
```
|
||||
|
||||
### `createServer`
|
||||
|
||||
```ts
|
||||
import { createServer } from 'node:https'
|
||||
import fs from 'node:fs'
|
||||
|
||||
//...
|
||||
|
||||
serve({
|
||||
fetch: app.fetch,
|
||||
createServer: createServer,
|
||||
serverOptions: {
|
||||
key: fs.readFileSync('test/fixtures/keys/agent1-key.pem'),
|
||||
cert: fs.readFileSync('test/fixtures/keys/agent1-cert.pem'),
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
### `overrideGlobalObjects`
|
||||
|
||||
The default value is `true`. The Node.js Adapter rewrites the global Request/Response and uses a lightweight Request/Response to improve performance. If you don't want to do that, set `false`.
|
||||
|
||||
```ts
|
||||
serve({
|
||||
fetch: app.fetch,
|
||||
overrideGlobalObjects: false,
|
||||
})
|
||||
```
|
||||
|
||||
### `autoCleanupIncoming`
|
||||
|
||||
The default value is `true`. The Node.js Adapter automatically cleans up (explicitly call `destroy()` method) if application is not finished to consume the incoming request. If you don't want to do that, set `false`.
|
||||
|
||||
If the application accepts connections from arbitrary clients, this cleanup must be done otherwise incomplete requests from clients may cause the application to stop responding. If your application only accepts connections from trusted clients, such as in a reverse proxy environment and there is no process that returns a response without reading the body of the POST request all the way through, you can improve performance by setting it to `false`.
|
||||
|
||||
```ts
|
||||
serve({
|
||||
fetch: app.fetch,
|
||||
autoCleanupIncoming: false,
|
||||
})
|
||||
```
|
||||
|
||||
## Middleware
|
||||
|
||||
Most built-in middleware also works with Node.js.
|
||||
Read [the documentation](https://hono.dev/middleware/builtin/basic-auth) and use the Middleware of your liking.
|
||||
|
||||
```ts
|
||||
import { serve } from '@hono/node-server'
|
||||
import { Hono } from 'hono'
|
||||
import { prettyJSON } from 'hono/pretty-json'
|
||||
|
||||
const app = new Hono()
|
||||
|
||||
app.get('*', prettyJSON())
|
||||
app.get('/', (c) => c.json({ 'Hono meets': 'Node.js' }))
|
||||
|
||||
serve(app)
|
||||
```
|
||||
|
||||
## Serve Static Middleware
|
||||
|
||||
Use Serve Static Middleware that has been created for Node.js.
|
||||
|
||||
```ts
|
||||
import { serveStatic } from '@hono/node-server/serve-static'
|
||||
|
||||
//...
|
||||
|
||||
app.use('/static/*', serveStatic({ root: './' }))
|
||||
```
|
||||
|
||||
If using a relative path, `root` will be relative to the current working directory from which the app was started.
|
||||
|
||||
This can cause confusion when running your application locally.
|
||||
|
||||
Imagine your project structure is:
|
||||
|
||||
```
|
||||
my-hono-project/
|
||||
src/
|
||||
index.ts
|
||||
static/
|
||||
index.html
|
||||
```
|
||||
|
||||
Typically, you would run your app from the project's root directory (`my-hono-project`),
|
||||
so you would need the following code to serve the `static` folder:
|
||||
|
||||
```ts
|
||||
app.use('/static/*', serveStatic({ root: './static' }))
|
||||
```
|
||||
|
||||
Notice that `root` here is not relative to `src/index.ts`, rather to `my-hono-project`.
|
||||
|
||||
### Options
|
||||
|
||||
#### `rewriteRequestPath`
|
||||
|
||||
If you want to serve files in `./.foojs` with the request path `/__foo/*`, you can write like the following.
|
||||
|
||||
```ts
|
||||
app.use(
|
||||
'/__foo/*',
|
||||
serveStatic({
|
||||
root: './.foojs/',
|
||||
rewriteRequestPath: (path: string) => path.replace(/^\/__foo/, ''),
|
||||
})
|
||||
)
|
||||
```
|
||||
|
||||
#### `onFound`
|
||||
|
||||
You can specify handling when the requested file is found with `onFound`.
|
||||
|
||||
```ts
|
||||
app.use(
|
||||
'/static/*',
|
||||
serveStatic({
|
||||
// ...
|
||||
onFound: (_path, c) => {
|
||||
c.header('Cache-Control', `public, immutable, max-age=31536000`)
|
||||
},
|
||||
})
|
||||
)
|
||||
```
|
||||
|
||||
#### `onNotFound`
|
||||
|
||||
The `onNotFound` is useful for debugging. You can write a handle for when a file is not found.
|
||||
|
||||
```ts
|
||||
app.use(
|
||||
'/static/*',
|
||||
serveStatic({
|
||||
root: './non-existent-dir',
|
||||
onNotFound: (path, c) => {
|
||||
console.log(`${path} is not found, request to ${c.req.path}`)
|
||||
},
|
||||
})
|
||||
)
|
||||
```
|
||||
|
||||
#### `precompressed`
|
||||
|
||||
The `precompressed` option checks if files with extensions like `.br` or `.gz` are available and serves them based on the `Accept-Encoding` header. It prioritizes Brotli, then Zstd, and Gzip. If none are available, it serves the original file.
|
||||
|
||||
```ts
|
||||
app.use(
|
||||
'/static/*',
|
||||
serveStatic({
|
||||
precompressed: true,
|
||||
})
|
||||
)
|
||||
```
|
||||
|
||||
## ConnInfo Helper
|
||||
|
||||
You can use the [ConnInfo Helper](https://hono.dev/docs/helpers/conninfo) by importing `getConnInfo` from `@hono/node-server/conninfo`.
|
||||
|
||||
```ts
|
||||
import { getConnInfo } from '@hono/node-server/conninfo'
|
||||
|
||||
app.get('/', (c) => {
|
||||
const info = getConnInfo(c) // info is `ConnInfo`
|
||||
return c.text(`Your remote address is ${info.remote.address}`)
|
||||
})
|
||||
```
|
||||
|
||||
## Accessing Node.js API
|
||||
|
||||
You can access the Node.js API from `c.env` in Node.js. For example, if you want to specify a type, you can write the following.
|
||||
|
||||
```ts
|
||||
import { serve } from '@hono/node-server'
|
||||
import type { HttpBindings } from '@hono/node-server'
|
||||
import { Hono } from 'hono'
|
||||
|
||||
const app = new Hono<{ Bindings: HttpBindings }>()
|
||||
|
||||
app.get('/', (c) => {
|
||||
return c.json({
|
||||
remoteAddress: c.env.incoming.socket.remoteAddress,
|
||||
})
|
||||
})
|
||||
|
||||
serve(app)
|
||||
```
|
||||
|
||||
The APIs that you can get from `c.env` are as follows.
|
||||
|
||||
```ts
|
||||
type HttpBindings = {
|
||||
incoming: IncomingMessage
|
||||
outgoing: ServerResponse
|
||||
}
|
||||
|
||||
type Http2Bindings = {
|
||||
incoming: Http2ServerRequest
|
||||
outgoing: Http2ServerResponse
|
||||
}
|
||||
```
|
||||
|
||||
## Direct response from Node.js API
|
||||
|
||||
You can directly respond to the client from the Node.js API.
|
||||
In that case, the response from Hono should be ignored, so return `RESPONSE_ALREADY_SENT`.
|
||||
|
||||
> [!NOTE]
|
||||
> This feature can be used when migrating existing Node.js applications to Hono, but we recommend using Hono's API for new applications.
|
||||
|
||||
```ts
|
||||
import { serve } from '@hono/node-server'
|
||||
import type { HttpBindings } from '@hono/node-server'
|
||||
import { RESPONSE_ALREADY_SENT } from '@hono/node-server/utils/response'
|
||||
import { Hono } from 'hono'
|
||||
|
||||
const app = new Hono<{ Bindings: HttpBindings }>()
|
||||
|
||||
app.get('/', (c) => {
|
||||
const { outgoing } = c.env
|
||||
outgoing.writeHead(200, { 'Content-Type': 'text/plain' })
|
||||
outgoing.end('Hello World\n')
|
||||
|
||||
return RESPONSE_ALREADY_SENT
|
||||
})
|
||||
|
||||
serve(app)
|
||||
```
|
||||
|
||||
## Listen to a UNIX domain socket
|
||||
|
||||
You can configure the HTTP server to listen to a UNIX domain socket instead of a TCP port.
|
||||
|
||||
```ts
|
||||
import { createAdaptorServer } from '@hono/node-server'
|
||||
|
||||
// ...
|
||||
|
||||
const socketPath = '/tmp/example.sock'
|
||||
|
||||
const server = createAdaptorServer(app)
|
||||
server.listen(socketPath, () => {
|
||||
console.log(`Listening on ${socketPath}`)
|
||||
})
|
||||
```
|
||||
|
||||
## Related projects
|
||||
|
||||
- Hono - <https://hono.dev>
|
||||
- Hono GitHub repository - <https://github.com/honojs/hono>
|
||||
|
||||
## Authors
|
||||
|
||||
- Yusuke Wada <https://github.com/yusukebe>
|
||||
- Taku Amano <https://github.com/usualoma>
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
10
projects/stt-mcp/node_modules/@hono/node-server/dist/conninfo.d.mts
generated
vendored
Normal file
10
projects/stt-mcp/node_modules/@hono/node-server/dist/conninfo.d.mts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import { GetConnInfo } from 'hono/conninfo';
|
||||
|
||||
/**
|
||||
* ConnInfo Helper for Node.js
|
||||
* @param c Context
|
||||
* @returns ConnInfo
|
||||
*/
|
||||
declare const getConnInfo: GetConnInfo;
|
||||
|
||||
export { getConnInfo };
|
||||
10
projects/stt-mcp/node_modules/@hono/node-server/dist/conninfo.d.ts
generated
vendored
Normal file
10
projects/stt-mcp/node_modules/@hono/node-server/dist/conninfo.d.ts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import { GetConnInfo } from 'hono/conninfo';
|
||||
|
||||
/**
|
||||
* ConnInfo Helper for Node.js
|
||||
* @param c Context
|
||||
* @returns ConnInfo
|
||||
*/
|
||||
declare const getConnInfo: GetConnInfo;
|
||||
|
||||
export { getConnInfo };
|
||||
42
projects/stt-mcp/node_modules/@hono/node-server/dist/conninfo.js
generated
vendored
Normal file
42
projects/stt-mcp/node_modules/@hono/node-server/dist/conninfo.js
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/conninfo.ts
|
||||
var conninfo_exports = {};
|
||||
__export(conninfo_exports, {
|
||||
getConnInfo: () => getConnInfo
|
||||
});
|
||||
module.exports = __toCommonJS(conninfo_exports);
|
||||
var getConnInfo = (c) => {
|
||||
const bindings = c.env.server ? c.env.server : c.env;
|
||||
const address = bindings.incoming.socket.remoteAddress;
|
||||
const port = bindings.incoming.socket.remotePort;
|
||||
const family = bindings.incoming.socket.remoteFamily;
|
||||
return {
|
||||
remote: {
|
||||
address,
|
||||
port,
|
||||
addressType: family === "IPv4" ? "IPv4" : family === "IPv6" ? "IPv6" : void 0
|
||||
}
|
||||
};
|
||||
};
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
getConnInfo
|
||||
});
|
||||
17
projects/stt-mcp/node_modules/@hono/node-server/dist/conninfo.mjs
generated
vendored
Normal file
17
projects/stt-mcp/node_modules/@hono/node-server/dist/conninfo.mjs
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
// src/conninfo.ts
|
||||
var getConnInfo = (c) => {
|
||||
const bindings = c.env.server ? c.env.server : c.env;
|
||||
const address = bindings.incoming.socket.remoteAddress;
|
||||
const port = bindings.incoming.socket.remotePort;
|
||||
const family = bindings.incoming.socket.remoteFamily;
|
||||
return {
|
||||
remote: {
|
||||
address,
|
||||
port,
|
||||
addressType: family === "IPv4" ? "IPv4" : family === "IPv6" ? "IPv6" : void 0
|
||||
}
|
||||
};
|
||||
};
|
||||
export {
|
||||
getConnInfo
|
||||
};
|
||||
2
projects/stt-mcp/node_modules/@hono/node-server/dist/globals.d.mts
generated
vendored
Normal file
2
projects/stt-mcp/node_modules/@hono/node-server/dist/globals.d.mts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
export { }
|
||||
2
projects/stt-mcp/node_modules/@hono/node-server/dist/globals.d.ts
generated
vendored
Normal file
2
projects/stt-mcp/node_modules/@hono/node-server/dist/globals.d.ts
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
export { }
|
||||
29
projects/stt-mcp/node_modules/@hono/node-server/dist/globals.js
generated
vendored
Normal file
29
projects/stt-mcp/node_modules/@hono/node-server/dist/globals.js
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
|
||||
// src/globals.ts
|
||||
var import_node_crypto = __toESM(require("crypto"));
|
||||
if (typeof global.crypto === "undefined") {
|
||||
global.crypto = import_node_crypto.default;
|
||||
}
|
||||
5
projects/stt-mcp/node_modules/@hono/node-server/dist/globals.mjs
generated
vendored
Normal file
5
projects/stt-mcp/node_modules/@hono/node-server/dist/globals.mjs
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
// src/globals.ts
|
||||
import crypto from "crypto";
|
||||
if (typeof global.crypto === "undefined") {
|
||||
global.crypto = crypto;
|
||||
}
|
||||
8
projects/stt-mcp/node_modules/@hono/node-server/dist/index.d.mts
generated
vendored
Normal file
8
projects/stt-mcp/node_modules/@hono/node-server/dist/index.d.mts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
export { createAdaptorServer, serve } from './server.mjs';
|
||||
export { getRequestListener } from './listener.mjs';
|
||||
export { RequestError } from './request.mjs';
|
||||
export { Http2Bindings, HttpBindings, ServerType } from './types.mjs';
|
||||
import 'node:net';
|
||||
import 'node:http';
|
||||
import 'node:http2';
|
||||
import 'node:https';
|
||||
8
projects/stt-mcp/node_modules/@hono/node-server/dist/index.d.ts
generated
vendored
Normal file
8
projects/stt-mcp/node_modules/@hono/node-server/dist/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
export { createAdaptorServer, serve } from './server.js';
|
||||
export { getRequestListener } from './listener.js';
|
||||
export { RequestError } from './request.js';
|
||||
export { Http2Bindings, HttpBindings, ServerType } from './types.js';
|
||||
import 'node:net';
|
||||
import 'node:http';
|
||||
import 'node:http2';
|
||||
import 'node:https';
|
||||
632
projects/stt-mcp/node_modules/@hono/node-server/dist/index.js
generated
vendored
Normal file
632
projects/stt-mcp/node_modules/@hono/node-server/dist/index.js
generated
vendored
Normal file
@@ -0,0 +1,632 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/index.ts
|
||||
var src_exports = {};
|
||||
__export(src_exports, {
|
||||
RequestError: () => RequestError,
|
||||
createAdaptorServer: () => createAdaptorServer,
|
||||
getRequestListener: () => getRequestListener,
|
||||
serve: () => serve
|
||||
});
|
||||
module.exports = __toCommonJS(src_exports);
|
||||
|
||||
// src/server.ts
|
||||
var import_node_http = require("http");
|
||||
|
||||
// src/listener.ts
|
||||
var import_node_http22 = require("http2");
|
||||
|
||||
// src/request.ts
|
||||
var import_node_http2 = require("http2");
|
||||
var import_node_stream = require("stream");
|
||||
var RequestError = class extends Error {
|
||||
constructor(message, options) {
|
||||
super(message, options);
|
||||
this.name = "RequestError";
|
||||
}
|
||||
};
|
||||
var toRequestError = (e) => {
|
||||
if (e instanceof RequestError) {
|
||||
return e;
|
||||
}
|
||||
return new RequestError(e.message, { cause: e });
|
||||
};
|
||||
var GlobalRequest = global.Request;
|
||||
var Request = class extends GlobalRequest {
|
||||
constructor(input, options) {
|
||||
if (typeof input === "object" && getRequestCache in input) {
|
||||
input = input[getRequestCache]();
|
||||
}
|
||||
if (typeof options?.body?.getReader !== "undefined") {
|
||||
;
|
||||
options.duplex ??= "half";
|
||||
}
|
||||
super(input, options);
|
||||
}
|
||||
};
|
||||
var newHeadersFromIncoming = (incoming) => {
|
||||
const headerRecord = [];
|
||||
const rawHeaders = incoming.rawHeaders;
|
||||
for (let i = 0; i < rawHeaders.length; i += 2) {
|
||||
const { [i]: key, [i + 1]: value } = rawHeaders;
|
||||
if (key.charCodeAt(0) !== /*:*/
|
||||
58) {
|
||||
headerRecord.push([key, value]);
|
||||
}
|
||||
}
|
||||
return new Headers(headerRecord);
|
||||
};
|
||||
var wrapBodyStream = Symbol("wrapBodyStream");
|
||||
var newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
|
||||
const init = {
|
||||
method,
|
||||
headers,
|
||||
signal: abortController.signal
|
||||
};
|
||||
if (method === "TRACE") {
|
||||
init.method = "GET";
|
||||
const req = new Request(url, init);
|
||||
Object.defineProperty(req, "method", {
|
||||
get() {
|
||||
return "TRACE";
|
||||
}
|
||||
});
|
||||
return req;
|
||||
}
|
||||
if (!(method === "GET" || method === "HEAD")) {
|
||||
if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) {
|
||||
init.body = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(incoming.rawBody);
|
||||
controller.close();
|
||||
}
|
||||
});
|
||||
} else if (incoming[wrapBodyStream]) {
|
||||
let reader;
|
||||
init.body = new ReadableStream({
|
||||
async pull(controller) {
|
||||
try {
|
||||
reader ||= import_node_stream.Readable.toWeb(incoming).getReader();
|
||||
const { done, value } = await reader.read();
|
||||
if (done) {
|
||||
controller.close();
|
||||
} else {
|
||||
controller.enqueue(value);
|
||||
}
|
||||
} catch (error) {
|
||||
controller.error(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
init.body = import_node_stream.Readable.toWeb(incoming);
|
||||
}
|
||||
}
|
||||
return new Request(url, init);
|
||||
};
|
||||
var getRequestCache = Symbol("getRequestCache");
|
||||
var requestCache = Symbol("requestCache");
|
||||
var incomingKey = Symbol("incomingKey");
|
||||
var urlKey = Symbol("urlKey");
|
||||
var headersKey = Symbol("headersKey");
|
||||
var abortControllerKey = Symbol("abortControllerKey");
|
||||
var getAbortController = Symbol("getAbortController");
|
||||
var requestPrototype = {
|
||||
get method() {
|
||||
return this[incomingKey].method || "GET";
|
||||
},
|
||||
get url() {
|
||||
return this[urlKey];
|
||||
},
|
||||
get headers() {
|
||||
return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
|
||||
},
|
||||
[getAbortController]() {
|
||||
this[getRequestCache]();
|
||||
return this[abortControllerKey];
|
||||
},
|
||||
[getRequestCache]() {
|
||||
this[abortControllerKey] ||= new AbortController();
|
||||
return this[requestCache] ||= newRequestFromIncoming(
|
||||
this.method,
|
||||
this[urlKey],
|
||||
this.headers,
|
||||
this[incomingKey],
|
||||
this[abortControllerKey]
|
||||
);
|
||||
}
|
||||
};
|
||||
[
|
||||
"body",
|
||||
"bodyUsed",
|
||||
"cache",
|
||||
"credentials",
|
||||
"destination",
|
||||
"integrity",
|
||||
"mode",
|
||||
"redirect",
|
||||
"referrer",
|
||||
"referrerPolicy",
|
||||
"signal",
|
||||
"keepalive"
|
||||
].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
get() {
|
||||
return this[getRequestCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
value: function() {
|
||||
return this[getRequestCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(requestPrototype, Request.prototype);
|
||||
var newRequest = (incoming, defaultHostname) => {
|
||||
const req = Object.create(requestPrototype);
|
||||
req[incomingKey] = incoming;
|
||||
const incomingUrl = incoming.url || "";
|
||||
if (incomingUrl[0] !== "/" && // short-circuit for performance. most requests are relative URL.
|
||||
(incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) {
|
||||
if (incoming instanceof import_node_http2.Http2ServerRequest) {
|
||||
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
||||
}
|
||||
try {
|
||||
const url2 = new URL(incomingUrl);
|
||||
req[urlKey] = url2.href;
|
||||
} catch (e) {
|
||||
throw new RequestError("Invalid absolute URL", { cause: e });
|
||||
}
|
||||
return req;
|
||||
}
|
||||
const host = (incoming instanceof import_node_http2.Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;
|
||||
if (!host) {
|
||||
throw new RequestError("Missing host header");
|
||||
}
|
||||
let scheme;
|
||||
if (incoming instanceof import_node_http2.Http2ServerRequest) {
|
||||
scheme = incoming.scheme;
|
||||
if (!(scheme === "http" || scheme === "https")) {
|
||||
throw new RequestError("Unsupported scheme");
|
||||
}
|
||||
} else {
|
||||
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
||||
}
|
||||
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
||||
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
||||
throw new RequestError("Invalid host header");
|
||||
}
|
||||
req[urlKey] = url.href;
|
||||
return req;
|
||||
};
|
||||
|
||||
// src/response.ts
|
||||
var responseCache = Symbol("responseCache");
|
||||
var getResponseCache = Symbol("getResponseCache");
|
||||
var cacheKey = Symbol("cache");
|
||||
var GlobalResponse = global.Response;
|
||||
var Response2 = class _Response {
|
||||
#body;
|
||||
#init;
|
||||
[getResponseCache]() {
|
||||
delete this[cacheKey];
|
||||
return this[responseCache] ||= new GlobalResponse(this.#body, this.#init);
|
||||
}
|
||||
constructor(body, init) {
|
||||
let headers;
|
||||
this.#body = body;
|
||||
if (init instanceof _Response) {
|
||||
const cachedGlobalResponse = init[responseCache];
|
||||
if (cachedGlobalResponse) {
|
||||
this.#init = cachedGlobalResponse;
|
||||
this[getResponseCache]();
|
||||
return;
|
||||
} else {
|
||||
this.#init = init.#init;
|
||||
headers = new Headers(init.#init.headers);
|
||||
}
|
||||
} else {
|
||||
this.#init = init;
|
||||
}
|
||||
if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) {
|
||||
;
|
||||
this[cacheKey] = [init?.status || 200, body, headers || init?.headers];
|
||||
}
|
||||
}
|
||||
get headers() {
|
||||
const cache = this[cacheKey];
|
||||
if (cache) {
|
||||
if (!(cache[2] instanceof Headers)) {
|
||||
cache[2] = new Headers(
|
||||
cache[2] || { "content-type": "text/plain; charset=UTF-8" }
|
||||
);
|
||||
}
|
||||
return cache[2];
|
||||
}
|
||||
return this[getResponseCache]().headers;
|
||||
}
|
||||
get status() {
|
||||
return this[cacheKey]?.[0] ?? this[getResponseCache]().status;
|
||||
}
|
||||
get ok() {
|
||||
const status = this.status;
|
||||
return status >= 200 && status < 300;
|
||||
}
|
||||
};
|
||||
["body", "bodyUsed", "redirected", "statusText", "trailers", "type", "url"].forEach((k) => {
|
||||
Object.defineProperty(Response2.prototype, k, {
|
||||
get() {
|
||||
return this[getResponseCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(Response2.prototype, k, {
|
||||
value: function() {
|
||||
return this[getResponseCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(Response2, GlobalResponse);
|
||||
Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);
|
||||
|
||||
// src/utils.ts
|
||||
async function readWithoutBlocking(readPromise) {
|
||||
return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
|
||||
}
|
||||
function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
|
||||
const cancel = (error) => {
|
||||
reader.cancel(error).catch(() => {
|
||||
});
|
||||
};
|
||||
writable.on("close", cancel);
|
||||
writable.on("error", cancel);
|
||||
(currentReadPromise ?? reader.read()).then(flow, handleStreamError);
|
||||
return reader.closed.finally(() => {
|
||||
writable.off("close", cancel);
|
||||
writable.off("error", cancel);
|
||||
});
|
||||
function handleStreamError(error) {
|
||||
if (error) {
|
||||
writable.destroy(error);
|
||||
}
|
||||
}
|
||||
function onDrain() {
|
||||
reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
function flow({ done, value }) {
|
||||
try {
|
||||
if (done) {
|
||||
writable.end();
|
||||
} else if (!writable.write(value)) {
|
||||
writable.once("drain", onDrain);
|
||||
} else {
|
||||
return reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
} catch (e) {
|
||||
handleStreamError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
function writeFromReadableStream(stream, writable) {
|
||||
if (stream.locked) {
|
||||
throw new TypeError("ReadableStream is locked.");
|
||||
} else if (writable.destroyed) {
|
||||
return;
|
||||
}
|
||||
return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
|
||||
}
|
||||
var buildOutgoingHttpHeaders = (headers) => {
|
||||
const res = {};
|
||||
if (!(headers instanceof Headers)) {
|
||||
headers = new Headers(headers ?? void 0);
|
||||
}
|
||||
const cookies = [];
|
||||
for (const [k, v] of headers) {
|
||||
if (k === "set-cookie") {
|
||||
cookies.push(v);
|
||||
} else {
|
||||
res[k] = v;
|
||||
}
|
||||
}
|
||||
if (cookies.length > 0) {
|
||||
res["set-cookie"] = cookies;
|
||||
}
|
||||
res["content-type"] ??= "text/plain; charset=UTF-8";
|
||||
return res;
|
||||
};
|
||||
|
||||
// src/utils/response/constants.ts
|
||||
var X_ALREADY_SENT = "x-hono-already-sent";
|
||||
|
||||
// src/globals.ts
|
||||
var import_node_crypto = __toESM(require("crypto"));
|
||||
if (typeof global.crypto === "undefined") {
|
||||
global.crypto = import_node_crypto.default;
|
||||
}
|
||||
|
||||
// src/listener.ts
|
||||
var outgoingEnded = Symbol("outgoingEnded");
|
||||
var handleRequestError = () => new Response(null, {
|
||||
status: 400
|
||||
});
|
||||
var handleFetchError = (e) => new Response(null, {
|
||||
status: e instanceof Error && (e.name === "TimeoutError" || e.constructor.name === "TimeoutError") ? 504 : 500
|
||||
});
|
||||
var handleResponseError = (e, outgoing) => {
|
||||
const err = e instanceof Error ? e : new Error("unknown error", { cause: e });
|
||||
if (err.code === "ERR_STREAM_PREMATURE_CLOSE") {
|
||||
console.info("The user aborted a request.");
|
||||
} else {
|
||||
console.error(e);
|
||||
if (!outgoing.headersSent) {
|
||||
outgoing.writeHead(500, { "Content-Type": "text/plain" });
|
||||
}
|
||||
outgoing.end(`Error: ${err.message}`);
|
||||
outgoing.destroy(err);
|
||||
}
|
||||
};
|
||||
var flushHeaders = (outgoing) => {
|
||||
if ("flushHeaders" in outgoing && outgoing.writable) {
|
||||
outgoing.flushHeaders();
|
||||
}
|
||||
};
|
||||
var responseViaCache = async (res, outgoing) => {
|
||||
let [status, body, header] = res[cacheKey];
|
||||
let hasContentLength = false;
|
||||
if (!header) {
|
||||
header = { "content-type": "text/plain; charset=UTF-8" };
|
||||
} else if (header instanceof Headers) {
|
||||
hasContentLength = header.has("content-length");
|
||||
header = buildOutgoingHttpHeaders(header);
|
||||
} else if (Array.isArray(header)) {
|
||||
const headerObj = new Headers(header);
|
||||
hasContentLength = headerObj.has("content-length");
|
||||
header = buildOutgoingHttpHeaders(headerObj);
|
||||
} else {
|
||||
for (const key in header) {
|
||||
if (key.length === 14 && key.toLowerCase() === "content-length") {
|
||||
hasContentLength = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasContentLength) {
|
||||
if (typeof body === "string") {
|
||||
header["Content-Length"] = Buffer.byteLength(body);
|
||||
} else if (body instanceof Uint8Array) {
|
||||
header["Content-Length"] = body.byteLength;
|
||||
} else if (body instanceof Blob) {
|
||||
header["Content-Length"] = body.size;
|
||||
}
|
||||
}
|
||||
outgoing.writeHead(status, header);
|
||||
if (typeof body === "string" || body instanceof Uint8Array) {
|
||||
outgoing.end(body);
|
||||
} else if (body instanceof Blob) {
|
||||
outgoing.end(new Uint8Array(await body.arrayBuffer()));
|
||||
} else {
|
||||
flushHeaders(outgoing);
|
||||
await writeFromReadableStream(body, outgoing)?.catch(
|
||||
(e) => handleResponseError(e, outgoing)
|
||||
);
|
||||
}
|
||||
;
|
||||
outgoing[outgoingEnded]?.();
|
||||
};
|
||||
var isPromise = (res) => typeof res.then === "function";
|
||||
var responseViaResponseObject = async (res, outgoing, options = {}) => {
|
||||
if (isPromise(res)) {
|
||||
if (options.errorHandler) {
|
||||
try {
|
||||
res = await res;
|
||||
} catch (err) {
|
||||
const errRes = await options.errorHandler(err);
|
||||
if (!errRes) {
|
||||
return;
|
||||
}
|
||||
res = errRes;
|
||||
}
|
||||
} else {
|
||||
res = await res.catch(handleFetchError);
|
||||
}
|
||||
}
|
||||
if (cacheKey in res) {
|
||||
return responseViaCache(res, outgoing);
|
||||
}
|
||||
const resHeaderRecord = buildOutgoingHttpHeaders(res.headers);
|
||||
if (res.body) {
|
||||
const reader = res.body.getReader();
|
||||
const values = [];
|
||||
let done = false;
|
||||
let currentReadPromise = void 0;
|
||||
if (resHeaderRecord["transfer-encoding"] !== "chunked") {
|
||||
let maxReadCount = 2;
|
||||
for (let i = 0; i < maxReadCount; i++) {
|
||||
currentReadPromise ||= reader.read();
|
||||
const chunk = await readWithoutBlocking(currentReadPromise).catch((e) => {
|
||||
console.error(e);
|
||||
done = true;
|
||||
});
|
||||
if (!chunk) {
|
||||
if (i === 1) {
|
||||
await new Promise((resolve) => setTimeout(resolve));
|
||||
maxReadCount = 3;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
currentReadPromise = void 0;
|
||||
if (chunk.value) {
|
||||
values.push(chunk.value);
|
||||
}
|
||||
if (chunk.done) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (done && !("content-length" in resHeaderRecord)) {
|
||||
resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0);
|
||||
}
|
||||
}
|
||||
outgoing.writeHead(res.status, resHeaderRecord);
|
||||
values.forEach((value) => {
|
||||
;
|
||||
outgoing.write(value);
|
||||
});
|
||||
if (done) {
|
||||
outgoing.end();
|
||||
} else {
|
||||
if (values.length === 0) {
|
||||
flushHeaders(outgoing);
|
||||
}
|
||||
await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);
|
||||
}
|
||||
} else if (resHeaderRecord[X_ALREADY_SENT]) {
|
||||
} else {
|
||||
outgoing.writeHead(res.status, resHeaderRecord);
|
||||
outgoing.end();
|
||||
}
|
||||
;
|
||||
outgoing[outgoingEnded]?.();
|
||||
};
|
||||
var getRequestListener = (fetchCallback, options = {}) => {
|
||||
const autoCleanupIncoming = options.autoCleanupIncoming ?? true;
|
||||
if (options.overrideGlobalObjects !== false && global.Request !== Request) {
|
||||
Object.defineProperty(global, "Request", {
|
||||
value: Request
|
||||
});
|
||||
Object.defineProperty(global, "Response", {
|
||||
value: Response2
|
||||
});
|
||||
}
|
||||
return async (incoming, outgoing) => {
|
||||
let res, req;
|
||||
try {
|
||||
req = newRequest(incoming, options.hostname);
|
||||
let incomingEnded = !autoCleanupIncoming || incoming.method === "GET" || incoming.method === "HEAD";
|
||||
if (!incomingEnded) {
|
||||
;
|
||||
incoming[wrapBodyStream] = true;
|
||||
incoming.on("end", () => {
|
||||
incomingEnded = true;
|
||||
});
|
||||
if (incoming instanceof import_node_http22.Http2ServerRequest) {
|
||||
;
|
||||
outgoing[outgoingEnded] = () => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
incoming.destroy();
|
||||
outgoing.destroy();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
outgoing.on("close", () => {
|
||||
const abortController = req[abortControllerKey];
|
||||
if (abortController) {
|
||||
if (incoming.errored) {
|
||||
req[abortControllerKey].abort(incoming.errored.toString());
|
||||
} else if (!outgoing.writableFinished) {
|
||||
req[abortControllerKey].abort("Client connection prematurely closed.");
|
||||
}
|
||||
}
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
incoming.destroy();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
res = fetchCallback(req, { incoming, outgoing });
|
||||
if (cacheKey in res) {
|
||||
return responseViaCache(res, outgoing);
|
||||
}
|
||||
} catch (e) {
|
||||
if (!res) {
|
||||
if (options.errorHandler) {
|
||||
res = await options.errorHandler(req ? e : toRequestError(e));
|
||||
if (!res) {
|
||||
return;
|
||||
}
|
||||
} else if (!req) {
|
||||
res = handleRequestError();
|
||||
} else {
|
||||
res = handleFetchError(e);
|
||||
}
|
||||
} else {
|
||||
return handleResponseError(e, outgoing);
|
||||
}
|
||||
}
|
||||
try {
|
||||
return await responseViaResponseObject(res, outgoing, options);
|
||||
} catch (e) {
|
||||
return handleResponseError(e, outgoing);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// src/server.ts
|
||||
var createAdaptorServer = (options) => {
|
||||
const fetchCallback = options.fetch;
|
||||
const requestListener = getRequestListener(fetchCallback, {
|
||||
hostname: options.hostname,
|
||||
overrideGlobalObjects: options.overrideGlobalObjects,
|
||||
autoCleanupIncoming: options.autoCleanupIncoming
|
||||
});
|
||||
const createServer = options.createServer || import_node_http.createServer;
|
||||
const server = createServer(options.serverOptions || {}, requestListener);
|
||||
return server;
|
||||
};
|
||||
var serve = (options, listeningListener) => {
|
||||
const server = createAdaptorServer(options);
|
||||
server.listen(options?.port ?? 3e3, options.hostname, () => {
|
||||
const serverInfo = server.address();
|
||||
listeningListener && listeningListener(serverInfo);
|
||||
});
|
||||
return server;
|
||||
};
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
RequestError,
|
||||
createAdaptorServer,
|
||||
getRequestListener,
|
||||
serve
|
||||
});
|
||||
592
projects/stt-mcp/node_modules/@hono/node-server/dist/index.mjs
generated
vendored
Normal file
592
projects/stt-mcp/node_modules/@hono/node-server/dist/index.mjs
generated
vendored
Normal file
@@ -0,0 +1,592 @@
|
||||
// src/server.ts
|
||||
import { createServer as createServerHTTP } from "http";
|
||||
|
||||
// src/listener.ts
|
||||
import { Http2ServerRequest as Http2ServerRequest2 } from "http2";
|
||||
|
||||
// src/request.ts
|
||||
import { Http2ServerRequest } from "http2";
|
||||
import { Readable } from "stream";
|
||||
var RequestError = class extends Error {
|
||||
constructor(message, options) {
|
||||
super(message, options);
|
||||
this.name = "RequestError";
|
||||
}
|
||||
};
|
||||
var toRequestError = (e) => {
|
||||
if (e instanceof RequestError) {
|
||||
return e;
|
||||
}
|
||||
return new RequestError(e.message, { cause: e });
|
||||
};
|
||||
var GlobalRequest = global.Request;
|
||||
var Request = class extends GlobalRequest {
|
||||
constructor(input, options) {
|
||||
if (typeof input === "object" && getRequestCache in input) {
|
||||
input = input[getRequestCache]();
|
||||
}
|
||||
if (typeof options?.body?.getReader !== "undefined") {
|
||||
;
|
||||
options.duplex ??= "half";
|
||||
}
|
||||
super(input, options);
|
||||
}
|
||||
};
|
||||
var newHeadersFromIncoming = (incoming) => {
|
||||
const headerRecord = [];
|
||||
const rawHeaders = incoming.rawHeaders;
|
||||
for (let i = 0; i < rawHeaders.length; i += 2) {
|
||||
const { [i]: key, [i + 1]: value } = rawHeaders;
|
||||
if (key.charCodeAt(0) !== /*:*/
|
||||
58) {
|
||||
headerRecord.push([key, value]);
|
||||
}
|
||||
}
|
||||
return new Headers(headerRecord);
|
||||
};
|
||||
var wrapBodyStream = Symbol("wrapBodyStream");
|
||||
var newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
|
||||
const init = {
|
||||
method,
|
||||
headers,
|
||||
signal: abortController.signal
|
||||
};
|
||||
if (method === "TRACE") {
|
||||
init.method = "GET";
|
||||
const req = new Request(url, init);
|
||||
Object.defineProperty(req, "method", {
|
||||
get() {
|
||||
return "TRACE";
|
||||
}
|
||||
});
|
||||
return req;
|
||||
}
|
||||
if (!(method === "GET" || method === "HEAD")) {
|
||||
if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) {
|
||||
init.body = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(incoming.rawBody);
|
||||
controller.close();
|
||||
}
|
||||
});
|
||||
} else if (incoming[wrapBodyStream]) {
|
||||
let reader;
|
||||
init.body = new ReadableStream({
|
||||
async pull(controller) {
|
||||
try {
|
||||
reader ||= Readable.toWeb(incoming).getReader();
|
||||
const { done, value } = await reader.read();
|
||||
if (done) {
|
||||
controller.close();
|
||||
} else {
|
||||
controller.enqueue(value);
|
||||
}
|
||||
} catch (error) {
|
||||
controller.error(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
init.body = Readable.toWeb(incoming);
|
||||
}
|
||||
}
|
||||
return new Request(url, init);
|
||||
};
|
||||
var getRequestCache = Symbol("getRequestCache");
|
||||
var requestCache = Symbol("requestCache");
|
||||
var incomingKey = Symbol("incomingKey");
|
||||
var urlKey = Symbol("urlKey");
|
||||
var headersKey = Symbol("headersKey");
|
||||
var abortControllerKey = Symbol("abortControllerKey");
|
||||
var getAbortController = Symbol("getAbortController");
|
||||
var requestPrototype = {
|
||||
get method() {
|
||||
return this[incomingKey].method || "GET";
|
||||
},
|
||||
get url() {
|
||||
return this[urlKey];
|
||||
},
|
||||
get headers() {
|
||||
return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
|
||||
},
|
||||
[getAbortController]() {
|
||||
this[getRequestCache]();
|
||||
return this[abortControllerKey];
|
||||
},
|
||||
[getRequestCache]() {
|
||||
this[abortControllerKey] ||= new AbortController();
|
||||
return this[requestCache] ||= newRequestFromIncoming(
|
||||
this.method,
|
||||
this[urlKey],
|
||||
this.headers,
|
||||
this[incomingKey],
|
||||
this[abortControllerKey]
|
||||
);
|
||||
}
|
||||
};
|
||||
[
|
||||
"body",
|
||||
"bodyUsed",
|
||||
"cache",
|
||||
"credentials",
|
||||
"destination",
|
||||
"integrity",
|
||||
"mode",
|
||||
"redirect",
|
||||
"referrer",
|
||||
"referrerPolicy",
|
||||
"signal",
|
||||
"keepalive"
|
||||
].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
get() {
|
||||
return this[getRequestCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
value: function() {
|
||||
return this[getRequestCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(requestPrototype, Request.prototype);
|
||||
var newRequest = (incoming, defaultHostname) => {
|
||||
const req = Object.create(requestPrototype);
|
||||
req[incomingKey] = incoming;
|
||||
const incomingUrl = incoming.url || "";
|
||||
if (incomingUrl[0] !== "/" && // short-circuit for performance. most requests are relative URL.
|
||||
(incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) {
|
||||
if (incoming instanceof Http2ServerRequest) {
|
||||
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
||||
}
|
||||
try {
|
||||
const url2 = new URL(incomingUrl);
|
||||
req[urlKey] = url2.href;
|
||||
} catch (e) {
|
||||
throw new RequestError("Invalid absolute URL", { cause: e });
|
||||
}
|
||||
return req;
|
||||
}
|
||||
const host = (incoming instanceof Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;
|
||||
if (!host) {
|
||||
throw new RequestError("Missing host header");
|
||||
}
|
||||
let scheme;
|
||||
if (incoming instanceof Http2ServerRequest) {
|
||||
scheme = incoming.scheme;
|
||||
if (!(scheme === "http" || scheme === "https")) {
|
||||
throw new RequestError("Unsupported scheme");
|
||||
}
|
||||
} else {
|
||||
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
||||
}
|
||||
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
||||
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
||||
throw new RequestError("Invalid host header");
|
||||
}
|
||||
req[urlKey] = url.href;
|
||||
return req;
|
||||
};
|
||||
|
||||
// src/response.ts
|
||||
var responseCache = Symbol("responseCache");
|
||||
var getResponseCache = Symbol("getResponseCache");
|
||||
var cacheKey = Symbol("cache");
|
||||
var GlobalResponse = global.Response;
|
||||
var Response2 = class _Response {
|
||||
#body;
|
||||
#init;
|
||||
[getResponseCache]() {
|
||||
delete this[cacheKey];
|
||||
return this[responseCache] ||= new GlobalResponse(this.#body, this.#init);
|
||||
}
|
||||
constructor(body, init) {
|
||||
let headers;
|
||||
this.#body = body;
|
||||
if (init instanceof _Response) {
|
||||
const cachedGlobalResponse = init[responseCache];
|
||||
if (cachedGlobalResponse) {
|
||||
this.#init = cachedGlobalResponse;
|
||||
this[getResponseCache]();
|
||||
return;
|
||||
} else {
|
||||
this.#init = init.#init;
|
||||
headers = new Headers(init.#init.headers);
|
||||
}
|
||||
} else {
|
||||
this.#init = init;
|
||||
}
|
||||
if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) {
|
||||
;
|
||||
this[cacheKey] = [init?.status || 200, body, headers || init?.headers];
|
||||
}
|
||||
}
|
||||
get headers() {
|
||||
const cache = this[cacheKey];
|
||||
if (cache) {
|
||||
if (!(cache[2] instanceof Headers)) {
|
||||
cache[2] = new Headers(
|
||||
cache[2] || { "content-type": "text/plain; charset=UTF-8" }
|
||||
);
|
||||
}
|
||||
return cache[2];
|
||||
}
|
||||
return this[getResponseCache]().headers;
|
||||
}
|
||||
get status() {
|
||||
return this[cacheKey]?.[0] ?? this[getResponseCache]().status;
|
||||
}
|
||||
get ok() {
|
||||
const status = this.status;
|
||||
return status >= 200 && status < 300;
|
||||
}
|
||||
};
|
||||
["body", "bodyUsed", "redirected", "statusText", "trailers", "type", "url"].forEach((k) => {
|
||||
Object.defineProperty(Response2.prototype, k, {
|
||||
get() {
|
||||
return this[getResponseCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(Response2.prototype, k, {
|
||||
value: function() {
|
||||
return this[getResponseCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(Response2, GlobalResponse);
|
||||
Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);
|
||||
|
||||
// src/utils.ts
|
||||
async function readWithoutBlocking(readPromise) {
|
||||
return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
|
||||
}
|
||||
function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
|
||||
const cancel = (error) => {
|
||||
reader.cancel(error).catch(() => {
|
||||
});
|
||||
};
|
||||
writable.on("close", cancel);
|
||||
writable.on("error", cancel);
|
||||
(currentReadPromise ?? reader.read()).then(flow, handleStreamError);
|
||||
return reader.closed.finally(() => {
|
||||
writable.off("close", cancel);
|
||||
writable.off("error", cancel);
|
||||
});
|
||||
function handleStreamError(error) {
|
||||
if (error) {
|
||||
writable.destroy(error);
|
||||
}
|
||||
}
|
||||
function onDrain() {
|
||||
reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
function flow({ done, value }) {
|
||||
try {
|
||||
if (done) {
|
||||
writable.end();
|
||||
} else if (!writable.write(value)) {
|
||||
writable.once("drain", onDrain);
|
||||
} else {
|
||||
return reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
} catch (e) {
|
||||
handleStreamError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
function writeFromReadableStream(stream, writable) {
|
||||
if (stream.locked) {
|
||||
throw new TypeError("ReadableStream is locked.");
|
||||
} else if (writable.destroyed) {
|
||||
return;
|
||||
}
|
||||
return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
|
||||
}
|
||||
var buildOutgoingHttpHeaders = (headers) => {
|
||||
const res = {};
|
||||
if (!(headers instanceof Headers)) {
|
||||
headers = new Headers(headers ?? void 0);
|
||||
}
|
||||
const cookies = [];
|
||||
for (const [k, v] of headers) {
|
||||
if (k === "set-cookie") {
|
||||
cookies.push(v);
|
||||
} else {
|
||||
res[k] = v;
|
||||
}
|
||||
}
|
||||
if (cookies.length > 0) {
|
||||
res["set-cookie"] = cookies;
|
||||
}
|
||||
res["content-type"] ??= "text/plain; charset=UTF-8";
|
||||
return res;
|
||||
};
|
||||
|
||||
// src/utils/response/constants.ts
|
||||
var X_ALREADY_SENT = "x-hono-already-sent";
|
||||
|
||||
// src/globals.ts
|
||||
import crypto from "crypto";
|
||||
if (typeof global.crypto === "undefined") {
|
||||
global.crypto = crypto;
|
||||
}
|
||||
|
||||
// src/listener.ts
|
||||
var outgoingEnded = Symbol("outgoingEnded");
|
||||
var handleRequestError = () => new Response(null, {
|
||||
status: 400
|
||||
});
|
||||
var handleFetchError = (e) => new Response(null, {
|
||||
status: e instanceof Error && (e.name === "TimeoutError" || e.constructor.name === "TimeoutError") ? 504 : 500
|
||||
});
|
||||
var handleResponseError = (e, outgoing) => {
|
||||
const err = e instanceof Error ? e : new Error("unknown error", { cause: e });
|
||||
if (err.code === "ERR_STREAM_PREMATURE_CLOSE") {
|
||||
console.info("The user aborted a request.");
|
||||
} else {
|
||||
console.error(e);
|
||||
if (!outgoing.headersSent) {
|
||||
outgoing.writeHead(500, { "Content-Type": "text/plain" });
|
||||
}
|
||||
outgoing.end(`Error: ${err.message}`);
|
||||
outgoing.destroy(err);
|
||||
}
|
||||
};
|
||||
var flushHeaders = (outgoing) => {
|
||||
if ("flushHeaders" in outgoing && outgoing.writable) {
|
||||
outgoing.flushHeaders();
|
||||
}
|
||||
};
|
||||
var responseViaCache = async (res, outgoing) => {
|
||||
let [status, body, header] = res[cacheKey];
|
||||
let hasContentLength = false;
|
||||
if (!header) {
|
||||
header = { "content-type": "text/plain; charset=UTF-8" };
|
||||
} else if (header instanceof Headers) {
|
||||
hasContentLength = header.has("content-length");
|
||||
header = buildOutgoingHttpHeaders(header);
|
||||
} else if (Array.isArray(header)) {
|
||||
const headerObj = new Headers(header);
|
||||
hasContentLength = headerObj.has("content-length");
|
||||
header = buildOutgoingHttpHeaders(headerObj);
|
||||
} else {
|
||||
for (const key in header) {
|
||||
if (key.length === 14 && key.toLowerCase() === "content-length") {
|
||||
hasContentLength = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasContentLength) {
|
||||
if (typeof body === "string") {
|
||||
header["Content-Length"] = Buffer.byteLength(body);
|
||||
} else if (body instanceof Uint8Array) {
|
||||
header["Content-Length"] = body.byteLength;
|
||||
} else if (body instanceof Blob) {
|
||||
header["Content-Length"] = body.size;
|
||||
}
|
||||
}
|
||||
outgoing.writeHead(status, header);
|
||||
if (typeof body === "string" || body instanceof Uint8Array) {
|
||||
outgoing.end(body);
|
||||
} else if (body instanceof Blob) {
|
||||
outgoing.end(new Uint8Array(await body.arrayBuffer()));
|
||||
} else {
|
||||
flushHeaders(outgoing);
|
||||
await writeFromReadableStream(body, outgoing)?.catch(
|
||||
(e) => handleResponseError(e, outgoing)
|
||||
);
|
||||
}
|
||||
;
|
||||
outgoing[outgoingEnded]?.();
|
||||
};
|
||||
var isPromise = (res) => typeof res.then === "function";
|
||||
var responseViaResponseObject = async (res, outgoing, options = {}) => {
|
||||
if (isPromise(res)) {
|
||||
if (options.errorHandler) {
|
||||
try {
|
||||
res = await res;
|
||||
} catch (err) {
|
||||
const errRes = await options.errorHandler(err);
|
||||
if (!errRes) {
|
||||
return;
|
||||
}
|
||||
res = errRes;
|
||||
}
|
||||
} else {
|
||||
res = await res.catch(handleFetchError);
|
||||
}
|
||||
}
|
||||
if (cacheKey in res) {
|
||||
return responseViaCache(res, outgoing);
|
||||
}
|
||||
const resHeaderRecord = buildOutgoingHttpHeaders(res.headers);
|
||||
if (res.body) {
|
||||
const reader = res.body.getReader();
|
||||
const values = [];
|
||||
let done = false;
|
||||
let currentReadPromise = void 0;
|
||||
if (resHeaderRecord["transfer-encoding"] !== "chunked") {
|
||||
let maxReadCount = 2;
|
||||
for (let i = 0; i < maxReadCount; i++) {
|
||||
currentReadPromise ||= reader.read();
|
||||
const chunk = await readWithoutBlocking(currentReadPromise).catch((e) => {
|
||||
console.error(e);
|
||||
done = true;
|
||||
});
|
||||
if (!chunk) {
|
||||
if (i === 1) {
|
||||
await new Promise((resolve) => setTimeout(resolve));
|
||||
maxReadCount = 3;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
currentReadPromise = void 0;
|
||||
if (chunk.value) {
|
||||
values.push(chunk.value);
|
||||
}
|
||||
if (chunk.done) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (done && !("content-length" in resHeaderRecord)) {
|
||||
resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0);
|
||||
}
|
||||
}
|
||||
outgoing.writeHead(res.status, resHeaderRecord);
|
||||
values.forEach((value) => {
|
||||
;
|
||||
outgoing.write(value);
|
||||
});
|
||||
if (done) {
|
||||
outgoing.end();
|
||||
} else {
|
||||
if (values.length === 0) {
|
||||
flushHeaders(outgoing);
|
||||
}
|
||||
await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);
|
||||
}
|
||||
} else if (resHeaderRecord[X_ALREADY_SENT]) {
|
||||
} else {
|
||||
outgoing.writeHead(res.status, resHeaderRecord);
|
||||
outgoing.end();
|
||||
}
|
||||
;
|
||||
outgoing[outgoingEnded]?.();
|
||||
};
|
||||
var getRequestListener = (fetchCallback, options = {}) => {
|
||||
const autoCleanupIncoming = options.autoCleanupIncoming ?? true;
|
||||
if (options.overrideGlobalObjects !== false && global.Request !== Request) {
|
||||
Object.defineProperty(global, "Request", {
|
||||
value: Request
|
||||
});
|
||||
Object.defineProperty(global, "Response", {
|
||||
value: Response2
|
||||
});
|
||||
}
|
||||
return async (incoming, outgoing) => {
|
||||
let res, req;
|
||||
try {
|
||||
req = newRequest(incoming, options.hostname);
|
||||
let incomingEnded = !autoCleanupIncoming || incoming.method === "GET" || incoming.method === "HEAD";
|
||||
if (!incomingEnded) {
|
||||
;
|
||||
incoming[wrapBodyStream] = true;
|
||||
incoming.on("end", () => {
|
||||
incomingEnded = true;
|
||||
});
|
||||
if (incoming instanceof Http2ServerRequest2) {
|
||||
;
|
||||
outgoing[outgoingEnded] = () => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
incoming.destroy();
|
||||
outgoing.destroy();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
outgoing.on("close", () => {
|
||||
const abortController = req[abortControllerKey];
|
||||
if (abortController) {
|
||||
if (incoming.errored) {
|
||||
req[abortControllerKey].abort(incoming.errored.toString());
|
||||
} else if (!outgoing.writableFinished) {
|
||||
req[abortControllerKey].abort("Client connection prematurely closed.");
|
||||
}
|
||||
}
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
incoming.destroy();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
res = fetchCallback(req, { incoming, outgoing });
|
||||
if (cacheKey in res) {
|
||||
return responseViaCache(res, outgoing);
|
||||
}
|
||||
} catch (e) {
|
||||
if (!res) {
|
||||
if (options.errorHandler) {
|
||||
res = await options.errorHandler(req ? e : toRequestError(e));
|
||||
if (!res) {
|
||||
return;
|
||||
}
|
||||
} else if (!req) {
|
||||
res = handleRequestError();
|
||||
} else {
|
||||
res = handleFetchError(e);
|
||||
}
|
||||
} else {
|
||||
return handleResponseError(e, outgoing);
|
||||
}
|
||||
}
|
||||
try {
|
||||
return await responseViaResponseObject(res, outgoing, options);
|
||||
} catch (e) {
|
||||
return handleResponseError(e, outgoing);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// src/server.ts
|
||||
var createAdaptorServer = (options) => {
|
||||
const fetchCallback = options.fetch;
|
||||
const requestListener = getRequestListener(fetchCallback, {
|
||||
hostname: options.hostname,
|
||||
overrideGlobalObjects: options.overrideGlobalObjects,
|
||||
autoCleanupIncoming: options.autoCleanupIncoming
|
||||
});
|
||||
const createServer = options.createServer || createServerHTTP;
|
||||
const server = createServer(options.serverOptions || {}, requestListener);
|
||||
return server;
|
||||
};
|
||||
var serve = (options, listeningListener) => {
|
||||
const server = createAdaptorServer(options);
|
||||
server.listen(options?.port ?? 3e3, options.hostname, () => {
|
||||
const serverInfo = server.address();
|
||||
listeningListener && listeningListener(serverInfo);
|
||||
});
|
||||
return server;
|
||||
};
|
||||
export {
|
||||
RequestError,
|
||||
createAdaptorServer,
|
||||
getRequestListener,
|
||||
serve
|
||||
};
|
||||
13
projects/stt-mcp/node_modules/@hono/node-server/dist/listener.d.mts
generated
vendored
Normal file
13
projects/stt-mcp/node_modules/@hono/node-server/dist/listener.d.mts
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import { IncomingMessage, ServerResponse } from 'node:http';
|
||||
import { Http2ServerRequest, Http2ServerResponse } from 'node:http2';
|
||||
import { FetchCallback, CustomErrorHandler } from './types.mjs';
|
||||
import 'node:https';
|
||||
|
||||
declare const getRequestListener: (fetchCallback: FetchCallback, options?: {
|
||||
hostname?: string;
|
||||
errorHandler?: CustomErrorHandler;
|
||||
overrideGlobalObjects?: boolean;
|
||||
autoCleanupIncoming?: boolean;
|
||||
}) => (incoming: IncomingMessage | Http2ServerRequest, outgoing: ServerResponse | Http2ServerResponse) => Promise<void>;
|
||||
|
||||
export { getRequestListener };
|
||||
13
projects/stt-mcp/node_modules/@hono/node-server/dist/listener.d.ts
generated
vendored
Normal file
13
projects/stt-mcp/node_modules/@hono/node-server/dist/listener.d.ts
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import { IncomingMessage, ServerResponse } from 'node:http';
|
||||
import { Http2ServerRequest, Http2ServerResponse } from 'node:http2';
|
||||
import { FetchCallback, CustomErrorHandler } from './types.js';
|
||||
import 'node:https';
|
||||
|
||||
declare const getRequestListener: (fetchCallback: FetchCallback, options?: {
|
||||
hostname?: string;
|
||||
errorHandler?: CustomErrorHandler;
|
||||
overrideGlobalObjects?: boolean;
|
||||
autoCleanupIncoming?: boolean;
|
||||
}) => (incoming: IncomingMessage | Http2ServerRequest, outgoing: ServerResponse | Http2ServerResponse) => Promise<void>;
|
||||
|
||||
export { getRequestListener };
|
||||
600
projects/stt-mcp/node_modules/@hono/node-server/dist/listener.js
generated
vendored
Normal file
600
projects/stt-mcp/node_modules/@hono/node-server/dist/listener.js
generated
vendored
Normal file
@@ -0,0 +1,600 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/listener.ts
|
||||
var listener_exports = {};
|
||||
__export(listener_exports, {
|
||||
getRequestListener: () => getRequestListener
|
||||
});
|
||||
module.exports = __toCommonJS(listener_exports);
|
||||
var import_node_http22 = require("http2");
|
||||
|
||||
// src/request.ts
|
||||
var import_node_http2 = require("http2");
|
||||
var import_node_stream = require("stream");
|
||||
var RequestError = class extends Error {
|
||||
constructor(message, options) {
|
||||
super(message, options);
|
||||
this.name = "RequestError";
|
||||
}
|
||||
};
|
||||
var toRequestError = (e) => {
|
||||
if (e instanceof RequestError) {
|
||||
return e;
|
||||
}
|
||||
return new RequestError(e.message, { cause: e });
|
||||
};
|
||||
var GlobalRequest = global.Request;
|
||||
var Request = class extends GlobalRequest {
|
||||
constructor(input, options) {
|
||||
if (typeof input === "object" && getRequestCache in input) {
|
||||
input = input[getRequestCache]();
|
||||
}
|
||||
if (typeof options?.body?.getReader !== "undefined") {
|
||||
;
|
||||
options.duplex ??= "half";
|
||||
}
|
||||
super(input, options);
|
||||
}
|
||||
};
|
||||
var newHeadersFromIncoming = (incoming) => {
|
||||
const headerRecord = [];
|
||||
const rawHeaders = incoming.rawHeaders;
|
||||
for (let i = 0; i < rawHeaders.length; i += 2) {
|
||||
const { [i]: key, [i + 1]: value } = rawHeaders;
|
||||
if (key.charCodeAt(0) !== /*:*/
|
||||
58) {
|
||||
headerRecord.push([key, value]);
|
||||
}
|
||||
}
|
||||
return new Headers(headerRecord);
|
||||
};
|
||||
var wrapBodyStream = Symbol("wrapBodyStream");
|
||||
var newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
|
||||
const init = {
|
||||
method,
|
||||
headers,
|
||||
signal: abortController.signal
|
||||
};
|
||||
if (method === "TRACE") {
|
||||
init.method = "GET";
|
||||
const req = new Request(url, init);
|
||||
Object.defineProperty(req, "method", {
|
||||
get() {
|
||||
return "TRACE";
|
||||
}
|
||||
});
|
||||
return req;
|
||||
}
|
||||
if (!(method === "GET" || method === "HEAD")) {
|
||||
if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) {
|
||||
init.body = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(incoming.rawBody);
|
||||
controller.close();
|
||||
}
|
||||
});
|
||||
} else if (incoming[wrapBodyStream]) {
|
||||
let reader;
|
||||
init.body = new ReadableStream({
|
||||
async pull(controller) {
|
||||
try {
|
||||
reader ||= import_node_stream.Readable.toWeb(incoming).getReader();
|
||||
const { done, value } = await reader.read();
|
||||
if (done) {
|
||||
controller.close();
|
||||
} else {
|
||||
controller.enqueue(value);
|
||||
}
|
||||
} catch (error) {
|
||||
controller.error(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
init.body = import_node_stream.Readable.toWeb(incoming);
|
||||
}
|
||||
}
|
||||
return new Request(url, init);
|
||||
};
|
||||
var getRequestCache = Symbol("getRequestCache");
|
||||
var requestCache = Symbol("requestCache");
|
||||
var incomingKey = Symbol("incomingKey");
|
||||
var urlKey = Symbol("urlKey");
|
||||
var headersKey = Symbol("headersKey");
|
||||
var abortControllerKey = Symbol("abortControllerKey");
|
||||
var getAbortController = Symbol("getAbortController");
|
||||
var requestPrototype = {
|
||||
get method() {
|
||||
return this[incomingKey].method || "GET";
|
||||
},
|
||||
get url() {
|
||||
return this[urlKey];
|
||||
},
|
||||
get headers() {
|
||||
return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
|
||||
},
|
||||
[getAbortController]() {
|
||||
this[getRequestCache]();
|
||||
return this[abortControllerKey];
|
||||
},
|
||||
[getRequestCache]() {
|
||||
this[abortControllerKey] ||= new AbortController();
|
||||
return this[requestCache] ||= newRequestFromIncoming(
|
||||
this.method,
|
||||
this[urlKey],
|
||||
this.headers,
|
||||
this[incomingKey],
|
||||
this[abortControllerKey]
|
||||
);
|
||||
}
|
||||
};
|
||||
[
|
||||
"body",
|
||||
"bodyUsed",
|
||||
"cache",
|
||||
"credentials",
|
||||
"destination",
|
||||
"integrity",
|
||||
"mode",
|
||||
"redirect",
|
||||
"referrer",
|
||||
"referrerPolicy",
|
||||
"signal",
|
||||
"keepalive"
|
||||
].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
get() {
|
||||
return this[getRequestCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
value: function() {
|
||||
return this[getRequestCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(requestPrototype, Request.prototype);
|
||||
var newRequest = (incoming, defaultHostname) => {
|
||||
const req = Object.create(requestPrototype);
|
||||
req[incomingKey] = incoming;
|
||||
const incomingUrl = incoming.url || "";
|
||||
if (incomingUrl[0] !== "/" && // short-circuit for performance. most requests are relative URL.
|
||||
(incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) {
|
||||
if (incoming instanceof import_node_http2.Http2ServerRequest) {
|
||||
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
||||
}
|
||||
try {
|
||||
const url2 = new URL(incomingUrl);
|
||||
req[urlKey] = url2.href;
|
||||
} catch (e) {
|
||||
throw new RequestError("Invalid absolute URL", { cause: e });
|
||||
}
|
||||
return req;
|
||||
}
|
||||
const host = (incoming instanceof import_node_http2.Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;
|
||||
if (!host) {
|
||||
throw new RequestError("Missing host header");
|
||||
}
|
||||
let scheme;
|
||||
if (incoming instanceof import_node_http2.Http2ServerRequest) {
|
||||
scheme = incoming.scheme;
|
||||
if (!(scheme === "http" || scheme === "https")) {
|
||||
throw new RequestError("Unsupported scheme");
|
||||
}
|
||||
} else {
|
||||
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
||||
}
|
||||
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
||||
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
||||
throw new RequestError("Invalid host header");
|
||||
}
|
||||
req[urlKey] = url.href;
|
||||
return req;
|
||||
};
|
||||
|
||||
// src/response.ts
|
||||
var responseCache = Symbol("responseCache");
|
||||
var getResponseCache = Symbol("getResponseCache");
|
||||
var cacheKey = Symbol("cache");
|
||||
var GlobalResponse = global.Response;
|
||||
var Response2 = class _Response {
|
||||
#body;
|
||||
#init;
|
||||
[getResponseCache]() {
|
||||
delete this[cacheKey];
|
||||
return this[responseCache] ||= new GlobalResponse(this.#body, this.#init);
|
||||
}
|
||||
constructor(body, init) {
|
||||
let headers;
|
||||
this.#body = body;
|
||||
if (init instanceof _Response) {
|
||||
const cachedGlobalResponse = init[responseCache];
|
||||
if (cachedGlobalResponse) {
|
||||
this.#init = cachedGlobalResponse;
|
||||
this[getResponseCache]();
|
||||
return;
|
||||
} else {
|
||||
this.#init = init.#init;
|
||||
headers = new Headers(init.#init.headers);
|
||||
}
|
||||
} else {
|
||||
this.#init = init;
|
||||
}
|
||||
if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) {
|
||||
;
|
||||
this[cacheKey] = [init?.status || 200, body, headers || init?.headers];
|
||||
}
|
||||
}
|
||||
get headers() {
|
||||
const cache = this[cacheKey];
|
||||
if (cache) {
|
||||
if (!(cache[2] instanceof Headers)) {
|
||||
cache[2] = new Headers(
|
||||
cache[2] || { "content-type": "text/plain; charset=UTF-8" }
|
||||
);
|
||||
}
|
||||
return cache[2];
|
||||
}
|
||||
return this[getResponseCache]().headers;
|
||||
}
|
||||
get status() {
|
||||
return this[cacheKey]?.[0] ?? this[getResponseCache]().status;
|
||||
}
|
||||
get ok() {
|
||||
const status = this.status;
|
||||
return status >= 200 && status < 300;
|
||||
}
|
||||
};
|
||||
["body", "bodyUsed", "redirected", "statusText", "trailers", "type", "url"].forEach((k) => {
|
||||
Object.defineProperty(Response2.prototype, k, {
|
||||
get() {
|
||||
return this[getResponseCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(Response2.prototype, k, {
|
||||
value: function() {
|
||||
return this[getResponseCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(Response2, GlobalResponse);
|
||||
Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);
|
||||
|
||||
// src/utils.ts
|
||||
async function readWithoutBlocking(readPromise) {
|
||||
return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
|
||||
}
|
||||
function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
|
||||
const cancel = (error) => {
|
||||
reader.cancel(error).catch(() => {
|
||||
});
|
||||
};
|
||||
writable.on("close", cancel);
|
||||
writable.on("error", cancel);
|
||||
(currentReadPromise ?? reader.read()).then(flow, handleStreamError);
|
||||
return reader.closed.finally(() => {
|
||||
writable.off("close", cancel);
|
||||
writable.off("error", cancel);
|
||||
});
|
||||
function handleStreamError(error) {
|
||||
if (error) {
|
||||
writable.destroy(error);
|
||||
}
|
||||
}
|
||||
function onDrain() {
|
||||
reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
function flow({ done, value }) {
|
||||
try {
|
||||
if (done) {
|
||||
writable.end();
|
||||
} else if (!writable.write(value)) {
|
||||
writable.once("drain", onDrain);
|
||||
} else {
|
||||
return reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
} catch (e) {
|
||||
handleStreamError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
function writeFromReadableStream(stream, writable) {
|
||||
if (stream.locked) {
|
||||
throw new TypeError("ReadableStream is locked.");
|
||||
} else if (writable.destroyed) {
|
||||
return;
|
||||
}
|
||||
return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
|
||||
}
|
||||
var buildOutgoingHttpHeaders = (headers) => {
|
||||
const res = {};
|
||||
if (!(headers instanceof Headers)) {
|
||||
headers = new Headers(headers ?? void 0);
|
||||
}
|
||||
const cookies = [];
|
||||
for (const [k, v] of headers) {
|
||||
if (k === "set-cookie") {
|
||||
cookies.push(v);
|
||||
} else {
|
||||
res[k] = v;
|
||||
}
|
||||
}
|
||||
if (cookies.length > 0) {
|
||||
res["set-cookie"] = cookies;
|
||||
}
|
||||
res["content-type"] ??= "text/plain; charset=UTF-8";
|
||||
return res;
|
||||
};
|
||||
|
||||
// src/utils/response/constants.ts
|
||||
var X_ALREADY_SENT = "x-hono-already-sent";
|
||||
|
||||
// src/globals.ts
|
||||
var import_node_crypto = __toESM(require("crypto"));
|
||||
if (typeof global.crypto === "undefined") {
|
||||
global.crypto = import_node_crypto.default;
|
||||
}
|
||||
|
||||
// src/listener.ts
|
||||
var outgoingEnded = Symbol("outgoingEnded");
|
||||
var handleRequestError = () => new Response(null, {
|
||||
status: 400
|
||||
});
|
||||
var handleFetchError = (e) => new Response(null, {
|
||||
status: e instanceof Error && (e.name === "TimeoutError" || e.constructor.name === "TimeoutError") ? 504 : 500
|
||||
});
|
||||
var handleResponseError = (e, outgoing) => {
|
||||
const err = e instanceof Error ? e : new Error("unknown error", { cause: e });
|
||||
if (err.code === "ERR_STREAM_PREMATURE_CLOSE") {
|
||||
console.info("The user aborted a request.");
|
||||
} else {
|
||||
console.error(e);
|
||||
if (!outgoing.headersSent) {
|
||||
outgoing.writeHead(500, { "Content-Type": "text/plain" });
|
||||
}
|
||||
outgoing.end(`Error: ${err.message}`);
|
||||
outgoing.destroy(err);
|
||||
}
|
||||
};
|
||||
var flushHeaders = (outgoing) => {
|
||||
if ("flushHeaders" in outgoing && outgoing.writable) {
|
||||
outgoing.flushHeaders();
|
||||
}
|
||||
};
|
||||
var responseViaCache = async (res, outgoing) => {
|
||||
let [status, body, header] = res[cacheKey];
|
||||
let hasContentLength = false;
|
||||
if (!header) {
|
||||
header = { "content-type": "text/plain; charset=UTF-8" };
|
||||
} else if (header instanceof Headers) {
|
||||
hasContentLength = header.has("content-length");
|
||||
header = buildOutgoingHttpHeaders(header);
|
||||
} else if (Array.isArray(header)) {
|
||||
const headerObj = new Headers(header);
|
||||
hasContentLength = headerObj.has("content-length");
|
||||
header = buildOutgoingHttpHeaders(headerObj);
|
||||
} else {
|
||||
for (const key in header) {
|
||||
if (key.length === 14 && key.toLowerCase() === "content-length") {
|
||||
hasContentLength = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasContentLength) {
|
||||
if (typeof body === "string") {
|
||||
header["Content-Length"] = Buffer.byteLength(body);
|
||||
} else if (body instanceof Uint8Array) {
|
||||
header["Content-Length"] = body.byteLength;
|
||||
} else if (body instanceof Blob) {
|
||||
header["Content-Length"] = body.size;
|
||||
}
|
||||
}
|
||||
outgoing.writeHead(status, header);
|
||||
if (typeof body === "string" || body instanceof Uint8Array) {
|
||||
outgoing.end(body);
|
||||
} else if (body instanceof Blob) {
|
||||
outgoing.end(new Uint8Array(await body.arrayBuffer()));
|
||||
} else {
|
||||
flushHeaders(outgoing);
|
||||
await writeFromReadableStream(body, outgoing)?.catch(
|
||||
(e) => handleResponseError(e, outgoing)
|
||||
);
|
||||
}
|
||||
;
|
||||
outgoing[outgoingEnded]?.();
|
||||
};
|
||||
var isPromise = (res) => typeof res.then === "function";
|
||||
var responseViaResponseObject = async (res, outgoing, options = {}) => {
|
||||
if (isPromise(res)) {
|
||||
if (options.errorHandler) {
|
||||
try {
|
||||
res = await res;
|
||||
} catch (err) {
|
||||
const errRes = await options.errorHandler(err);
|
||||
if (!errRes) {
|
||||
return;
|
||||
}
|
||||
res = errRes;
|
||||
}
|
||||
} else {
|
||||
res = await res.catch(handleFetchError);
|
||||
}
|
||||
}
|
||||
if (cacheKey in res) {
|
||||
return responseViaCache(res, outgoing);
|
||||
}
|
||||
const resHeaderRecord = buildOutgoingHttpHeaders(res.headers);
|
||||
if (res.body) {
|
||||
const reader = res.body.getReader();
|
||||
const values = [];
|
||||
let done = false;
|
||||
let currentReadPromise = void 0;
|
||||
if (resHeaderRecord["transfer-encoding"] !== "chunked") {
|
||||
let maxReadCount = 2;
|
||||
for (let i = 0; i < maxReadCount; i++) {
|
||||
currentReadPromise ||= reader.read();
|
||||
const chunk = await readWithoutBlocking(currentReadPromise).catch((e) => {
|
||||
console.error(e);
|
||||
done = true;
|
||||
});
|
||||
if (!chunk) {
|
||||
if (i === 1) {
|
||||
await new Promise((resolve) => setTimeout(resolve));
|
||||
maxReadCount = 3;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
currentReadPromise = void 0;
|
||||
if (chunk.value) {
|
||||
values.push(chunk.value);
|
||||
}
|
||||
if (chunk.done) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (done && !("content-length" in resHeaderRecord)) {
|
||||
resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0);
|
||||
}
|
||||
}
|
||||
outgoing.writeHead(res.status, resHeaderRecord);
|
||||
values.forEach((value) => {
|
||||
;
|
||||
outgoing.write(value);
|
||||
});
|
||||
if (done) {
|
||||
outgoing.end();
|
||||
} else {
|
||||
if (values.length === 0) {
|
||||
flushHeaders(outgoing);
|
||||
}
|
||||
await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);
|
||||
}
|
||||
} else if (resHeaderRecord[X_ALREADY_SENT]) {
|
||||
} else {
|
||||
outgoing.writeHead(res.status, resHeaderRecord);
|
||||
outgoing.end();
|
||||
}
|
||||
;
|
||||
outgoing[outgoingEnded]?.();
|
||||
};
|
||||
var getRequestListener = (fetchCallback, options = {}) => {
|
||||
const autoCleanupIncoming = options.autoCleanupIncoming ?? true;
|
||||
if (options.overrideGlobalObjects !== false && global.Request !== Request) {
|
||||
Object.defineProperty(global, "Request", {
|
||||
value: Request
|
||||
});
|
||||
Object.defineProperty(global, "Response", {
|
||||
value: Response2
|
||||
});
|
||||
}
|
||||
return async (incoming, outgoing) => {
|
||||
let res, req;
|
||||
try {
|
||||
req = newRequest(incoming, options.hostname);
|
||||
let incomingEnded = !autoCleanupIncoming || incoming.method === "GET" || incoming.method === "HEAD";
|
||||
if (!incomingEnded) {
|
||||
;
|
||||
incoming[wrapBodyStream] = true;
|
||||
incoming.on("end", () => {
|
||||
incomingEnded = true;
|
||||
});
|
||||
if (incoming instanceof import_node_http22.Http2ServerRequest) {
|
||||
;
|
||||
outgoing[outgoingEnded] = () => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
incoming.destroy();
|
||||
outgoing.destroy();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
outgoing.on("close", () => {
|
||||
const abortController = req[abortControllerKey];
|
||||
if (abortController) {
|
||||
if (incoming.errored) {
|
||||
req[abortControllerKey].abort(incoming.errored.toString());
|
||||
} else if (!outgoing.writableFinished) {
|
||||
req[abortControllerKey].abort("Client connection prematurely closed.");
|
||||
}
|
||||
}
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
incoming.destroy();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
res = fetchCallback(req, { incoming, outgoing });
|
||||
if (cacheKey in res) {
|
||||
return responseViaCache(res, outgoing);
|
||||
}
|
||||
} catch (e) {
|
||||
if (!res) {
|
||||
if (options.errorHandler) {
|
||||
res = await options.errorHandler(req ? e : toRequestError(e));
|
||||
if (!res) {
|
||||
return;
|
||||
}
|
||||
} else if (!req) {
|
||||
res = handleRequestError();
|
||||
} else {
|
||||
res = handleFetchError(e);
|
||||
}
|
||||
} else {
|
||||
return handleResponseError(e, outgoing);
|
||||
}
|
||||
}
|
||||
try {
|
||||
return await responseViaResponseObject(res, outgoing, options);
|
||||
} catch (e) {
|
||||
return handleResponseError(e, outgoing);
|
||||
}
|
||||
};
|
||||
};
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
getRequestListener
|
||||
});
|
||||
565
projects/stt-mcp/node_modules/@hono/node-server/dist/listener.mjs
generated
vendored
Normal file
565
projects/stt-mcp/node_modules/@hono/node-server/dist/listener.mjs
generated
vendored
Normal file
@@ -0,0 +1,565 @@
|
||||
// src/listener.ts
|
||||
import { Http2ServerRequest as Http2ServerRequest2 } from "http2";
|
||||
|
||||
// src/request.ts
|
||||
import { Http2ServerRequest } from "http2";
|
||||
import { Readable } from "stream";
|
||||
var RequestError = class extends Error {
|
||||
constructor(message, options) {
|
||||
super(message, options);
|
||||
this.name = "RequestError";
|
||||
}
|
||||
};
|
||||
var toRequestError = (e) => {
|
||||
if (e instanceof RequestError) {
|
||||
return e;
|
||||
}
|
||||
return new RequestError(e.message, { cause: e });
|
||||
};
|
||||
var GlobalRequest = global.Request;
|
||||
var Request = class extends GlobalRequest {
|
||||
constructor(input, options) {
|
||||
if (typeof input === "object" && getRequestCache in input) {
|
||||
input = input[getRequestCache]();
|
||||
}
|
||||
if (typeof options?.body?.getReader !== "undefined") {
|
||||
;
|
||||
options.duplex ??= "half";
|
||||
}
|
||||
super(input, options);
|
||||
}
|
||||
};
|
||||
var newHeadersFromIncoming = (incoming) => {
|
||||
const headerRecord = [];
|
||||
const rawHeaders = incoming.rawHeaders;
|
||||
for (let i = 0; i < rawHeaders.length; i += 2) {
|
||||
const { [i]: key, [i + 1]: value } = rawHeaders;
|
||||
if (key.charCodeAt(0) !== /*:*/
|
||||
58) {
|
||||
headerRecord.push([key, value]);
|
||||
}
|
||||
}
|
||||
return new Headers(headerRecord);
|
||||
};
|
||||
var wrapBodyStream = Symbol("wrapBodyStream");
|
||||
var newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
|
||||
const init = {
|
||||
method,
|
||||
headers,
|
||||
signal: abortController.signal
|
||||
};
|
||||
if (method === "TRACE") {
|
||||
init.method = "GET";
|
||||
const req = new Request(url, init);
|
||||
Object.defineProperty(req, "method", {
|
||||
get() {
|
||||
return "TRACE";
|
||||
}
|
||||
});
|
||||
return req;
|
||||
}
|
||||
if (!(method === "GET" || method === "HEAD")) {
|
||||
if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) {
|
||||
init.body = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(incoming.rawBody);
|
||||
controller.close();
|
||||
}
|
||||
});
|
||||
} else if (incoming[wrapBodyStream]) {
|
||||
let reader;
|
||||
init.body = new ReadableStream({
|
||||
async pull(controller) {
|
||||
try {
|
||||
reader ||= Readable.toWeb(incoming).getReader();
|
||||
const { done, value } = await reader.read();
|
||||
if (done) {
|
||||
controller.close();
|
||||
} else {
|
||||
controller.enqueue(value);
|
||||
}
|
||||
} catch (error) {
|
||||
controller.error(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
init.body = Readable.toWeb(incoming);
|
||||
}
|
||||
}
|
||||
return new Request(url, init);
|
||||
};
|
||||
var getRequestCache = Symbol("getRequestCache");
|
||||
var requestCache = Symbol("requestCache");
|
||||
var incomingKey = Symbol("incomingKey");
|
||||
var urlKey = Symbol("urlKey");
|
||||
var headersKey = Symbol("headersKey");
|
||||
var abortControllerKey = Symbol("abortControllerKey");
|
||||
var getAbortController = Symbol("getAbortController");
|
||||
var requestPrototype = {
|
||||
get method() {
|
||||
return this[incomingKey].method || "GET";
|
||||
},
|
||||
get url() {
|
||||
return this[urlKey];
|
||||
},
|
||||
get headers() {
|
||||
return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
|
||||
},
|
||||
[getAbortController]() {
|
||||
this[getRequestCache]();
|
||||
return this[abortControllerKey];
|
||||
},
|
||||
[getRequestCache]() {
|
||||
this[abortControllerKey] ||= new AbortController();
|
||||
return this[requestCache] ||= newRequestFromIncoming(
|
||||
this.method,
|
||||
this[urlKey],
|
||||
this.headers,
|
||||
this[incomingKey],
|
||||
this[abortControllerKey]
|
||||
);
|
||||
}
|
||||
};
|
||||
[
|
||||
"body",
|
||||
"bodyUsed",
|
||||
"cache",
|
||||
"credentials",
|
||||
"destination",
|
||||
"integrity",
|
||||
"mode",
|
||||
"redirect",
|
||||
"referrer",
|
||||
"referrerPolicy",
|
||||
"signal",
|
||||
"keepalive"
|
||||
].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
get() {
|
||||
return this[getRequestCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
value: function() {
|
||||
return this[getRequestCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(requestPrototype, Request.prototype);
|
||||
var newRequest = (incoming, defaultHostname) => {
|
||||
const req = Object.create(requestPrototype);
|
||||
req[incomingKey] = incoming;
|
||||
const incomingUrl = incoming.url || "";
|
||||
if (incomingUrl[0] !== "/" && // short-circuit for performance. most requests are relative URL.
|
||||
(incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) {
|
||||
if (incoming instanceof Http2ServerRequest) {
|
||||
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
||||
}
|
||||
try {
|
||||
const url2 = new URL(incomingUrl);
|
||||
req[urlKey] = url2.href;
|
||||
} catch (e) {
|
||||
throw new RequestError("Invalid absolute URL", { cause: e });
|
||||
}
|
||||
return req;
|
||||
}
|
||||
const host = (incoming instanceof Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;
|
||||
if (!host) {
|
||||
throw new RequestError("Missing host header");
|
||||
}
|
||||
let scheme;
|
||||
if (incoming instanceof Http2ServerRequest) {
|
||||
scheme = incoming.scheme;
|
||||
if (!(scheme === "http" || scheme === "https")) {
|
||||
throw new RequestError("Unsupported scheme");
|
||||
}
|
||||
} else {
|
||||
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
||||
}
|
||||
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
||||
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
||||
throw new RequestError("Invalid host header");
|
||||
}
|
||||
req[urlKey] = url.href;
|
||||
return req;
|
||||
};
|
||||
|
||||
// src/response.ts
|
||||
var responseCache = Symbol("responseCache");
|
||||
var getResponseCache = Symbol("getResponseCache");
|
||||
var cacheKey = Symbol("cache");
|
||||
var GlobalResponse = global.Response;
|
||||
var Response2 = class _Response {
|
||||
#body;
|
||||
#init;
|
||||
[getResponseCache]() {
|
||||
delete this[cacheKey];
|
||||
return this[responseCache] ||= new GlobalResponse(this.#body, this.#init);
|
||||
}
|
||||
constructor(body, init) {
|
||||
let headers;
|
||||
this.#body = body;
|
||||
if (init instanceof _Response) {
|
||||
const cachedGlobalResponse = init[responseCache];
|
||||
if (cachedGlobalResponse) {
|
||||
this.#init = cachedGlobalResponse;
|
||||
this[getResponseCache]();
|
||||
return;
|
||||
} else {
|
||||
this.#init = init.#init;
|
||||
headers = new Headers(init.#init.headers);
|
||||
}
|
||||
} else {
|
||||
this.#init = init;
|
||||
}
|
||||
if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) {
|
||||
;
|
||||
this[cacheKey] = [init?.status || 200, body, headers || init?.headers];
|
||||
}
|
||||
}
|
||||
get headers() {
|
||||
const cache = this[cacheKey];
|
||||
if (cache) {
|
||||
if (!(cache[2] instanceof Headers)) {
|
||||
cache[2] = new Headers(
|
||||
cache[2] || { "content-type": "text/plain; charset=UTF-8" }
|
||||
);
|
||||
}
|
||||
return cache[2];
|
||||
}
|
||||
return this[getResponseCache]().headers;
|
||||
}
|
||||
get status() {
|
||||
return this[cacheKey]?.[0] ?? this[getResponseCache]().status;
|
||||
}
|
||||
get ok() {
|
||||
const status = this.status;
|
||||
return status >= 200 && status < 300;
|
||||
}
|
||||
};
|
||||
["body", "bodyUsed", "redirected", "statusText", "trailers", "type", "url"].forEach((k) => {
|
||||
Object.defineProperty(Response2.prototype, k, {
|
||||
get() {
|
||||
return this[getResponseCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(Response2.prototype, k, {
|
||||
value: function() {
|
||||
return this[getResponseCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(Response2, GlobalResponse);
|
||||
Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);
|
||||
|
||||
// src/utils.ts
|
||||
async function readWithoutBlocking(readPromise) {
|
||||
return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
|
||||
}
|
||||
function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
|
||||
const cancel = (error) => {
|
||||
reader.cancel(error).catch(() => {
|
||||
});
|
||||
};
|
||||
writable.on("close", cancel);
|
||||
writable.on("error", cancel);
|
||||
(currentReadPromise ?? reader.read()).then(flow, handleStreamError);
|
||||
return reader.closed.finally(() => {
|
||||
writable.off("close", cancel);
|
||||
writable.off("error", cancel);
|
||||
});
|
||||
function handleStreamError(error) {
|
||||
if (error) {
|
||||
writable.destroy(error);
|
||||
}
|
||||
}
|
||||
function onDrain() {
|
||||
reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
function flow({ done, value }) {
|
||||
try {
|
||||
if (done) {
|
||||
writable.end();
|
||||
} else if (!writable.write(value)) {
|
||||
writable.once("drain", onDrain);
|
||||
} else {
|
||||
return reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
} catch (e) {
|
||||
handleStreamError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
function writeFromReadableStream(stream, writable) {
|
||||
if (stream.locked) {
|
||||
throw new TypeError("ReadableStream is locked.");
|
||||
} else if (writable.destroyed) {
|
||||
return;
|
||||
}
|
||||
return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
|
||||
}
|
||||
var buildOutgoingHttpHeaders = (headers) => {
|
||||
const res = {};
|
||||
if (!(headers instanceof Headers)) {
|
||||
headers = new Headers(headers ?? void 0);
|
||||
}
|
||||
const cookies = [];
|
||||
for (const [k, v] of headers) {
|
||||
if (k === "set-cookie") {
|
||||
cookies.push(v);
|
||||
} else {
|
||||
res[k] = v;
|
||||
}
|
||||
}
|
||||
if (cookies.length > 0) {
|
||||
res["set-cookie"] = cookies;
|
||||
}
|
||||
res["content-type"] ??= "text/plain; charset=UTF-8";
|
||||
return res;
|
||||
};
|
||||
|
||||
// src/utils/response/constants.ts
|
||||
var X_ALREADY_SENT = "x-hono-already-sent";
|
||||
|
||||
// src/globals.ts
|
||||
import crypto from "crypto";
|
||||
if (typeof global.crypto === "undefined") {
|
||||
global.crypto = crypto;
|
||||
}
|
||||
|
||||
// src/listener.ts
|
||||
var outgoingEnded = Symbol("outgoingEnded");
|
||||
var handleRequestError = () => new Response(null, {
|
||||
status: 400
|
||||
});
|
||||
var handleFetchError = (e) => new Response(null, {
|
||||
status: e instanceof Error && (e.name === "TimeoutError" || e.constructor.name === "TimeoutError") ? 504 : 500
|
||||
});
|
||||
var handleResponseError = (e, outgoing) => {
|
||||
const err = e instanceof Error ? e : new Error("unknown error", { cause: e });
|
||||
if (err.code === "ERR_STREAM_PREMATURE_CLOSE") {
|
||||
console.info("The user aborted a request.");
|
||||
} else {
|
||||
console.error(e);
|
||||
if (!outgoing.headersSent) {
|
||||
outgoing.writeHead(500, { "Content-Type": "text/plain" });
|
||||
}
|
||||
outgoing.end(`Error: ${err.message}`);
|
||||
outgoing.destroy(err);
|
||||
}
|
||||
};
|
||||
var flushHeaders = (outgoing) => {
|
||||
if ("flushHeaders" in outgoing && outgoing.writable) {
|
||||
outgoing.flushHeaders();
|
||||
}
|
||||
};
|
||||
var responseViaCache = async (res, outgoing) => {
|
||||
let [status, body, header] = res[cacheKey];
|
||||
let hasContentLength = false;
|
||||
if (!header) {
|
||||
header = { "content-type": "text/plain; charset=UTF-8" };
|
||||
} else if (header instanceof Headers) {
|
||||
hasContentLength = header.has("content-length");
|
||||
header = buildOutgoingHttpHeaders(header);
|
||||
} else if (Array.isArray(header)) {
|
||||
const headerObj = new Headers(header);
|
||||
hasContentLength = headerObj.has("content-length");
|
||||
header = buildOutgoingHttpHeaders(headerObj);
|
||||
} else {
|
||||
for (const key in header) {
|
||||
if (key.length === 14 && key.toLowerCase() === "content-length") {
|
||||
hasContentLength = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasContentLength) {
|
||||
if (typeof body === "string") {
|
||||
header["Content-Length"] = Buffer.byteLength(body);
|
||||
} else if (body instanceof Uint8Array) {
|
||||
header["Content-Length"] = body.byteLength;
|
||||
} else if (body instanceof Blob) {
|
||||
header["Content-Length"] = body.size;
|
||||
}
|
||||
}
|
||||
outgoing.writeHead(status, header);
|
||||
if (typeof body === "string" || body instanceof Uint8Array) {
|
||||
outgoing.end(body);
|
||||
} else if (body instanceof Blob) {
|
||||
outgoing.end(new Uint8Array(await body.arrayBuffer()));
|
||||
} else {
|
||||
flushHeaders(outgoing);
|
||||
await writeFromReadableStream(body, outgoing)?.catch(
|
||||
(e) => handleResponseError(e, outgoing)
|
||||
);
|
||||
}
|
||||
;
|
||||
outgoing[outgoingEnded]?.();
|
||||
};
|
||||
var isPromise = (res) => typeof res.then === "function";
|
||||
var responseViaResponseObject = async (res, outgoing, options = {}) => {
|
||||
if (isPromise(res)) {
|
||||
if (options.errorHandler) {
|
||||
try {
|
||||
res = await res;
|
||||
} catch (err) {
|
||||
const errRes = await options.errorHandler(err);
|
||||
if (!errRes) {
|
||||
return;
|
||||
}
|
||||
res = errRes;
|
||||
}
|
||||
} else {
|
||||
res = await res.catch(handleFetchError);
|
||||
}
|
||||
}
|
||||
if (cacheKey in res) {
|
||||
return responseViaCache(res, outgoing);
|
||||
}
|
||||
const resHeaderRecord = buildOutgoingHttpHeaders(res.headers);
|
||||
if (res.body) {
|
||||
const reader = res.body.getReader();
|
||||
const values = [];
|
||||
let done = false;
|
||||
let currentReadPromise = void 0;
|
||||
if (resHeaderRecord["transfer-encoding"] !== "chunked") {
|
||||
let maxReadCount = 2;
|
||||
for (let i = 0; i < maxReadCount; i++) {
|
||||
currentReadPromise ||= reader.read();
|
||||
const chunk = await readWithoutBlocking(currentReadPromise).catch((e) => {
|
||||
console.error(e);
|
||||
done = true;
|
||||
});
|
||||
if (!chunk) {
|
||||
if (i === 1) {
|
||||
await new Promise((resolve) => setTimeout(resolve));
|
||||
maxReadCount = 3;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
currentReadPromise = void 0;
|
||||
if (chunk.value) {
|
||||
values.push(chunk.value);
|
||||
}
|
||||
if (chunk.done) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (done && !("content-length" in resHeaderRecord)) {
|
||||
resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0);
|
||||
}
|
||||
}
|
||||
outgoing.writeHead(res.status, resHeaderRecord);
|
||||
values.forEach((value) => {
|
||||
;
|
||||
outgoing.write(value);
|
||||
});
|
||||
if (done) {
|
||||
outgoing.end();
|
||||
} else {
|
||||
if (values.length === 0) {
|
||||
flushHeaders(outgoing);
|
||||
}
|
||||
await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);
|
||||
}
|
||||
} else if (resHeaderRecord[X_ALREADY_SENT]) {
|
||||
} else {
|
||||
outgoing.writeHead(res.status, resHeaderRecord);
|
||||
outgoing.end();
|
||||
}
|
||||
;
|
||||
outgoing[outgoingEnded]?.();
|
||||
};
|
||||
var getRequestListener = (fetchCallback, options = {}) => {
|
||||
const autoCleanupIncoming = options.autoCleanupIncoming ?? true;
|
||||
if (options.overrideGlobalObjects !== false && global.Request !== Request) {
|
||||
Object.defineProperty(global, "Request", {
|
||||
value: Request
|
||||
});
|
||||
Object.defineProperty(global, "Response", {
|
||||
value: Response2
|
||||
});
|
||||
}
|
||||
return async (incoming, outgoing) => {
|
||||
let res, req;
|
||||
try {
|
||||
req = newRequest(incoming, options.hostname);
|
||||
let incomingEnded = !autoCleanupIncoming || incoming.method === "GET" || incoming.method === "HEAD";
|
||||
if (!incomingEnded) {
|
||||
;
|
||||
incoming[wrapBodyStream] = true;
|
||||
incoming.on("end", () => {
|
||||
incomingEnded = true;
|
||||
});
|
||||
if (incoming instanceof Http2ServerRequest2) {
|
||||
;
|
||||
outgoing[outgoingEnded] = () => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
incoming.destroy();
|
||||
outgoing.destroy();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
outgoing.on("close", () => {
|
||||
const abortController = req[abortControllerKey];
|
||||
if (abortController) {
|
||||
if (incoming.errored) {
|
||||
req[abortControllerKey].abort(incoming.errored.toString());
|
||||
} else if (!outgoing.writableFinished) {
|
||||
req[abortControllerKey].abort("Client connection prematurely closed.");
|
||||
}
|
||||
}
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
incoming.destroy();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
res = fetchCallback(req, { incoming, outgoing });
|
||||
if (cacheKey in res) {
|
||||
return responseViaCache(res, outgoing);
|
||||
}
|
||||
} catch (e) {
|
||||
if (!res) {
|
||||
if (options.errorHandler) {
|
||||
res = await options.errorHandler(req ? e : toRequestError(e));
|
||||
if (!res) {
|
||||
return;
|
||||
}
|
||||
} else if (!req) {
|
||||
res = handleRequestError();
|
||||
} else {
|
||||
res = handleFetchError(e);
|
||||
}
|
||||
} else {
|
||||
return handleResponseError(e, outgoing);
|
||||
}
|
||||
}
|
||||
try {
|
||||
return await responseViaResponseObject(res, outgoing, options);
|
||||
} catch (e) {
|
||||
return handleResponseError(e, outgoing);
|
||||
}
|
||||
};
|
||||
};
|
||||
export {
|
||||
getRequestListener
|
||||
};
|
||||
25
projects/stt-mcp/node_modules/@hono/node-server/dist/request.d.mts
generated
vendored
Normal file
25
projects/stt-mcp/node_modules/@hono/node-server/dist/request.d.mts
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
import { IncomingMessage } from 'node:http';
|
||||
import { Http2ServerRequest } from 'node:http2';
|
||||
|
||||
declare class RequestError extends Error {
|
||||
constructor(message: string, options?: {
|
||||
cause?: unknown;
|
||||
});
|
||||
}
|
||||
declare const toRequestError: (e: unknown) => RequestError;
|
||||
declare const GlobalRequest: {
|
||||
new (input: RequestInfo | URL, init?: RequestInit): globalThis.Request;
|
||||
prototype: globalThis.Request;
|
||||
};
|
||||
declare class Request extends GlobalRequest {
|
||||
constructor(input: string | Request, options?: RequestInit);
|
||||
}
|
||||
type IncomingMessageWithWrapBodyStream = IncomingMessage & {
|
||||
[wrapBodyStream]: boolean;
|
||||
};
|
||||
declare const wrapBodyStream: unique symbol;
|
||||
declare const abortControllerKey: unique symbol;
|
||||
declare const getAbortController: unique symbol;
|
||||
declare const newRequest: (incoming: IncomingMessage | Http2ServerRequest, defaultHostname?: string) => any;
|
||||
|
||||
export { GlobalRequest, IncomingMessageWithWrapBodyStream, Request, RequestError, abortControllerKey, getAbortController, newRequest, toRequestError, wrapBodyStream };
|
||||
25
projects/stt-mcp/node_modules/@hono/node-server/dist/request.d.ts
generated
vendored
Normal file
25
projects/stt-mcp/node_modules/@hono/node-server/dist/request.d.ts
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
import { IncomingMessage } from 'node:http';
|
||||
import { Http2ServerRequest } from 'node:http2';
|
||||
|
||||
declare class RequestError extends Error {
|
||||
constructor(message: string, options?: {
|
||||
cause?: unknown;
|
||||
});
|
||||
}
|
||||
declare const toRequestError: (e: unknown) => RequestError;
|
||||
declare const GlobalRequest: {
|
||||
new (input: RequestInfo | URL, init?: RequestInit): globalThis.Request;
|
||||
prototype: globalThis.Request;
|
||||
};
|
||||
declare class Request extends GlobalRequest {
|
||||
constructor(input: string | Request, options?: RequestInit);
|
||||
}
|
||||
type IncomingMessageWithWrapBodyStream = IncomingMessage & {
|
||||
[wrapBodyStream]: boolean;
|
||||
};
|
||||
declare const wrapBodyStream: unique symbol;
|
||||
declare const abortControllerKey: unique symbol;
|
||||
declare const getAbortController: unique symbol;
|
||||
declare const newRequest: (incoming: IncomingMessage | Http2ServerRequest, defaultHostname?: string) => any;
|
||||
|
||||
export { GlobalRequest, IncomingMessageWithWrapBodyStream, Request, RequestError, abortControllerKey, getAbortController, newRequest, toRequestError, wrapBodyStream };
|
||||
227
projects/stt-mcp/node_modules/@hono/node-server/dist/request.js
generated
vendored
Normal file
227
projects/stt-mcp/node_modules/@hono/node-server/dist/request.js
generated
vendored
Normal file
@@ -0,0 +1,227 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/request.ts
|
||||
var request_exports = {};
|
||||
__export(request_exports, {
|
||||
GlobalRequest: () => GlobalRequest,
|
||||
Request: () => Request,
|
||||
RequestError: () => RequestError,
|
||||
abortControllerKey: () => abortControllerKey,
|
||||
getAbortController: () => getAbortController,
|
||||
newRequest: () => newRequest,
|
||||
toRequestError: () => toRequestError,
|
||||
wrapBodyStream: () => wrapBodyStream
|
||||
});
|
||||
module.exports = __toCommonJS(request_exports);
|
||||
var import_node_http2 = require("http2");
|
||||
var import_node_stream = require("stream");
|
||||
var RequestError = class extends Error {
|
||||
constructor(message, options) {
|
||||
super(message, options);
|
||||
this.name = "RequestError";
|
||||
}
|
||||
};
|
||||
var toRequestError = (e) => {
|
||||
if (e instanceof RequestError) {
|
||||
return e;
|
||||
}
|
||||
return new RequestError(e.message, { cause: e });
|
||||
};
|
||||
var GlobalRequest = global.Request;
|
||||
var Request = class extends GlobalRequest {
|
||||
constructor(input, options) {
|
||||
if (typeof input === "object" && getRequestCache in input) {
|
||||
input = input[getRequestCache]();
|
||||
}
|
||||
if (typeof options?.body?.getReader !== "undefined") {
|
||||
;
|
||||
options.duplex ??= "half";
|
||||
}
|
||||
super(input, options);
|
||||
}
|
||||
};
|
||||
var newHeadersFromIncoming = (incoming) => {
|
||||
const headerRecord = [];
|
||||
const rawHeaders = incoming.rawHeaders;
|
||||
for (let i = 0; i < rawHeaders.length; i += 2) {
|
||||
const { [i]: key, [i + 1]: value } = rawHeaders;
|
||||
if (key.charCodeAt(0) !== /*:*/
|
||||
58) {
|
||||
headerRecord.push([key, value]);
|
||||
}
|
||||
}
|
||||
return new Headers(headerRecord);
|
||||
};
|
||||
var wrapBodyStream = Symbol("wrapBodyStream");
|
||||
var newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
|
||||
const init = {
|
||||
method,
|
||||
headers,
|
||||
signal: abortController.signal
|
||||
};
|
||||
if (method === "TRACE") {
|
||||
init.method = "GET";
|
||||
const req = new Request(url, init);
|
||||
Object.defineProperty(req, "method", {
|
||||
get() {
|
||||
return "TRACE";
|
||||
}
|
||||
});
|
||||
return req;
|
||||
}
|
||||
if (!(method === "GET" || method === "HEAD")) {
|
||||
if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) {
|
||||
init.body = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(incoming.rawBody);
|
||||
controller.close();
|
||||
}
|
||||
});
|
||||
} else if (incoming[wrapBodyStream]) {
|
||||
let reader;
|
||||
init.body = new ReadableStream({
|
||||
async pull(controller) {
|
||||
try {
|
||||
reader ||= import_node_stream.Readable.toWeb(incoming).getReader();
|
||||
const { done, value } = await reader.read();
|
||||
if (done) {
|
||||
controller.close();
|
||||
} else {
|
||||
controller.enqueue(value);
|
||||
}
|
||||
} catch (error) {
|
||||
controller.error(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
init.body = import_node_stream.Readable.toWeb(incoming);
|
||||
}
|
||||
}
|
||||
return new Request(url, init);
|
||||
};
|
||||
var getRequestCache = Symbol("getRequestCache");
|
||||
var requestCache = Symbol("requestCache");
|
||||
var incomingKey = Symbol("incomingKey");
|
||||
var urlKey = Symbol("urlKey");
|
||||
var headersKey = Symbol("headersKey");
|
||||
var abortControllerKey = Symbol("abortControllerKey");
|
||||
var getAbortController = Symbol("getAbortController");
|
||||
var requestPrototype = {
|
||||
get method() {
|
||||
return this[incomingKey].method || "GET";
|
||||
},
|
||||
get url() {
|
||||
return this[urlKey];
|
||||
},
|
||||
get headers() {
|
||||
return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
|
||||
},
|
||||
[getAbortController]() {
|
||||
this[getRequestCache]();
|
||||
return this[abortControllerKey];
|
||||
},
|
||||
[getRequestCache]() {
|
||||
this[abortControllerKey] ||= new AbortController();
|
||||
return this[requestCache] ||= newRequestFromIncoming(
|
||||
this.method,
|
||||
this[urlKey],
|
||||
this.headers,
|
||||
this[incomingKey],
|
||||
this[abortControllerKey]
|
||||
);
|
||||
}
|
||||
};
|
||||
[
|
||||
"body",
|
||||
"bodyUsed",
|
||||
"cache",
|
||||
"credentials",
|
||||
"destination",
|
||||
"integrity",
|
||||
"mode",
|
||||
"redirect",
|
||||
"referrer",
|
||||
"referrerPolicy",
|
||||
"signal",
|
||||
"keepalive"
|
||||
].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
get() {
|
||||
return this[getRequestCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
value: function() {
|
||||
return this[getRequestCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(requestPrototype, Request.prototype);
|
||||
var newRequest = (incoming, defaultHostname) => {
|
||||
const req = Object.create(requestPrototype);
|
||||
req[incomingKey] = incoming;
|
||||
const incomingUrl = incoming.url || "";
|
||||
if (incomingUrl[0] !== "/" && // short-circuit for performance. most requests are relative URL.
|
||||
(incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) {
|
||||
if (incoming instanceof import_node_http2.Http2ServerRequest) {
|
||||
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
||||
}
|
||||
try {
|
||||
const url2 = new URL(incomingUrl);
|
||||
req[urlKey] = url2.href;
|
||||
} catch (e) {
|
||||
throw new RequestError("Invalid absolute URL", { cause: e });
|
||||
}
|
||||
return req;
|
||||
}
|
||||
const host = (incoming instanceof import_node_http2.Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;
|
||||
if (!host) {
|
||||
throw new RequestError("Missing host header");
|
||||
}
|
||||
let scheme;
|
||||
if (incoming instanceof import_node_http2.Http2ServerRequest) {
|
||||
scheme = incoming.scheme;
|
||||
if (!(scheme === "http" || scheme === "https")) {
|
||||
throw new RequestError("Unsupported scheme");
|
||||
}
|
||||
} else {
|
||||
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
||||
}
|
||||
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
||||
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
||||
throw new RequestError("Invalid host header");
|
||||
}
|
||||
req[urlKey] = url.href;
|
||||
return req;
|
||||
};
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
GlobalRequest,
|
||||
Request,
|
||||
RequestError,
|
||||
abortControllerKey,
|
||||
getAbortController,
|
||||
newRequest,
|
||||
toRequestError,
|
||||
wrapBodyStream
|
||||
});
|
||||
195
projects/stt-mcp/node_modules/@hono/node-server/dist/request.mjs
generated
vendored
Normal file
195
projects/stt-mcp/node_modules/@hono/node-server/dist/request.mjs
generated
vendored
Normal file
@@ -0,0 +1,195 @@
|
||||
// src/request.ts
|
||||
import { Http2ServerRequest } from "http2";
|
||||
import { Readable } from "stream";
|
||||
var RequestError = class extends Error {
|
||||
constructor(message, options) {
|
||||
super(message, options);
|
||||
this.name = "RequestError";
|
||||
}
|
||||
};
|
||||
var toRequestError = (e) => {
|
||||
if (e instanceof RequestError) {
|
||||
return e;
|
||||
}
|
||||
return new RequestError(e.message, { cause: e });
|
||||
};
|
||||
var GlobalRequest = global.Request;
|
||||
var Request = class extends GlobalRequest {
|
||||
constructor(input, options) {
|
||||
if (typeof input === "object" && getRequestCache in input) {
|
||||
input = input[getRequestCache]();
|
||||
}
|
||||
if (typeof options?.body?.getReader !== "undefined") {
|
||||
;
|
||||
options.duplex ??= "half";
|
||||
}
|
||||
super(input, options);
|
||||
}
|
||||
};
|
||||
var newHeadersFromIncoming = (incoming) => {
|
||||
const headerRecord = [];
|
||||
const rawHeaders = incoming.rawHeaders;
|
||||
for (let i = 0; i < rawHeaders.length; i += 2) {
|
||||
const { [i]: key, [i + 1]: value } = rawHeaders;
|
||||
if (key.charCodeAt(0) !== /*:*/
|
||||
58) {
|
||||
headerRecord.push([key, value]);
|
||||
}
|
||||
}
|
||||
return new Headers(headerRecord);
|
||||
};
|
||||
var wrapBodyStream = Symbol("wrapBodyStream");
|
||||
var newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
|
||||
const init = {
|
||||
method,
|
||||
headers,
|
||||
signal: abortController.signal
|
||||
};
|
||||
if (method === "TRACE") {
|
||||
init.method = "GET";
|
||||
const req = new Request(url, init);
|
||||
Object.defineProperty(req, "method", {
|
||||
get() {
|
||||
return "TRACE";
|
||||
}
|
||||
});
|
||||
return req;
|
||||
}
|
||||
if (!(method === "GET" || method === "HEAD")) {
|
||||
if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) {
|
||||
init.body = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(incoming.rawBody);
|
||||
controller.close();
|
||||
}
|
||||
});
|
||||
} else if (incoming[wrapBodyStream]) {
|
||||
let reader;
|
||||
init.body = new ReadableStream({
|
||||
async pull(controller) {
|
||||
try {
|
||||
reader ||= Readable.toWeb(incoming).getReader();
|
||||
const { done, value } = await reader.read();
|
||||
if (done) {
|
||||
controller.close();
|
||||
} else {
|
||||
controller.enqueue(value);
|
||||
}
|
||||
} catch (error) {
|
||||
controller.error(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
init.body = Readable.toWeb(incoming);
|
||||
}
|
||||
}
|
||||
return new Request(url, init);
|
||||
};
|
||||
var getRequestCache = Symbol("getRequestCache");
|
||||
var requestCache = Symbol("requestCache");
|
||||
var incomingKey = Symbol("incomingKey");
|
||||
var urlKey = Symbol("urlKey");
|
||||
var headersKey = Symbol("headersKey");
|
||||
var abortControllerKey = Symbol("abortControllerKey");
|
||||
var getAbortController = Symbol("getAbortController");
|
||||
var requestPrototype = {
|
||||
get method() {
|
||||
return this[incomingKey].method || "GET";
|
||||
},
|
||||
get url() {
|
||||
return this[urlKey];
|
||||
},
|
||||
get headers() {
|
||||
return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
|
||||
},
|
||||
[getAbortController]() {
|
||||
this[getRequestCache]();
|
||||
return this[abortControllerKey];
|
||||
},
|
||||
[getRequestCache]() {
|
||||
this[abortControllerKey] ||= new AbortController();
|
||||
return this[requestCache] ||= newRequestFromIncoming(
|
||||
this.method,
|
||||
this[urlKey],
|
||||
this.headers,
|
||||
this[incomingKey],
|
||||
this[abortControllerKey]
|
||||
);
|
||||
}
|
||||
};
|
||||
[
|
||||
"body",
|
||||
"bodyUsed",
|
||||
"cache",
|
||||
"credentials",
|
||||
"destination",
|
||||
"integrity",
|
||||
"mode",
|
||||
"redirect",
|
||||
"referrer",
|
||||
"referrerPolicy",
|
||||
"signal",
|
||||
"keepalive"
|
||||
].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
get() {
|
||||
return this[getRequestCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
value: function() {
|
||||
return this[getRequestCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(requestPrototype, Request.prototype);
|
||||
var newRequest = (incoming, defaultHostname) => {
|
||||
const req = Object.create(requestPrototype);
|
||||
req[incomingKey] = incoming;
|
||||
const incomingUrl = incoming.url || "";
|
||||
if (incomingUrl[0] !== "/" && // short-circuit for performance. most requests are relative URL.
|
||||
(incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) {
|
||||
if (incoming instanceof Http2ServerRequest) {
|
||||
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
||||
}
|
||||
try {
|
||||
const url2 = new URL(incomingUrl);
|
||||
req[urlKey] = url2.href;
|
||||
} catch (e) {
|
||||
throw new RequestError("Invalid absolute URL", { cause: e });
|
||||
}
|
||||
return req;
|
||||
}
|
||||
const host = (incoming instanceof Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;
|
||||
if (!host) {
|
||||
throw new RequestError("Missing host header");
|
||||
}
|
||||
let scheme;
|
||||
if (incoming instanceof Http2ServerRequest) {
|
||||
scheme = incoming.scheme;
|
||||
if (!(scheme === "http" || scheme === "https")) {
|
||||
throw new RequestError("Unsupported scheme");
|
||||
}
|
||||
} else {
|
||||
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
||||
}
|
||||
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
||||
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
||||
throw new RequestError("Invalid host header");
|
||||
}
|
||||
req[urlKey] = url.href;
|
||||
return req;
|
||||
};
|
||||
export {
|
||||
GlobalRequest,
|
||||
Request,
|
||||
RequestError,
|
||||
abortControllerKey,
|
||||
getAbortController,
|
||||
newRequest,
|
||||
toRequestError,
|
||||
wrapBodyStream
|
||||
};
|
||||
26
projects/stt-mcp/node_modules/@hono/node-server/dist/response.d.mts
generated
vendored
Normal file
26
projects/stt-mcp/node_modules/@hono/node-server/dist/response.d.mts
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
import { OutgoingHttpHeaders } from 'node:http';
|
||||
|
||||
declare const getResponseCache: unique symbol;
|
||||
declare const cacheKey: unique symbol;
|
||||
type InternalCache = [
|
||||
number,
|
||||
string | ReadableStream,
|
||||
Record<string, string> | [string, string][] | Headers | OutgoingHttpHeaders | undefined
|
||||
];
|
||||
declare const GlobalResponse: {
|
||||
new (body?: BodyInit | null, init?: ResponseInit): globalThis.Response;
|
||||
prototype: globalThis.Response;
|
||||
error(): globalThis.Response;
|
||||
json(data: any, init?: ResponseInit): globalThis.Response;
|
||||
redirect(url: string | URL, status?: number): globalThis.Response;
|
||||
};
|
||||
declare class Response {
|
||||
#private;
|
||||
[getResponseCache](): globalThis.Response;
|
||||
constructor(body?: BodyInit | null, init?: ResponseInit);
|
||||
get headers(): Headers;
|
||||
get status(): number;
|
||||
get ok(): boolean;
|
||||
}
|
||||
|
||||
export { GlobalResponse, InternalCache, Response, cacheKey };
|
||||
26
projects/stt-mcp/node_modules/@hono/node-server/dist/response.d.ts
generated
vendored
Normal file
26
projects/stt-mcp/node_modules/@hono/node-server/dist/response.d.ts
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
import { OutgoingHttpHeaders } from 'node:http';
|
||||
|
||||
declare const getResponseCache: unique symbol;
|
||||
declare const cacheKey: unique symbol;
|
||||
type InternalCache = [
|
||||
number,
|
||||
string | ReadableStream,
|
||||
Record<string, string> | [string, string][] | Headers | OutgoingHttpHeaders | undefined
|
||||
];
|
||||
declare const GlobalResponse: {
|
||||
new (body?: BodyInit | null, init?: ResponseInit): globalThis.Response;
|
||||
prototype: globalThis.Response;
|
||||
error(): globalThis.Response;
|
||||
json(data: any, init?: ResponseInit): globalThis.Response;
|
||||
redirect(url: string | URL, status?: number): globalThis.Response;
|
||||
};
|
||||
declare class Response {
|
||||
#private;
|
||||
[getResponseCache](): globalThis.Response;
|
||||
constructor(body?: BodyInit | null, init?: ResponseInit);
|
||||
get headers(): Headers;
|
||||
get status(): number;
|
||||
get ok(): boolean;
|
||||
}
|
||||
|
||||
export { GlobalResponse, InternalCache, Response, cacheKey };
|
||||
101
projects/stt-mcp/node_modules/@hono/node-server/dist/response.js
generated
vendored
Normal file
101
projects/stt-mcp/node_modules/@hono/node-server/dist/response.js
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/response.ts
|
||||
var response_exports = {};
|
||||
__export(response_exports, {
|
||||
GlobalResponse: () => GlobalResponse,
|
||||
Response: () => Response,
|
||||
cacheKey: () => cacheKey
|
||||
});
|
||||
module.exports = __toCommonJS(response_exports);
|
||||
var responseCache = Symbol("responseCache");
|
||||
var getResponseCache = Symbol("getResponseCache");
|
||||
var cacheKey = Symbol("cache");
|
||||
var GlobalResponse = global.Response;
|
||||
var Response = class _Response {
|
||||
#body;
|
||||
#init;
|
||||
[getResponseCache]() {
|
||||
delete this[cacheKey];
|
||||
return this[responseCache] ||= new GlobalResponse(this.#body, this.#init);
|
||||
}
|
||||
constructor(body, init) {
|
||||
let headers;
|
||||
this.#body = body;
|
||||
if (init instanceof _Response) {
|
||||
const cachedGlobalResponse = init[responseCache];
|
||||
if (cachedGlobalResponse) {
|
||||
this.#init = cachedGlobalResponse;
|
||||
this[getResponseCache]();
|
||||
return;
|
||||
} else {
|
||||
this.#init = init.#init;
|
||||
headers = new Headers(init.#init.headers);
|
||||
}
|
||||
} else {
|
||||
this.#init = init;
|
||||
}
|
||||
if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) {
|
||||
;
|
||||
this[cacheKey] = [init?.status || 200, body, headers || init?.headers];
|
||||
}
|
||||
}
|
||||
get headers() {
|
||||
const cache = this[cacheKey];
|
||||
if (cache) {
|
||||
if (!(cache[2] instanceof Headers)) {
|
||||
cache[2] = new Headers(
|
||||
cache[2] || { "content-type": "text/plain; charset=UTF-8" }
|
||||
);
|
||||
}
|
||||
return cache[2];
|
||||
}
|
||||
return this[getResponseCache]().headers;
|
||||
}
|
||||
get status() {
|
||||
return this[cacheKey]?.[0] ?? this[getResponseCache]().status;
|
||||
}
|
||||
get ok() {
|
||||
const status = this.status;
|
||||
return status >= 200 && status < 300;
|
||||
}
|
||||
};
|
||||
["body", "bodyUsed", "redirected", "statusText", "trailers", "type", "url"].forEach((k) => {
|
||||
Object.defineProperty(Response.prototype, k, {
|
||||
get() {
|
||||
return this[getResponseCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(Response.prototype, k, {
|
||||
value: function() {
|
||||
return this[getResponseCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(Response, GlobalResponse);
|
||||
Object.setPrototypeOf(Response.prototype, GlobalResponse.prototype);
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
GlobalResponse,
|
||||
Response,
|
||||
cacheKey
|
||||
});
|
||||
74
projects/stt-mcp/node_modules/@hono/node-server/dist/response.mjs
generated
vendored
Normal file
74
projects/stt-mcp/node_modules/@hono/node-server/dist/response.mjs
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
// src/response.ts
|
||||
var responseCache = Symbol("responseCache");
|
||||
var getResponseCache = Symbol("getResponseCache");
|
||||
var cacheKey = Symbol("cache");
|
||||
var GlobalResponse = global.Response;
|
||||
var Response = class _Response {
|
||||
#body;
|
||||
#init;
|
||||
[getResponseCache]() {
|
||||
delete this[cacheKey];
|
||||
return this[responseCache] ||= new GlobalResponse(this.#body, this.#init);
|
||||
}
|
||||
constructor(body, init) {
|
||||
let headers;
|
||||
this.#body = body;
|
||||
if (init instanceof _Response) {
|
||||
const cachedGlobalResponse = init[responseCache];
|
||||
if (cachedGlobalResponse) {
|
||||
this.#init = cachedGlobalResponse;
|
||||
this[getResponseCache]();
|
||||
return;
|
||||
} else {
|
||||
this.#init = init.#init;
|
||||
headers = new Headers(init.#init.headers);
|
||||
}
|
||||
} else {
|
||||
this.#init = init;
|
||||
}
|
||||
if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) {
|
||||
;
|
||||
this[cacheKey] = [init?.status || 200, body, headers || init?.headers];
|
||||
}
|
||||
}
|
||||
get headers() {
|
||||
const cache = this[cacheKey];
|
||||
if (cache) {
|
||||
if (!(cache[2] instanceof Headers)) {
|
||||
cache[2] = new Headers(
|
||||
cache[2] || { "content-type": "text/plain; charset=UTF-8" }
|
||||
);
|
||||
}
|
||||
return cache[2];
|
||||
}
|
||||
return this[getResponseCache]().headers;
|
||||
}
|
||||
get status() {
|
||||
return this[cacheKey]?.[0] ?? this[getResponseCache]().status;
|
||||
}
|
||||
get ok() {
|
||||
const status = this.status;
|
||||
return status >= 200 && status < 300;
|
||||
}
|
||||
};
|
||||
["body", "bodyUsed", "redirected", "statusText", "trailers", "type", "url"].forEach((k) => {
|
||||
Object.defineProperty(Response.prototype, k, {
|
||||
get() {
|
||||
return this[getResponseCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(Response.prototype, k, {
|
||||
value: function() {
|
||||
return this[getResponseCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(Response, GlobalResponse);
|
||||
Object.setPrototypeOf(Response.prototype, GlobalResponse.prototype);
|
||||
export {
|
||||
GlobalResponse,
|
||||
Response,
|
||||
cacheKey
|
||||
};
|
||||
17
projects/stt-mcp/node_modules/@hono/node-server/dist/serve-static.d.mts
generated
vendored
Normal file
17
projects/stt-mcp/node_modules/@hono/node-server/dist/serve-static.d.mts
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Env, Context, MiddlewareHandler } from 'hono';
|
||||
|
||||
type ServeStaticOptions<E extends Env = Env> = {
|
||||
/**
|
||||
* Root path, relative to current working directory from which the app was started. Absolute paths are not supported.
|
||||
*/
|
||||
root?: string;
|
||||
path?: string;
|
||||
index?: string;
|
||||
precompressed?: boolean;
|
||||
rewriteRequestPath?: (path: string, c: Context<E>) => string;
|
||||
onFound?: (path: string, c: Context<E>) => void | Promise<void>;
|
||||
onNotFound?: (path: string, c: Context<E>) => void | Promise<void>;
|
||||
};
|
||||
declare const serveStatic: <E extends Env = any>(options?: ServeStaticOptions<E>) => MiddlewareHandler<E>;
|
||||
|
||||
export { ServeStaticOptions, serveStatic };
|
||||
17
projects/stt-mcp/node_modules/@hono/node-server/dist/serve-static.d.ts
generated
vendored
Normal file
17
projects/stt-mcp/node_modules/@hono/node-server/dist/serve-static.d.ts
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Env, Context, MiddlewareHandler } from 'hono';
|
||||
|
||||
type ServeStaticOptions<E extends Env = Env> = {
|
||||
/**
|
||||
* Root path, relative to current working directory from which the app was started. Absolute paths are not supported.
|
||||
*/
|
||||
root?: string;
|
||||
path?: string;
|
||||
index?: string;
|
||||
precompressed?: boolean;
|
||||
rewriteRequestPath?: (path: string, c: Context<E>) => string;
|
||||
onFound?: (path: string, c: Context<E>) => void | Promise<void>;
|
||||
onNotFound?: (path: string, c: Context<E>) => void | Promise<void>;
|
||||
};
|
||||
declare const serveStatic: <E extends Env = any>(options?: ServeStaticOptions<E>) => MiddlewareHandler<E>;
|
||||
|
||||
export { ServeStaticOptions, serveStatic };
|
||||
177
projects/stt-mcp/node_modules/@hono/node-server/dist/serve-static.js
generated
vendored
Normal file
177
projects/stt-mcp/node_modules/@hono/node-server/dist/serve-static.js
generated
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/serve-static.ts
|
||||
var serve_static_exports = {};
|
||||
__export(serve_static_exports, {
|
||||
serveStatic: () => serveStatic
|
||||
});
|
||||
module.exports = __toCommonJS(serve_static_exports);
|
||||
var import_mime = require("hono/utils/mime");
|
||||
var import_node_fs = require("fs");
|
||||
var import_node_path = require("path");
|
||||
var import_node_process = require("process");
|
||||
var import_node_stream = require("stream");
|
||||
var COMPRESSIBLE_CONTENT_TYPE_REGEX = /^\s*(?:text\/[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-virtualbox-hdd|x-virtualbox-ova|x-virtualbox-ovf|x-virtualbox-vbox|x-virtualbox-vdi|x-virtualbox-vhd|x-virtualbox-vmdk|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i;
|
||||
var ENCODINGS = {
|
||||
br: ".br",
|
||||
zstd: ".zst",
|
||||
gzip: ".gz"
|
||||
};
|
||||
var ENCODINGS_ORDERED_KEYS = Object.keys(ENCODINGS);
|
||||
var pr54206Applied = () => {
|
||||
const [major, minor] = import_node_process.versions.node.split(".").map((component) => parseInt(component));
|
||||
return major >= 23 || major === 22 && minor >= 7 || major === 20 && minor >= 18;
|
||||
};
|
||||
var useReadableToWeb = pr54206Applied();
|
||||
var createStreamBody = (stream) => {
|
||||
if (useReadableToWeb) {
|
||||
return import_node_stream.Readable.toWeb(stream);
|
||||
}
|
||||
const body = new ReadableStream({
|
||||
start(controller) {
|
||||
stream.on("data", (chunk) => {
|
||||
controller.enqueue(chunk);
|
||||
});
|
||||
stream.on("error", (err) => {
|
||||
controller.error(err);
|
||||
});
|
||||
stream.on("end", () => {
|
||||
controller.close();
|
||||
});
|
||||
},
|
||||
cancel() {
|
||||
stream.destroy();
|
||||
}
|
||||
});
|
||||
return body;
|
||||
};
|
||||
var getStats = (path) => {
|
||||
let stats;
|
||||
try {
|
||||
stats = (0, import_node_fs.statSync)(path);
|
||||
} catch {
|
||||
}
|
||||
return stats;
|
||||
};
|
||||
var tryDecode = (str, decoder) => {
|
||||
try {
|
||||
return decoder(str);
|
||||
} catch {
|
||||
return str.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match) => {
|
||||
try {
|
||||
return decoder(match);
|
||||
} catch {
|
||||
return match;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
var tryDecodeURI = (str) => tryDecode(str, decodeURI);
|
||||
var serveStatic = (options = { root: "" }) => {
|
||||
const root = options.root || "";
|
||||
const optionPath = options.path;
|
||||
if (root !== "" && !(0, import_node_fs.existsSync)(root)) {
|
||||
console.error(`serveStatic: root path '${root}' is not found, are you sure it's correct?`);
|
||||
}
|
||||
return async (c, next) => {
|
||||
if (c.finalized) {
|
||||
return next();
|
||||
}
|
||||
let filename;
|
||||
if (optionPath) {
|
||||
filename = optionPath;
|
||||
} else {
|
||||
try {
|
||||
filename = tryDecodeURI(c.req.path);
|
||||
if (/(?:^|[\/\\])\.\.(?:$|[\/\\])/.test(filename)) {
|
||||
throw new Error();
|
||||
}
|
||||
} catch {
|
||||
await options.onNotFound?.(c.req.path, c);
|
||||
return next();
|
||||
}
|
||||
}
|
||||
let path = (0, import_node_path.join)(
|
||||
root,
|
||||
!optionPath && options.rewriteRequestPath ? options.rewriteRequestPath(filename, c) : filename
|
||||
);
|
||||
let stats = getStats(path);
|
||||
if (stats && stats.isDirectory()) {
|
||||
const indexFile = options.index ?? "index.html";
|
||||
path = (0, import_node_path.join)(path, indexFile);
|
||||
stats = getStats(path);
|
||||
}
|
||||
if (!stats) {
|
||||
await options.onNotFound?.(path, c);
|
||||
return next();
|
||||
}
|
||||
const mimeType = (0, import_mime.getMimeType)(path);
|
||||
c.header("Content-Type", mimeType || "application/octet-stream");
|
||||
if (options.precompressed && (!mimeType || COMPRESSIBLE_CONTENT_TYPE_REGEX.test(mimeType))) {
|
||||
const acceptEncodingSet = new Set(
|
||||
c.req.header("Accept-Encoding")?.split(",").map((encoding) => encoding.trim())
|
||||
);
|
||||
for (const encoding of ENCODINGS_ORDERED_KEYS) {
|
||||
if (!acceptEncodingSet.has(encoding)) {
|
||||
continue;
|
||||
}
|
||||
const precompressedStats = getStats(path + ENCODINGS[encoding]);
|
||||
if (precompressedStats) {
|
||||
c.header("Content-Encoding", encoding);
|
||||
c.header("Vary", "Accept-Encoding", { append: true });
|
||||
stats = precompressedStats;
|
||||
path = path + ENCODINGS[encoding];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let result;
|
||||
const size = stats.size;
|
||||
const range = c.req.header("range") || "";
|
||||
if (c.req.method == "HEAD" || c.req.method == "OPTIONS") {
|
||||
c.header("Content-Length", size.toString());
|
||||
c.status(200);
|
||||
result = c.body(null);
|
||||
} else if (!range) {
|
||||
c.header("Content-Length", size.toString());
|
||||
result = c.body(createStreamBody((0, import_node_fs.createReadStream)(path)), 200);
|
||||
} else {
|
||||
c.header("Accept-Ranges", "bytes");
|
||||
c.header("Date", stats.birthtime.toUTCString());
|
||||
const parts = range.replace(/bytes=/, "").split("-", 2);
|
||||
const start = parseInt(parts[0], 10) || 0;
|
||||
let end = parseInt(parts[1], 10) || size - 1;
|
||||
if (size < end - start + 1) {
|
||||
end = size - 1;
|
||||
}
|
||||
const chunksize = end - start + 1;
|
||||
const stream = (0, import_node_fs.createReadStream)(path, { start, end });
|
||||
c.header("Content-Length", chunksize.toString());
|
||||
c.header("Content-Range", `bytes ${start}-${end}/${stats.size}`);
|
||||
result = c.body(createStreamBody(stream), 206);
|
||||
}
|
||||
await options.onFound?.(path, c);
|
||||
return result;
|
||||
};
|
||||
};
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
serveStatic
|
||||
});
|
||||
152
projects/stt-mcp/node_modules/@hono/node-server/dist/serve-static.mjs
generated
vendored
Normal file
152
projects/stt-mcp/node_modules/@hono/node-server/dist/serve-static.mjs
generated
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
// src/serve-static.ts
|
||||
import { getMimeType } from "hono/utils/mime";
|
||||
import { createReadStream, statSync, existsSync } from "fs";
|
||||
import { join } from "path";
|
||||
import { versions } from "process";
|
||||
import { Readable } from "stream";
|
||||
var COMPRESSIBLE_CONTENT_TYPE_REGEX = /^\s*(?:text\/[^;\s]+|application\/(?:javascript|json|xml|xml-dtd|ecmascript|dart|postscript|rtf|tar|toml|vnd\.dart|vnd\.ms-fontobject|vnd\.ms-opentype|wasm|x-httpd-php|x-javascript|x-ns-proxy-autoconfig|x-sh|x-tar|x-virtualbox-hdd|x-virtualbox-ova|x-virtualbox-ovf|x-virtualbox-vbox|x-virtualbox-vdi|x-virtualbox-vhd|x-virtualbox-vmdk|x-www-form-urlencoded)|font\/(?:otf|ttf)|image\/(?:bmp|vnd\.adobe\.photoshop|vnd\.microsoft\.icon|vnd\.ms-dds|x-icon|x-ms-bmp)|message\/rfc822|model\/gltf-binary|x-shader\/x-fragment|x-shader\/x-vertex|[^;\s]+?\+(?:json|text|xml|yaml))(?:[;\s]|$)/i;
|
||||
var ENCODINGS = {
|
||||
br: ".br",
|
||||
zstd: ".zst",
|
||||
gzip: ".gz"
|
||||
};
|
||||
var ENCODINGS_ORDERED_KEYS = Object.keys(ENCODINGS);
|
||||
var pr54206Applied = () => {
|
||||
const [major, minor] = versions.node.split(".").map((component) => parseInt(component));
|
||||
return major >= 23 || major === 22 && minor >= 7 || major === 20 && minor >= 18;
|
||||
};
|
||||
var useReadableToWeb = pr54206Applied();
|
||||
var createStreamBody = (stream) => {
|
||||
if (useReadableToWeb) {
|
||||
return Readable.toWeb(stream);
|
||||
}
|
||||
const body = new ReadableStream({
|
||||
start(controller) {
|
||||
stream.on("data", (chunk) => {
|
||||
controller.enqueue(chunk);
|
||||
});
|
||||
stream.on("error", (err) => {
|
||||
controller.error(err);
|
||||
});
|
||||
stream.on("end", () => {
|
||||
controller.close();
|
||||
});
|
||||
},
|
||||
cancel() {
|
||||
stream.destroy();
|
||||
}
|
||||
});
|
||||
return body;
|
||||
};
|
||||
var getStats = (path) => {
|
||||
let stats;
|
||||
try {
|
||||
stats = statSync(path);
|
||||
} catch {
|
||||
}
|
||||
return stats;
|
||||
};
|
||||
var tryDecode = (str, decoder) => {
|
||||
try {
|
||||
return decoder(str);
|
||||
} catch {
|
||||
return str.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match) => {
|
||||
try {
|
||||
return decoder(match);
|
||||
} catch {
|
||||
return match;
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
var tryDecodeURI = (str) => tryDecode(str, decodeURI);
|
||||
var serveStatic = (options = { root: "" }) => {
|
||||
const root = options.root || "";
|
||||
const optionPath = options.path;
|
||||
if (root !== "" && !existsSync(root)) {
|
||||
console.error(`serveStatic: root path '${root}' is not found, are you sure it's correct?`);
|
||||
}
|
||||
return async (c, next) => {
|
||||
if (c.finalized) {
|
||||
return next();
|
||||
}
|
||||
let filename;
|
||||
if (optionPath) {
|
||||
filename = optionPath;
|
||||
} else {
|
||||
try {
|
||||
filename = tryDecodeURI(c.req.path);
|
||||
if (/(?:^|[\/\\])\.\.(?:$|[\/\\])/.test(filename)) {
|
||||
throw new Error();
|
||||
}
|
||||
} catch {
|
||||
await options.onNotFound?.(c.req.path, c);
|
||||
return next();
|
||||
}
|
||||
}
|
||||
let path = join(
|
||||
root,
|
||||
!optionPath && options.rewriteRequestPath ? options.rewriteRequestPath(filename, c) : filename
|
||||
);
|
||||
let stats = getStats(path);
|
||||
if (stats && stats.isDirectory()) {
|
||||
const indexFile = options.index ?? "index.html";
|
||||
path = join(path, indexFile);
|
||||
stats = getStats(path);
|
||||
}
|
||||
if (!stats) {
|
||||
await options.onNotFound?.(path, c);
|
||||
return next();
|
||||
}
|
||||
const mimeType = getMimeType(path);
|
||||
c.header("Content-Type", mimeType || "application/octet-stream");
|
||||
if (options.precompressed && (!mimeType || COMPRESSIBLE_CONTENT_TYPE_REGEX.test(mimeType))) {
|
||||
const acceptEncodingSet = new Set(
|
||||
c.req.header("Accept-Encoding")?.split(",").map((encoding) => encoding.trim())
|
||||
);
|
||||
for (const encoding of ENCODINGS_ORDERED_KEYS) {
|
||||
if (!acceptEncodingSet.has(encoding)) {
|
||||
continue;
|
||||
}
|
||||
const precompressedStats = getStats(path + ENCODINGS[encoding]);
|
||||
if (precompressedStats) {
|
||||
c.header("Content-Encoding", encoding);
|
||||
c.header("Vary", "Accept-Encoding", { append: true });
|
||||
stats = precompressedStats;
|
||||
path = path + ENCODINGS[encoding];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let result;
|
||||
const size = stats.size;
|
||||
const range = c.req.header("range") || "";
|
||||
if (c.req.method == "HEAD" || c.req.method == "OPTIONS") {
|
||||
c.header("Content-Length", size.toString());
|
||||
c.status(200);
|
||||
result = c.body(null);
|
||||
} else if (!range) {
|
||||
c.header("Content-Length", size.toString());
|
||||
result = c.body(createStreamBody(createReadStream(path)), 200);
|
||||
} else {
|
||||
c.header("Accept-Ranges", "bytes");
|
||||
c.header("Date", stats.birthtime.toUTCString());
|
||||
const parts = range.replace(/bytes=/, "").split("-", 2);
|
||||
const start = parseInt(parts[0], 10) || 0;
|
||||
let end = parseInt(parts[1], 10) || size - 1;
|
||||
if (size < end - start + 1) {
|
||||
end = size - 1;
|
||||
}
|
||||
const chunksize = end - start + 1;
|
||||
const stream = createReadStream(path, { start, end });
|
||||
c.header("Content-Length", chunksize.toString());
|
||||
c.header("Content-Range", `bytes ${start}-${end}/${stats.size}`);
|
||||
result = c.body(createStreamBody(stream), 206);
|
||||
}
|
||||
await options.onFound?.(path, c);
|
||||
return result;
|
||||
};
|
||||
};
|
||||
export {
|
||||
serveStatic
|
||||
};
|
||||
10
projects/stt-mcp/node_modules/@hono/node-server/dist/server.d.mts
generated
vendored
Normal file
10
projects/stt-mcp/node_modules/@hono/node-server/dist/server.d.mts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import { AddressInfo } from 'node:net';
|
||||
import { Options, ServerType } from './types.mjs';
|
||||
import 'node:http';
|
||||
import 'node:http2';
|
||||
import 'node:https';
|
||||
|
||||
declare const createAdaptorServer: (options: Options) => ServerType;
|
||||
declare const serve: (options: Options, listeningListener?: (info: AddressInfo) => void) => ServerType;
|
||||
|
||||
export { createAdaptorServer, serve };
|
||||
10
projects/stt-mcp/node_modules/@hono/node-server/dist/server.d.ts
generated
vendored
Normal file
10
projects/stt-mcp/node_modules/@hono/node-server/dist/server.d.ts
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import { AddressInfo } from 'node:net';
|
||||
import { Options, ServerType } from './types.js';
|
||||
import 'node:http';
|
||||
import 'node:http2';
|
||||
import 'node:https';
|
||||
|
||||
declare const createAdaptorServer: (options: Options) => ServerType;
|
||||
declare const serve: (options: Options, listeningListener?: (info: AddressInfo) => void) => ServerType;
|
||||
|
||||
export { createAdaptorServer, serve };
|
||||
626
projects/stt-mcp/node_modules/@hono/node-server/dist/server.js
generated
vendored
Normal file
626
projects/stt-mcp/node_modules/@hono/node-server/dist/server.js
generated
vendored
Normal file
@@ -0,0 +1,626 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/server.ts
|
||||
var server_exports = {};
|
||||
__export(server_exports, {
|
||||
createAdaptorServer: () => createAdaptorServer,
|
||||
serve: () => serve
|
||||
});
|
||||
module.exports = __toCommonJS(server_exports);
|
||||
var import_node_http = require("http");
|
||||
|
||||
// src/listener.ts
|
||||
var import_node_http22 = require("http2");
|
||||
|
||||
// src/request.ts
|
||||
var import_node_http2 = require("http2");
|
||||
var import_node_stream = require("stream");
|
||||
var RequestError = class extends Error {
|
||||
constructor(message, options) {
|
||||
super(message, options);
|
||||
this.name = "RequestError";
|
||||
}
|
||||
};
|
||||
var toRequestError = (e) => {
|
||||
if (e instanceof RequestError) {
|
||||
return e;
|
||||
}
|
||||
return new RequestError(e.message, { cause: e });
|
||||
};
|
||||
var GlobalRequest = global.Request;
|
||||
var Request = class extends GlobalRequest {
|
||||
constructor(input, options) {
|
||||
if (typeof input === "object" && getRequestCache in input) {
|
||||
input = input[getRequestCache]();
|
||||
}
|
||||
if (typeof options?.body?.getReader !== "undefined") {
|
||||
;
|
||||
options.duplex ??= "half";
|
||||
}
|
||||
super(input, options);
|
||||
}
|
||||
};
|
||||
var newHeadersFromIncoming = (incoming) => {
|
||||
const headerRecord = [];
|
||||
const rawHeaders = incoming.rawHeaders;
|
||||
for (let i = 0; i < rawHeaders.length; i += 2) {
|
||||
const { [i]: key, [i + 1]: value } = rawHeaders;
|
||||
if (key.charCodeAt(0) !== /*:*/
|
||||
58) {
|
||||
headerRecord.push([key, value]);
|
||||
}
|
||||
}
|
||||
return new Headers(headerRecord);
|
||||
};
|
||||
var wrapBodyStream = Symbol("wrapBodyStream");
|
||||
var newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
|
||||
const init = {
|
||||
method,
|
||||
headers,
|
||||
signal: abortController.signal
|
||||
};
|
||||
if (method === "TRACE") {
|
||||
init.method = "GET";
|
||||
const req = new Request(url, init);
|
||||
Object.defineProperty(req, "method", {
|
||||
get() {
|
||||
return "TRACE";
|
||||
}
|
||||
});
|
||||
return req;
|
||||
}
|
||||
if (!(method === "GET" || method === "HEAD")) {
|
||||
if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) {
|
||||
init.body = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(incoming.rawBody);
|
||||
controller.close();
|
||||
}
|
||||
});
|
||||
} else if (incoming[wrapBodyStream]) {
|
||||
let reader;
|
||||
init.body = new ReadableStream({
|
||||
async pull(controller) {
|
||||
try {
|
||||
reader ||= import_node_stream.Readable.toWeb(incoming).getReader();
|
||||
const { done, value } = await reader.read();
|
||||
if (done) {
|
||||
controller.close();
|
||||
} else {
|
||||
controller.enqueue(value);
|
||||
}
|
||||
} catch (error) {
|
||||
controller.error(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
init.body = import_node_stream.Readable.toWeb(incoming);
|
||||
}
|
||||
}
|
||||
return new Request(url, init);
|
||||
};
|
||||
var getRequestCache = Symbol("getRequestCache");
|
||||
var requestCache = Symbol("requestCache");
|
||||
var incomingKey = Symbol("incomingKey");
|
||||
var urlKey = Symbol("urlKey");
|
||||
var headersKey = Symbol("headersKey");
|
||||
var abortControllerKey = Symbol("abortControllerKey");
|
||||
var getAbortController = Symbol("getAbortController");
|
||||
var requestPrototype = {
|
||||
get method() {
|
||||
return this[incomingKey].method || "GET";
|
||||
},
|
||||
get url() {
|
||||
return this[urlKey];
|
||||
},
|
||||
get headers() {
|
||||
return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
|
||||
},
|
||||
[getAbortController]() {
|
||||
this[getRequestCache]();
|
||||
return this[abortControllerKey];
|
||||
},
|
||||
[getRequestCache]() {
|
||||
this[abortControllerKey] ||= new AbortController();
|
||||
return this[requestCache] ||= newRequestFromIncoming(
|
||||
this.method,
|
||||
this[urlKey],
|
||||
this.headers,
|
||||
this[incomingKey],
|
||||
this[abortControllerKey]
|
||||
);
|
||||
}
|
||||
};
|
||||
[
|
||||
"body",
|
||||
"bodyUsed",
|
||||
"cache",
|
||||
"credentials",
|
||||
"destination",
|
||||
"integrity",
|
||||
"mode",
|
||||
"redirect",
|
||||
"referrer",
|
||||
"referrerPolicy",
|
||||
"signal",
|
||||
"keepalive"
|
||||
].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
get() {
|
||||
return this[getRequestCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
value: function() {
|
||||
return this[getRequestCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(requestPrototype, Request.prototype);
|
||||
var newRequest = (incoming, defaultHostname) => {
|
||||
const req = Object.create(requestPrototype);
|
||||
req[incomingKey] = incoming;
|
||||
const incomingUrl = incoming.url || "";
|
||||
if (incomingUrl[0] !== "/" && // short-circuit for performance. most requests are relative URL.
|
||||
(incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) {
|
||||
if (incoming instanceof import_node_http2.Http2ServerRequest) {
|
||||
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
||||
}
|
||||
try {
|
||||
const url2 = new URL(incomingUrl);
|
||||
req[urlKey] = url2.href;
|
||||
} catch (e) {
|
||||
throw new RequestError("Invalid absolute URL", { cause: e });
|
||||
}
|
||||
return req;
|
||||
}
|
||||
const host = (incoming instanceof import_node_http2.Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;
|
||||
if (!host) {
|
||||
throw new RequestError("Missing host header");
|
||||
}
|
||||
let scheme;
|
||||
if (incoming instanceof import_node_http2.Http2ServerRequest) {
|
||||
scheme = incoming.scheme;
|
||||
if (!(scheme === "http" || scheme === "https")) {
|
||||
throw new RequestError("Unsupported scheme");
|
||||
}
|
||||
} else {
|
||||
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
||||
}
|
||||
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
||||
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
||||
throw new RequestError("Invalid host header");
|
||||
}
|
||||
req[urlKey] = url.href;
|
||||
return req;
|
||||
};
|
||||
|
||||
// src/response.ts
|
||||
var responseCache = Symbol("responseCache");
|
||||
var getResponseCache = Symbol("getResponseCache");
|
||||
var cacheKey = Symbol("cache");
|
||||
var GlobalResponse = global.Response;
|
||||
var Response2 = class _Response {
|
||||
#body;
|
||||
#init;
|
||||
[getResponseCache]() {
|
||||
delete this[cacheKey];
|
||||
return this[responseCache] ||= new GlobalResponse(this.#body, this.#init);
|
||||
}
|
||||
constructor(body, init) {
|
||||
let headers;
|
||||
this.#body = body;
|
||||
if (init instanceof _Response) {
|
||||
const cachedGlobalResponse = init[responseCache];
|
||||
if (cachedGlobalResponse) {
|
||||
this.#init = cachedGlobalResponse;
|
||||
this[getResponseCache]();
|
||||
return;
|
||||
} else {
|
||||
this.#init = init.#init;
|
||||
headers = new Headers(init.#init.headers);
|
||||
}
|
||||
} else {
|
||||
this.#init = init;
|
||||
}
|
||||
if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) {
|
||||
;
|
||||
this[cacheKey] = [init?.status || 200, body, headers || init?.headers];
|
||||
}
|
||||
}
|
||||
get headers() {
|
||||
const cache = this[cacheKey];
|
||||
if (cache) {
|
||||
if (!(cache[2] instanceof Headers)) {
|
||||
cache[2] = new Headers(
|
||||
cache[2] || { "content-type": "text/plain; charset=UTF-8" }
|
||||
);
|
||||
}
|
||||
return cache[2];
|
||||
}
|
||||
return this[getResponseCache]().headers;
|
||||
}
|
||||
get status() {
|
||||
return this[cacheKey]?.[0] ?? this[getResponseCache]().status;
|
||||
}
|
||||
get ok() {
|
||||
const status = this.status;
|
||||
return status >= 200 && status < 300;
|
||||
}
|
||||
};
|
||||
["body", "bodyUsed", "redirected", "statusText", "trailers", "type", "url"].forEach((k) => {
|
||||
Object.defineProperty(Response2.prototype, k, {
|
||||
get() {
|
||||
return this[getResponseCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(Response2.prototype, k, {
|
||||
value: function() {
|
||||
return this[getResponseCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(Response2, GlobalResponse);
|
||||
Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);
|
||||
|
||||
// src/utils.ts
|
||||
async function readWithoutBlocking(readPromise) {
|
||||
return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
|
||||
}
|
||||
function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
|
||||
const cancel = (error) => {
|
||||
reader.cancel(error).catch(() => {
|
||||
});
|
||||
};
|
||||
writable.on("close", cancel);
|
||||
writable.on("error", cancel);
|
||||
(currentReadPromise ?? reader.read()).then(flow, handleStreamError);
|
||||
return reader.closed.finally(() => {
|
||||
writable.off("close", cancel);
|
||||
writable.off("error", cancel);
|
||||
});
|
||||
function handleStreamError(error) {
|
||||
if (error) {
|
||||
writable.destroy(error);
|
||||
}
|
||||
}
|
||||
function onDrain() {
|
||||
reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
function flow({ done, value }) {
|
||||
try {
|
||||
if (done) {
|
||||
writable.end();
|
||||
} else if (!writable.write(value)) {
|
||||
writable.once("drain", onDrain);
|
||||
} else {
|
||||
return reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
} catch (e) {
|
||||
handleStreamError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
function writeFromReadableStream(stream, writable) {
|
||||
if (stream.locked) {
|
||||
throw new TypeError("ReadableStream is locked.");
|
||||
} else if (writable.destroyed) {
|
||||
return;
|
||||
}
|
||||
return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
|
||||
}
|
||||
var buildOutgoingHttpHeaders = (headers) => {
|
||||
const res = {};
|
||||
if (!(headers instanceof Headers)) {
|
||||
headers = new Headers(headers ?? void 0);
|
||||
}
|
||||
const cookies = [];
|
||||
for (const [k, v] of headers) {
|
||||
if (k === "set-cookie") {
|
||||
cookies.push(v);
|
||||
} else {
|
||||
res[k] = v;
|
||||
}
|
||||
}
|
||||
if (cookies.length > 0) {
|
||||
res["set-cookie"] = cookies;
|
||||
}
|
||||
res["content-type"] ??= "text/plain; charset=UTF-8";
|
||||
return res;
|
||||
};
|
||||
|
||||
// src/utils/response/constants.ts
|
||||
var X_ALREADY_SENT = "x-hono-already-sent";
|
||||
|
||||
// src/globals.ts
|
||||
var import_node_crypto = __toESM(require("crypto"));
|
||||
if (typeof global.crypto === "undefined") {
|
||||
global.crypto = import_node_crypto.default;
|
||||
}
|
||||
|
||||
// src/listener.ts
|
||||
var outgoingEnded = Symbol("outgoingEnded");
|
||||
var handleRequestError = () => new Response(null, {
|
||||
status: 400
|
||||
});
|
||||
var handleFetchError = (e) => new Response(null, {
|
||||
status: e instanceof Error && (e.name === "TimeoutError" || e.constructor.name === "TimeoutError") ? 504 : 500
|
||||
});
|
||||
var handleResponseError = (e, outgoing) => {
|
||||
const err = e instanceof Error ? e : new Error("unknown error", { cause: e });
|
||||
if (err.code === "ERR_STREAM_PREMATURE_CLOSE") {
|
||||
console.info("The user aborted a request.");
|
||||
} else {
|
||||
console.error(e);
|
||||
if (!outgoing.headersSent) {
|
||||
outgoing.writeHead(500, { "Content-Type": "text/plain" });
|
||||
}
|
||||
outgoing.end(`Error: ${err.message}`);
|
||||
outgoing.destroy(err);
|
||||
}
|
||||
};
|
||||
var flushHeaders = (outgoing) => {
|
||||
if ("flushHeaders" in outgoing && outgoing.writable) {
|
||||
outgoing.flushHeaders();
|
||||
}
|
||||
};
|
||||
var responseViaCache = async (res, outgoing) => {
|
||||
let [status, body, header] = res[cacheKey];
|
||||
let hasContentLength = false;
|
||||
if (!header) {
|
||||
header = { "content-type": "text/plain; charset=UTF-8" };
|
||||
} else if (header instanceof Headers) {
|
||||
hasContentLength = header.has("content-length");
|
||||
header = buildOutgoingHttpHeaders(header);
|
||||
} else if (Array.isArray(header)) {
|
||||
const headerObj = new Headers(header);
|
||||
hasContentLength = headerObj.has("content-length");
|
||||
header = buildOutgoingHttpHeaders(headerObj);
|
||||
} else {
|
||||
for (const key in header) {
|
||||
if (key.length === 14 && key.toLowerCase() === "content-length") {
|
||||
hasContentLength = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasContentLength) {
|
||||
if (typeof body === "string") {
|
||||
header["Content-Length"] = Buffer.byteLength(body);
|
||||
} else if (body instanceof Uint8Array) {
|
||||
header["Content-Length"] = body.byteLength;
|
||||
} else if (body instanceof Blob) {
|
||||
header["Content-Length"] = body.size;
|
||||
}
|
||||
}
|
||||
outgoing.writeHead(status, header);
|
||||
if (typeof body === "string" || body instanceof Uint8Array) {
|
||||
outgoing.end(body);
|
||||
} else if (body instanceof Blob) {
|
||||
outgoing.end(new Uint8Array(await body.arrayBuffer()));
|
||||
} else {
|
||||
flushHeaders(outgoing);
|
||||
await writeFromReadableStream(body, outgoing)?.catch(
|
||||
(e) => handleResponseError(e, outgoing)
|
||||
);
|
||||
}
|
||||
;
|
||||
outgoing[outgoingEnded]?.();
|
||||
};
|
||||
var isPromise = (res) => typeof res.then === "function";
|
||||
var responseViaResponseObject = async (res, outgoing, options = {}) => {
|
||||
if (isPromise(res)) {
|
||||
if (options.errorHandler) {
|
||||
try {
|
||||
res = await res;
|
||||
} catch (err) {
|
||||
const errRes = await options.errorHandler(err);
|
||||
if (!errRes) {
|
||||
return;
|
||||
}
|
||||
res = errRes;
|
||||
}
|
||||
} else {
|
||||
res = await res.catch(handleFetchError);
|
||||
}
|
||||
}
|
||||
if (cacheKey in res) {
|
||||
return responseViaCache(res, outgoing);
|
||||
}
|
||||
const resHeaderRecord = buildOutgoingHttpHeaders(res.headers);
|
||||
if (res.body) {
|
||||
const reader = res.body.getReader();
|
||||
const values = [];
|
||||
let done = false;
|
||||
let currentReadPromise = void 0;
|
||||
if (resHeaderRecord["transfer-encoding"] !== "chunked") {
|
||||
let maxReadCount = 2;
|
||||
for (let i = 0; i < maxReadCount; i++) {
|
||||
currentReadPromise ||= reader.read();
|
||||
const chunk = await readWithoutBlocking(currentReadPromise).catch((e) => {
|
||||
console.error(e);
|
||||
done = true;
|
||||
});
|
||||
if (!chunk) {
|
||||
if (i === 1) {
|
||||
await new Promise((resolve) => setTimeout(resolve));
|
||||
maxReadCount = 3;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
currentReadPromise = void 0;
|
||||
if (chunk.value) {
|
||||
values.push(chunk.value);
|
||||
}
|
||||
if (chunk.done) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (done && !("content-length" in resHeaderRecord)) {
|
||||
resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0);
|
||||
}
|
||||
}
|
||||
outgoing.writeHead(res.status, resHeaderRecord);
|
||||
values.forEach((value) => {
|
||||
;
|
||||
outgoing.write(value);
|
||||
});
|
||||
if (done) {
|
||||
outgoing.end();
|
||||
} else {
|
||||
if (values.length === 0) {
|
||||
flushHeaders(outgoing);
|
||||
}
|
||||
await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);
|
||||
}
|
||||
} else if (resHeaderRecord[X_ALREADY_SENT]) {
|
||||
} else {
|
||||
outgoing.writeHead(res.status, resHeaderRecord);
|
||||
outgoing.end();
|
||||
}
|
||||
;
|
||||
outgoing[outgoingEnded]?.();
|
||||
};
|
||||
var getRequestListener = (fetchCallback, options = {}) => {
|
||||
const autoCleanupIncoming = options.autoCleanupIncoming ?? true;
|
||||
if (options.overrideGlobalObjects !== false && global.Request !== Request) {
|
||||
Object.defineProperty(global, "Request", {
|
||||
value: Request
|
||||
});
|
||||
Object.defineProperty(global, "Response", {
|
||||
value: Response2
|
||||
});
|
||||
}
|
||||
return async (incoming, outgoing) => {
|
||||
let res, req;
|
||||
try {
|
||||
req = newRequest(incoming, options.hostname);
|
||||
let incomingEnded = !autoCleanupIncoming || incoming.method === "GET" || incoming.method === "HEAD";
|
||||
if (!incomingEnded) {
|
||||
;
|
||||
incoming[wrapBodyStream] = true;
|
||||
incoming.on("end", () => {
|
||||
incomingEnded = true;
|
||||
});
|
||||
if (incoming instanceof import_node_http22.Http2ServerRequest) {
|
||||
;
|
||||
outgoing[outgoingEnded] = () => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
incoming.destroy();
|
||||
outgoing.destroy();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
outgoing.on("close", () => {
|
||||
const abortController = req[abortControllerKey];
|
||||
if (abortController) {
|
||||
if (incoming.errored) {
|
||||
req[abortControllerKey].abort(incoming.errored.toString());
|
||||
} else if (!outgoing.writableFinished) {
|
||||
req[abortControllerKey].abort("Client connection prematurely closed.");
|
||||
}
|
||||
}
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
incoming.destroy();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
res = fetchCallback(req, { incoming, outgoing });
|
||||
if (cacheKey in res) {
|
||||
return responseViaCache(res, outgoing);
|
||||
}
|
||||
} catch (e) {
|
||||
if (!res) {
|
||||
if (options.errorHandler) {
|
||||
res = await options.errorHandler(req ? e : toRequestError(e));
|
||||
if (!res) {
|
||||
return;
|
||||
}
|
||||
} else if (!req) {
|
||||
res = handleRequestError();
|
||||
} else {
|
||||
res = handleFetchError(e);
|
||||
}
|
||||
} else {
|
||||
return handleResponseError(e, outgoing);
|
||||
}
|
||||
}
|
||||
try {
|
||||
return await responseViaResponseObject(res, outgoing, options);
|
||||
} catch (e) {
|
||||
return handleResponseError(e, outgoing);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// src/server.ts
|
||||
var createAdaptorServer = (options) => {
|
||||
const fetchCallback = options.fetch;
|
||||
const requestListener = getRequestListener(fetchCallback, {
|
||||
hostname: options.hostname,
|
||||
overrideGlobalObjects: options.overrideGlobalObjects,
|
||||
autoCleanupIncoming: options.autoCleanupIncoming
|
||||
});
|
||||
const createServer = options.createServer || import_node_http.createServer;
|
||||
const server = createServer(options.serverOptions || {}, requestListener);
|
||||
return server;
|
||||
};
|
||||
var serve = (options, listeningListener) => {
|
||||
const server = createAdaptorServer(options);
|
||||
server.listen(options?.port ?? 3e3, options.hostname, () => {
|
||||
const serverInfo = server.address();
|
||||
listeningListener && listeningListener(serverInfo);
|
||||
});
|
||||
return server;
|
||||
};
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
createAdaptorServer,
|
||||
serve
|
||||
});
|
||||
590
projects/stt-mcp/node_modules/@hono/node-server/dist/server.mjs
generated
vendored
Normal file
590
projects/stt-mcp/node_modules/@hono/node-server/dist/server.mjs
generated
vendored
Normal file
@@ -0,0 +1,590 @@
|
||||
// src/server.ts
|
||||
import { createServer as createServerHTTP } from "http";
|
||||
|
||||
// src/listener.ts
|
||||
import { Http2ServerRequest as Http2ServerRequest2 } from "http2";
|
||||
|
||||
// src/request.ts
|
||||
import { Http2ServerRequest } from "http2";
|
||||
import { Readable } from "stream";
|
||||
var RequestError = class extends Error {
|
||||
constructor(message, options) {
|
||||
super(message, options);
|
||||
this.name = "RequestError";
|
||||
}
|
||||
};
|
||||
var toRequestError = (e) => {
|
||||
if (e instanceof RequestError) {
|
||||
return e;
|
||||
}
|
||||
return new RequestError(e.message, { cause: e });
|
||||
};
|
||||
var GlobalRequest = global.Request;
|
||||
var Request = class extends GlobalRequest {
|
||||
constructor(input, options) {
|
||||
if (typeof input === "object" && getRequestCache in input) {
|
||||
input = input[getRequestCache]();
|
||||
}
|
||||
if (typeof options?.body?.getReader !== "undefined") {
|
||||
;
|
||||
options.duplex ??= "half";
|
||||
}
|
||||
super(input, options);
|
||||
}
|
||||
};
|
||||
var newHeadersFromIncoming = (incoming) => {
|
||||
const headerRecord = [];
|
||||
const rawHeaders = incoming.rawHeaders;
|
||||
for (let i = 0; i < rawHeaders.length; i += 2) {
|
||||
const { [i]: key, [i + 1]: value } = rawHeaders;
|
||||
if (key.charCodeAt(0) !== /*:*/
|
||||
58) {
|
||||
headerRecord.push([key, value]);
|
||||
}
|
||||
}
|
||||
return new Headers(headerRecord);
|
||||
};
|
||||
var wrapBodyStream = Symbol("wrapBodyStream");
|
||||
var newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
|
||||
const init = {
|
||||
method,
|
||||
headers,
|
||||
signal: abortController.signal
|
||||
};
|
||||
if (method === "TRACE") {
|
||||
init.method = "GET";
|
||||
const req = new Request(url, init);
|
||||
Object.defineProperty(req, "method", {
|
||||
get() {
|
||||
return "TRACE";
|
||||
}
|
||||
});
|
||||
return req;
|
||||
}
|
||||
if (!(method === "GET" || method === "HEAD")) {
|
||||
if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) {
|
||||
init.body = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(incoming.rawBody);
|
||||
controller.close();
|
||||
}
|
||||
});
|
||||
} else if (incoming[wrapBodyStream]) {
|
||||
let reader;
|
||||
init.body = new ReadableStream({
|
||||
async pull(controller) {
|
||||
try {
|
||||
reader ||= Readable.toWeb(incoming).getReader();
|
||||
const { done, value } = await reader.read();
|
||||
if (done) {
|
||||
controller.close();
|
||||
} else {
|
||||
controller.enqueue(value);
|
||||
}
|
||||
} catch (error) {
|
||||
controller.error(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
init.body = Readable.toWeb(incoming);
|
||||
}
|
||||
}
|
||||
return new Request(url, init);
|
||||
};
|
||||
var getRequestCache = Symbol("getRequestCache");
|
||||
var requestCache = Symbol("requestCache");
|
||||
var incomingKey = Symbol("incomingKey");
|
||||
var urlKey = Symbol("urlKey");
|
||||
var headersKey = Symbol("headersKey");
|
||||
var abortControllerKey = Symbol("abortControllerKey");
|
||||
var getAbortController = Symbol("getAbortController");
|
||||
var requestPrototype = {
|
||||
get method() {
|
||||
return this[incomingKey].method || "GET";
|
||||
},
|
||||
get url() {
|
||||
return this[urlKey];
|
||||
},
|
||||
get headers() {
|
||||
return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
|
||||
},
|
||||
[getAbortController]() {
|
||||
this[getRequestCache]();
|
||||
return this[abortControllerKey];
|
||||
},
|
||||
[getRequestCache]() {
|
||||
this[abortControllerKey] ||= new AbortController();
|
||||
return this[requestCache] ||= newRequestFromIncoming(
|
||||
this.method,
|
||||
this[urlKey],
|
||||
this.headers,
|
||||
this[incomingKey],
|
||||
this[abortControllerKey]
|
||||
);
|
||||
}
|
||||
};
|
||||
[
|
||||
"body",
|
||||
"bodyUsed",
|
||||
"cache",
|
||||
"credentials",
|
||||
"destination",
|
||||
"integrity",
|
||||
"mode",
|
||||
"redirect",
|
||||
"referrer",
|
||||
"referrerPolicy",
|
||||
"signal",
|
||||
"keepalive"
|
||||
].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
get() {
|
||||
return this[getRequestCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
value: function() {
|
||||
return this[getRequestCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(requestPrototype, Request.prototype);
|
||||
var newRequest = (incoming, defaultHostname) => {
|
||||
const req = Object.create(requestPrototype);
|
||||
req[incomingKey] = incoming;
|
||||
const incomingUrl = incoming.url || "";
|
||||
if (incomingUrl[0] !== "/" && // short-circuit for performance. most requests are relative URL.
|
||||
(incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) {
|
||||
if (incoming instanceof Http2ServerRequest) {
|
||||
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
||||
}
|
||||
try {
|
||||
const url2 = new URL(incomingUrl);
|
||||
req[urlKey] = url2.href;
|
||||
} catch (e) {
|
||||
throw new RequestError("Invalid absolute URL", { cause: e });
|
||||
}
|
||||
return req;
|
||||
}
|
||||
const host = (incoming instanceof Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;
|
||||
if (!host) {
|
||||
throw new RequestError("Missing host header");
|
||||
}
|
||||
let scheme;
|
||||
if (incoming instanceof Http2ServerRequest) {
|
||||
scheme = incoming.scheme;
|
||||
if (!(scheme === "http" || scheme === "https")) {
|
||||
throw new RequestError("Unsupported scheme");
|
||||
}
|
||||
} else {
|
||||
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
||||
}
|
||||
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
||||
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
||||
throw new RequestError("Invalid host header");
|
||||
}
|
||||
req[urlKey] = url.href;
|
||||
return req;
|
||||
};
|
||||
|
||||
// src/response.ts
|
||||
var responseCache = Symbol("responseCache");
|
||||
var getResponseCache = Symbol("getResponseCache");
|
||||
var cacheKey = Symbol("cache");
|
||||
var GlobalResponse = global.Response;
|
||||
var Response2 = class _Response {
|
||||
#body;
|
||||
#init;
|
||||
[getResponseCache]() {
|
||||
delete this[cacheKey];
|
||||
return this[responseCache] ||= new GlobalResponse(this.#body, this.#init);
|
||||
}
|
||||
constructor(body, init) {
|
||||
let headers;
|
||||
this.#body = body;
|
||||
if (init instanceof _Response) {
|
||||
const cachedGlobalResponse = init[responseCache];
|
||||
if (cachedGlobalResponse) {
|
||||
this.#init = cachedGlobalResponse;
|
||||
this[getResponseCache]();
|
||||
return;
|
||||
} else {
|
||||
this.#init = init.#init;
|
||||
headers = new Headers(init.#init.headers);
|
||||
}
|
||||
} else {
|
||||
this.#init = init;
|
||||
}
|
||||
if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) {
|
||||
;
|
||||
this[cacheKey] = [init?.status || 200, body, headers || init?.headers];
|
||||
}
|
||||
}
|
||||
get headers() {
|
||||
const cache = this[cacheKey];
|
||||
if (cache) {
|
||||
if (!(cache[2] instanceof Headers)) {
|
||||
cache[2] = new Headers(
|
||||
cache[2] || { "content-type": "text/plain; charset=UTF-8" }
|
||||
);
|
||||
}
|
||||
return cache[2];
|
||||
}
|
||||
return this[getResponseCache]().headers;
|
||||
}
|
||||
get status() {
|
||||
return this[cacheKey]?.[0] ?? this[getResponseCache]().status;
|
||||
}
|
||||
get ok() {
|
||||
const status = this.status;
|
||||
return status >= 200 && status < 300;
|
||||
}
|
||||
};
|
||||
["body", "bodyUsed", "redirected", "statusText", "trailers", "type", "url"].forEach((k) => {
|
||||
Object.defineProperty(Response2.prototype, k, {
|
||||
get() {
|
||||
return this[getResponseCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(Response2.prototype, k, {
|
||||
value: function() {
|
||||
return this[getResponseCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(Response2, GlobalResponse);
|
||||
Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);
|
||||
|
||||
// src/utils.ts
|
||||
async function readWithoutBlocking(readPromise) {
|
||||
return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
|
||||
}
|
||||
function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
|
||||
const cancel = (error) => {
|
||||
reader.cancel(error).catch(() => {
|
||||
});
|
||||
};
|
||||
writable.on("close", cancel);
|
||||
writable.on("error", cancel);
|
||||
(currentReadPromise ?? reader.read()).then(flow, handleStreamError);
|
||||
return reader.closed.finally(() => {
|
||||
writable.off("close", cancel);
|
||||
writable.off("error", cancel);
|
||||
});
|
||||
function handleStreamError(error) {
|
||||
if (error) {
|
||||
writable.destroy(error);
|
||||
}
|
||||
}
|
||||
function onDrain() {
|
||||
reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
function flow({ done, value }) {
|
||||
try {
|
||||
if (done) {
|
||||
writable.end();
|
||||
} else if (!writable.write(value)) {
|
||||
writable.once("drain", onDrain);
|
||||
} else {
|
||||
return reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
} catch (e) {
|
||||
handleStreamError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
function writeFromReadableStream(stream, writable) {
|
||||
if (stream.locked) {
|
||||
throw new TypeError("ReadableStream is locked.");
|
||||
} else if (writable.destroyed) {
|
||||
return;
|
||||
}
|
||||
return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
|
||||
}
|
||||
var buildOutgoingHttpHeaders = (headers) => {
|
||||
const res = {};
|
||||
if (!(headers instanceof Headers)) {
|
||||
headers = new Headers(headers ?? void 0);
|
||||
}
|
||||
const cookies = [];
|
||||
for (const [k, v] of headers) {
|
||||
if (k === "set-cookie") {
|
||||
cookies.push(v);
|
||||
} else {
|
||||
res[k] = v;
|
||||
}
|
||||
}
|
||||
if (cookies.length > 0) {
|
||||
res["set-cookie"] = cookies;
|
||||
}
|
||||
res["content-type"] ??= "text/plain; charset=UTF-8";
|
||||
return res;
|
||||
};
|
||||
|
||||
// src/utils/response/constants.ts
|
||||
var X_ALREADY_SENT = "x-hono-already-sent";
|
||||
|
||||
// src/globals.ts
|
||||
import crypto from "crypto";
|
||||
if (typeof global.crypto === "undefined") {
|
||||
global.crypto = crypto;
|
||||
}
|
||||
|
||||
// src/listener.ts
|
||||
var outgoingEnded = Symbol("outgoingEnded");
|
||||
var handleRequestError = () => new Response(null, {
|
||||
status: 400
|
||||
});
|
||||
var handleFetchError = (e) => new Response(null, {
|
||||
status: e instanceof Error && (e.name === "TimeoutError" || e.constructor.name === "TimeoutError") ? 504 : 500
|
||||
});
|
||||
var handleResponseError = (e, outgoing) => {
|
||||
const err = e instanceof Error ? e : new Error("unknown error", { cause: e });
|
||||
if (err.code === "ERR_STREAM_PREMATURE_CLOSE") {
|
||||
console.info("The user aborted a request.");
|
||||
} else {
|
||||
console.error(e);
|
||||
if (!outgoing.headersSent) {
|
||||
outgoing.writeHead(500, { "Content-Type": "text/plain" });
|
||||
}
|
||||
outgoing.end(`Error: ${err.message}`);
|
||||
outgoing.destroy(err);
|
||||
}
|
||||
};
|
||||
var flushHeaders = (outgoing) => {
|
||||
if ("flushHeaders" in outgoing && outgoing.writable) {
|
||||
outgoing.flushHeaders();
|
||||
}
|
||||
};
|
||||
var responseViaCache = async (res, outgoing) => {
|
||||
let [status, body, header] = res[cacheKey];
|
||||
let hasContentLength = false;
|
||||
if (!header) {
|
||||
header = { "content-type": "text/plain; charset=UTF-8" };
|
||||
} else if (header instanceof Headers) {
|
||||
hasContentLength = header.has("content-length");
|
||||
header = buildOutgoingHttpHeaders(header);
|
||||
} else if (Array.isArray(header)) {
|
||||
const headerObj = new Headers(header);
|
||||
hasContentLength = headerObj.has("content-length");
|
||||
header = buildOutgoingHttpHeaders(headerObj);
|
||||
} else {
|
||||
for (const key in header) {
|
||||
if (key.length === 14 && key.toLowerCase() === "content-length") {
|
||||
hasContentLength = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasContentLength) {
|
||||
if (typeof body === "string") {
|
||||
header["Content-Length"] = Buffer.byteLength(body);
|
||||
} else if (body instanceof Uint8Array) {
|
||||
header["Content-Length"] = body.byteLength;
|
||||
} else if (body instanceof Blob) {
|
||||
header["Content-Length"] = body.size;
|
||||
}
|
||||
}
|
||||
outgoing.writeHead(status, header);
|
||||
if (typeof body === "string" || body instanceof Uint8Array) {
|
||||
outgoing.end(body);
|
||||
} else if (body instanceof Blob) {
|
||||
outgoing.end(new Uint8Array(await body.arrayBuffer()));
|
||||
} else {
|
||||
flushHeaders(outgoing);
|
||||
await writeFromReadableStream(body, outgoing)?.catch(
|
||||
(e) => handleResponseError(e, outgoing)
|
||||
);
|
||||
}
|
||||
;
|
||||
outgoing[outgoingEnded]?.();
|
||||
};
|
||||
var isPromise = (res) => typeof res.then === "function";
|
||||
var responseViaResponseObject = async (res, outgoing, options = {}) => {
|
||||
if (isPromise(res)) {
|
||||
if (options.errorHandler) {
|
||||
try {
|
||||
res = await res;
|
||||
} catch (err) {
|
||||
const errRes = await options.errorHandler(err);
|
||||
if (!errRes) {
|
||||
return;
|
||||
}
|
||||
res = errRes;
|
||||
}
|
||||
} else {
|
||||
res = await res.catch(handleFetchError);
|
||||
}
|
||||
}
|
||||
if (cacheKey in res) {
|
||||
return responseViaCache(res, outgoing);
|
||||
}
|
||||
const resHeaderRecord = buildOutgoingHttpHeaders(res.headers);
|
||||
if (res.body) {
|
||||
const reader = res.body.getReader();
|
||||
const values = [];
|
||||
let done = false;
|
||||
let currentReadPromise = void 0;
|
||||
if (resHeaderRecord["transfer-encoding"] !== "chunked") {
|
||||
let maxReadCount = 2;
|
||||
for (let i = 0; i < maxReadCount; i++) {
|
||||
currentReadPromise ||= reader.read();
|
||||
const chunk = await readWithoutBlocking(currentReadPromise).catch((e) => {
|
||||
console.error(e);
|
||||
done = true;
|
||||
});
|
||||
if (!chunk) {
|
||||
if (i === 1) {
|
||||
await new Promise((resolve) => setTimeout(resolve));
|
||||
maxReadCount = 3;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
currentReadPromise = void 0;
|
||||
if (chunk.value) {
|
||||
values.push(chunk.value);
|
||||
}
|
||||
if (chunk.done) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (done && !("content-length" in resHeaderRecord)) {
|
||||
resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0);
|
||||
}
|
||||
}
|
||||
outgoing.writeHead(res.status, resHeaderRecord);
|
||||
values.forEach((value) => {
|
||||
;
|
||||
outgoing.write(value);
|
||||
});
|
||||
if (done) {
|
||||
outgoing.end();
|
||||
} else {
|
||||
if (values.length === 0) {
|
||||
flushHeaders(outgoing);
|
||||
}
|
||||
await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);
|
||||
}
|
||||
} else if (resHeaderRecord[X_ALREADY_SENT]) {
|
||||
} else {
|
||||
outgoing.writeHead(res.status, resHeaderRecord);
|
||||
outgoing.end();
|
||||
}
|
||||
;
|
||||
outgoing[outgoingEnded]?.();
|
||||
};
|
||||
var getRequestListener = (fetchCallback, options = {}) => {
|
||||
const autoCleanupIncoming = options.autoCleanupIncoming ?? true;
|
||||
if (options.overrideGlobalObjects !== false && global.Request !== Request) {
|
||||
Object.defineProperty(global, "Request", {
|
||||
value: Request
|
||||
});
|
||||
Object.defineProperty(global, "Response", {
|
||||
value: Response2
|
||||
});
|
||||
}
|
||||
return async (incoming, outgoing) => {
|
||||
let res, req;
|
||||
try {
|
||||
req = newRequest(incoming, options.hostname);
|
||||
let incomingEnded = !autoCleanupIncoming || incoming.method === "GET" || incoming.method === "HEAD";
|
||||
if (!incomingEnded) {
|
||||
;
|
||||
incoming[wrapBodyStream] = true;
|
||||
incoming.on("end", () => {
|
||||
incomingEnded = true;
|
||||
});
|
||||
if (incoming instanceof Http2ServerRequest2) {
|
||||
;
|
||||
outgoing[outgoingEnded] = () => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
incoming.destroy();
|
||||
outgoing.destroy();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
outgoing.on("close", () => {
|
||||
const abortController = req[abortControllerKey];
|
||||
if (abortController) {
|
||||
if (incoming.errored) {
|
||||
req[abortControllerKey].abort(incoming.errored.toString());
|
||||
} else if (!outgoing.writableFinished) {
|
||||
req[abortControllerKey].abort("Client connection prematurely closed.");
|
||||
}
|
||||
}
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
incoming.destroy();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
res = fetchCallback(req, { incoming, outgoing });
|
||||
if (cacheKey in res) {
|
||||
return responseViaCache(res, outgoing);
|
||||
}
|
||||
} catch (e) {
|
||||
if (!res) {
|
||||
if (options.errorHandler) {
|
||||
res = await options.errorHandler(req ? e : toRequestError(e));
|
||||
if (!res) {
|
||||
return;
|
||||
}
|
||||
} else if (!req) {
|
||||
res = handleRequestError();
|
||||
} else {
|
||||
res = handleFetchError(e);
|
||||
}
|
||||
} else {
|
||||
return handleResponseError(e, outgoing);
|
||||
}
|
||||
}
|
||||
try {
|
||||
return await responseViaResponseObject(res, outgoing, options);
|
||||
} catch (e) {
|
||||
return handleResponseError(e, outgoing);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// src/server.ts
|
||||
var createAdaptorServer = (options) => {
|
||||
const fetchCallback = options.fetch;
|
||||
const requestListener = getRequestListener(fetchCallback, {
|
||||
hostname: options.hostname,
|
||||
overrideGlobalObjects: options.overrideGlobalObjects,
|
||||
autoCleanupIncoming: options.autoCleanupIncoming
|
||||
});
|
||||
const createServer = options.createServer || createServerHTTP;
|
||||
const server = createServer(options.serverOptions || {}, requestListener);
|
||||
return server;
|
||||
};
|
||||
var serve = (options, listeningListener) => {
|
||||
const server = createAdaptorServer(options);
|
||||
server.listen(options?.port ?? 3e3, options.hostname, () => {
|
||||
const serverInfo = server.address();
|
||||
listeningListener && listeningListener(serverInfo);
|
||||
});
|
||||
return server;
|
||||
};
|
||||
export {
|
||||
createAdaptorServer,
|
||||
serve
|
||||
};
|
||||
44
projects/stt-mcp/node_modules/@hono/node-server/dist/types.d.mts
generated
vendored
Normal file
44
projects/stt-mcp/node_modules/@hono/node-server/dist/types.d.mts
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
import { IncomingMessage, ServerResponse, Server, ServerOptions as ServerOptions$1, createServer } from 'node:http';
|
||||
import { Http2ServerRequest, Http2ServerResponse, Http2Server, Http2SecureServer, ServerOptions as ServerOptions$3, createServer as createServer$2, SecureServerOptions, createSecureServer } from 'node:http2';
|
||||
import { ServerOptions as ServerOptions$2, createServer as createServer$1 } from 'node:https';
|
||||
|
||||
type HttpBindings = {
|
||||
incoming: IncomingMessage;
|
||||
outgoing: ServerResponse;
|
||||
};
|
||||
type Http2Bindings = {
|
||||
incoming: Http2ServerRequest;
|
||||
outgoing: Http2ServerResponse;
|
||||
};
|
||||
type FetchCallback = (request: Request, env: HttpBindings | Http2Bindings) => Promise<unknown> | unknown;
|
||||
type NextHandlerOption = {
|
||||
fetch: FetchCallback;
|
||||
};
|
||||
type ServerType = Server | Http2Server | Http2SecureServer;
|
||||
type createHttpOptions = {
|
||||
serverOptions?: ServerOptions$1;
|
||||
createServer?: typeof createServer;
|
||||
};
|
||||
type createHttpsOptions = {
|
||||
serverOptions?: ServerOptions$2;
|
||||
createServer?: typeof createServer$1;
|
||||
};
|
||||
type createHttp2Options = {
|
||||
serverOptions?: ServerOptions$3;
|
||||
createServer?: typeof createServer$2;
|
||||
};
|
||||
type createSecureHttp2Options = {
|
||||
serverOptions?: SecureServerOptions;
|
||||
createServer?: typeof createSecureServer;
|
||||
};
|
||||
type ServerOptions = createHttpOptions | createHttpsOptions | createHttp2Options | createSecureHttp2Options;
|
||||
type Options = {
|
||||
fetch: FetchCallback;
|
||||
overrideGlobalObjects?: boolean;
|
||||
autoCleanupIncoming?: boolean;
|
||||
port?: number;
|
||||
hostname?: string;
|
||||
} & ServerOptions;
|
||||
type CustomErrorHandler = (err: unknown) => void | Response | Promise<void | Response>;
|
||||
|
||||
export { CustomErrorHandler, FetchCallback, Http2Bindings, HttpBindings, NextHandlerOption, Options, ServerOptions, ServerType };
|
||||
44
projects/stt-mcp/node_modules/@hono/node-server/dist/types.d.ts
generated
vendored
Normal file
44
projects/stt-mcp/node_modules/@hono/node-server/dist/types.d.ts
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
import { IncomingMessage, ServerResponse, Server, ServerOptions as ServerOptions$1, createServer } from 'node:http';
|
||||
import { Http2ServerRequest, Http2ServerResponse, Http2Server, Http2SecureServer, ServerOptions as ServerOptions$3, createServer as createServer$2, SecureServerOptions, createSecureServer } from 'node:http2';
|
||||
import { ServerOptions as ServerOptions$2, createServer as createServer$1 } from 'node:https';
|
||||
|
||||
type HttpBindings = {
|
||||
incoming: IncomingMessage;
|
||||
outgoing: ServerResponse;
|
||||
};
|
||||
type Http2Bindings = {
|
||||
incoming: Http2ServerRequest;
|
||||
outgoing: Http2ServerResponse;
|
||||
};
|
||||
type FetchCallback = (request: Request, env: HttpBindings | Http2Bindings) => Promise<unknown> | unknown;
|
||||
type NextHandlerOption = {
|
||||
fetch: FetchCallback;
|
||||
};
|
||||
type ServerType = Server | Http2Server | Http2SecureServer;
|
||||
type createHttpOptions = {
|
||||
serverOptions?: ServerOptions$1;
|
||||
createServer?: typeof createServer;
|
||||
};
|
||||
type createHttpsOptions = {
|
||||
serverOptions?: ServerOptions$2;
|
||||
createServer?: typeof createServer$1;
|
||||
};
|
||||
type createHttp2Options = {
|
||||
serverOptions?: ServerOptions$3;
|
||||
createServer?: typeof createServer$2;
|
||||
};
|
||||
type createSecureHttp2Options = {
|
||||
serverOptions?: SecureServerOptions;
|
||||
createServer?: typeof createSecureServer;
|
||||
};
|
||||
type ServerOptions = createHttpOptions | createHttpsOptions | createHttp2Options | createSecureHttp2Options;
|
||||
type Options = {
|
||||
fetch: FetchCallback;
|
||||
overrideGlobalObjects?: boolean;
|
||||
autoCleanupIncoming?: boolean;
|
||||
port?: number;
|
||||
hostname?: string;
|
||||
} & ServerOptions;
|
||||
type CustomErrorHandler = (err: unknown) => void | Response | Promise<void | Response>;
|
||||
|
||||
export { CustomErrorHandler, FetchCallback, Http2Bindings, HttpBindings, NextHandlerOption, Options, ServerOptions, ServerType };
|
||||
18
projects/stt-mcp/node_modules/@hono/node-server/dist/types.js
generated
vendored
Normal file
18
projects/stt-mcp/node_modules/@hono/node-server/dist/types.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/types.ts
|
||||
var types_exports = {};
|
||||
module.exports = __toCommonJS(types_exports);
|
||||
0
projects/stt-mcp/node_modules/@hono/node-server/dist/types.mjs
generated
vendored
Normal file
0
projects/stt-mcp/node_modules/@hono/node-server/dist/types.mjs
generated
vendored
Normal file
9
projects/stt-mcp/node_modules/@hono/node-server/dist/utils.d.mts
generated
vendored
Normal file
9
projects/stt-mcp/node_modules/@hono/node-server/dist/utils.d.mts
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import { OutgoingHttpHeaders } from 'node:http';
|
||||
import { Writable } from 'node:stream';
|
||||
|
||||
declare function readWithoutBlocking(readPromise: Promise<ReadableStreamReadResult<Uint8Array>>): Promise<ReadableStreamReadResult<Uint8Array> | undefined>;
|
||||
declare function writeFromReadableStreamDefaultReader(reader: ReadableStreamDefaultReader<Uint8Array>, writable: Writable, currentReadPromise?: Promise<ReadableStreamReadResult<Uint8Array>> | undefined): Promise<void>;
|
||||
declare function writeFromReadableStream(stream: ReadableStream<Uint8Array>, writable: Writable): Promise<void> | undefined;
|
||||
declare const buildOutgoingHttpHeaders: (headers: Headers | HeadersInit | null | undefined) => OutgoingHttpHeaders;
|
||||
|
||||
export { buildOutgoingHttpHeaders, readWithoutBlocking, writeFromReadableStream, writeFromReadableStreamDefaultReader };
|
||||
9
projects/stt-mcp/node_modules/@hono/node-server/dist/utils.d.ts
generated
vendored
Normal file
9
projects/stt-mcp/node_modules/@hono/node-server/dist/utils.d.ts
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import { OutgoingHttpHeaders } from 'node:http';
|
||||
import { Writable } from 'node:stream';
|
||||
|
||||
declare function readWithoutBlocking(readPromise: Promise<ReadableStreamReadResult<Uint8Array>>): Promise<ReadableStreamReadResult<Uint8Array> | undefined>;
|
||||
declare function writeFromReadableStreamDefaultReader(reader: ReadableStreamDefaultReader<Uint8Array>, writable: Writable, currentReadPromise?: Promise<ReadableStreamReadResult<Uint8Array>> | undefined): Promise<void>;
|
||||
declare function writeFromReadableStream(stream: ReadableStream<Uint8Array>, writable: Writable): Promise<void> | undefined;
|
||||
declare const buildOutgoingHttpHeaders: (headers: Headers | HeadersInit | null | undefined) => OutgoingHttpHeaders;
|
||||
|
||||
export { buildOutgoingHttpHeaders, readWithoutBlocking, writeFromReadableStream, writeFromReadableStreamDefaultReader };
|
||||
99
projects/stt-mcp/node_modules/@hono/node-server/dist/utils.js
generated
vendored
Normal file
99
projects/stt-mcp/node_modules/@hono/node-server/dist/utils.js
generated
vendored
Normal file
@@ -0,0 +1,99 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/utils.ts
|
||||
var utils_exports = {};
|
||||
__export(utils_exports, {
|
||||
buildOutgoingHttpHeaders: () => buildOutgoingHttpHeaders,
|
||||
readWithoutBlocking: () => readWithoutBlocking,
|
||||
writeFromReadableStream: () => writeFromReadableStream,
|
||||
writeFromReadableStreamDefaultReader: () => writeFromReadableStreamDefaultReader
|
||||
});
|
||||
module.exports = __toCommonJS(utils_exports);
|
||||
async function readWithoutBlocking(readPromise) {
|
||||
return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
|
||||
}
|
||||
function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
|
||||
const cancel = (error) => {
|
||||
reader.cancel(error).catch(() => {
|
||||
});
|
||||
};
|
||||
writable.on("close", cancel);
|
||||
writable.on("error", cancel);
|
||||
(currentReadPromise ?? reader.read()).then(flow, handleStreamError);
|
||||
return reader.closed.finally(() => {
|
||||
writable.off("close", cancel);
|
||||
writable.off("error", cancel);
|
||||
});
|
||||
function handleStreamError(error) {
|
||||
if (error) {
|
||||
writable.destroy(error);
|
||||
}
|
||||
}
|
||||
function onDrain() {
|
||||
reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
function flow({ done, value }) {
|
||||
try {
|
||||
if (done) {
|
||||
writable.end();
|
||||
} else if (!writable.write(value)) {
|
||||
writable.once("drain", onDrain);
|
||||
} else {
|
||||
return reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
} catch (e) {
|
||||
handleStreamError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
function writeFromReadableStream(stream, writable) {
|
||||
if (stream.locked) {
|
||||
throw new TypeError("ReadableStream is locked.");
|
||||
} else if (writable.destroyed) {
|
||||
return;
|
||||
}
|
||||
return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
|
||||
}
|
||||
var buildOutgoingHttpHeaders = (headers) => {
|
||||
const res = {};
|
||||
if (!(headers instanceof Headers)) {
|
||||
headers = new Headers(headers ?? void 0);
|
||||
}
|
||||
const cookies = [];
|
||||
for (const [k, v] of headers) {
|
||||
if (k === "set-cookie") {
|
||||
cookies.push(v);
|
||||
} else {
|
||||
res[k] = v;
|
||||
}
|
||||
}
|
||||
if (cookies.length > 0) {
|
||||
res["set-cookie"] = cookies;
|
||||
}
|
||||
res["content-type"] ??= "text/plain; charset=UTF-8";
|
||||
return res;
|
||||
};
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
buildOutgoingHttpHeaders,
|
||||
readWithoutBlocking,
|
||||
writeFromReadableStream,
|
||||
writeFromReadableStreamDefaultReader
|
||||
});
|
||||
71
projects/stt-mcp/node_modules/@hono/node-server/dist/utils.mjs
generated
vendored
Normal file
71
projects/stt-mcp/node_modules/@hono/node-server/dist/utils.mjs
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
// src/utils.ts
|
||||
async function readWithoutBlocking(readPromise) {
|
||||
return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
|
||||
}
|
||||
function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
|
||||
const cancel = (error) => {
|
||||
reader.cancel(error).catch(() => {
|
||||
});
|
||||
};
|
||||
writable.on("close", cancel);
|
||||
writable.on("error", cancel);
|
||||
(currentReadPromise ?? reader.read()).then(flow, handleStreamError);
|
||||
return reader.closed.finally(() => {
|
||||
writable.off("close", cancel);
|
||||
writable.off("error", cancel);
|
||||
});
|
||||
function handleStreamError(error) {
|
||||
if (error) {
|
||||
writable.destroy(error);
|
||||
}
|
||||
}
|
||||
function onDrain() {
|
||||
reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
function flow({ done, value }) {
|
||||
try {
|
||||
if (done) {
|
||||
writable.end();
|
||||
} else if (!writable.write(value)) {
|
||||
writable.once("drain", onDrain);
|
||||
} else {
|
||||
return reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
} catch (e) {
|
||||
handleStreamError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
function writeFromReadableStream(stream, writable) {
|
||||
if (stream.locked) {
|
||||
throw new TypeError("ReadableStream is locked.");
|
||||
} else if (writable.destroyed) {
|
||||
return;
|
||||
}
|
||||
return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
|
||||
}
|
||||
var buildOutgoingHttpHeaders = (headers) => {
|
||||
const res = {};
|
||||
if (!(headers instanceof Headers)) {
|
||||
headers = new Headers(headers ?? void 0);
|
||||
}
|
||||
const cookies = [];
|
||||
for (const [k, v] of headers) {
|
||||
if (k === "set-cookie") {
|
||||
cookies.push(v);
|
||||
} else {
|
||||
res[k] = v;
|
||||
}
|
||||
}
|
||||
if (cookies.length > 0) {
|
||||
res["set-cookie"] = cookies;
|
||||
}
|
||||
res["content-type"] ??= "text/plain; charset=UTF-8";
|
||||
return res;
|
||||
};
|
||||
export {
|
||||
buildOutgoingHttpHeaders,
|
||||
readWithoutBlocking,
|
||||
writeFromReadableStream,
|
||||
writeFromReadableStreamDefaultReader
|
||||
};
|
||||
3
projects/stt-mcp/node_modules/@hono/node-server/dist/utils/response.d.mts
generated
vendored
Normal file
3
projects/stt-mcp/node_modules/@hono/node-server/dist/utils/response.d.mts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const RESPONSE_ALREADY_SENT: Response;
|
||||
|
||||
export { RESPONSE_ALREADY_SENT };
|
||||
3
projects/stt-mcp/node_modules/@hono/node-server/dist/utils/response.d.ts
generated
vendored
Normal file
3
projects/stt-mcp/node_modules/@hono/node-server/dist/utils/response.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const RESPONSE_ALREADY_SENT: Response;
|
||||
|
||||
export { RESPONSE_ALREADY_SENT };
|
||||
37
projects/stt-mcp/node_modules/@hono/node-server/dist/utils/response.js
generated
vendored
Normal file
37
projects/stt-mcp/node_modules/@hono/node-server/dist/utils/response.js
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/utils/response.ts
|
||||
var response_exports = {};
|
||||
__export(response_exports, {
|
||||
RESPONSE_ALREADY_SENT: () => RESPONSE_ALREADY_SENT
|
||||
});
|
||||
module.exports = __toCommonJS(response_exports);
|
||||
|
||||
// src/utils/response/constants.ts
|
||||
var X_ALREADY_SENT = "x-hono-already-sent";
|
||||
|
||||
// src/utils/response.ts
|
||||
var RESPONSE_ALREADY_SENT = new Response(null, {
|
||||
headers: { [X_ALREADY_SENT]: "true" }
|
||||
});
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
RESPONSE_ALREADY_SENT
|
||||
});
|
||||
10
projects/stt-mcp/node_modules/@hono/node-server/dist/utils/response.mjs
generated
vendored
Normal file
10
projects/stt-mcp/node_modules/@hono/node-server/dist/utils/response.mjs
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// src/utils/response/constants.ts
|
||||
var X_ALREADY_SENT = "x-hono-already-sent";
|
||||
|
||||
// src/utils/response.ts
|
||||
var RESPONSE_ALREADY_SENT = new Response(null, {
|
||||
headers: { [X_ALREADY_SENT]: "true" }
|
||||
});
|
||||
export {
|
||||
RESPONSE_ALREADY_SENT
|
||||
};
|
||||
3
projects/stt-mcp/node_modules/@hono/node-server/dist/utils/response/constants.d.mts
generated
vendored
Normal file
3
projects/stt-mcp/node_modules/@hono/node-server/dist/utils/response/constants.d.mts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const X_ALREADY_SENT = "x-hono-already-sent";
|
||||
|
||||
export { X_ALREADY_SENT };
|
||||
3
projects/stt-mcp/node_modules/@hono/node-server/dist/utils/response/constants.d.ts
generated
vendored
Normal file
3
projects/stt-mcp/node_modules/@hono/node-server/dist/utils/response/constants.d.ts
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
declare const X_ALREADY_SENT = "x-hono-already-sent";
|
||||
|
||||
export { X_ALREADY_SENT };
|
||||
30
projects/stt-mcp/node_modules/@hono/node-server/dist/utils/response/constants.js
generated
vendored
Normal file
30
projects/stt-mcp/node_modules/@hono/node-server/dist/utils/response/constants.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
"use strict";
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/utils/response/constants.ts
|
||||
var constants_exports = {};
|
||||
__export(constants_exports, {
|
||||
X_ALREADY_SENT: () => X_ALREADY_SENT
|
||||
});
|
||||
module.exports = __toCommonJS(constants_exports);
|
||||
var X_ALREADY_SENT = "x-hono-already-sent";
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
X_ALREADY_SENT
|
||||
});
|
||||
5
projects/stt-mcp/node_modules/@hono/node-server/dist/utils/response/constants.mjs
generated
vendored
Normal file
5
projects/stt-mcp/node_modules/@hono/node-server/dist/utils/response/constants.mjs
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
// src/utils/response/constants.ts
|
||||
var X_ALREADY_SENT = "x-hono-already-sent";
|
||||
export {
|
||||
X_ALREADY_SENT
|
||||
};
|
||||
7
projects/stt-mcp/node_modules/@hono/node-server/dist/vercel.d.mts
generated
vendored
Normal file
7
projects/stt-mcp/node_modules/@hono/node-server/dist/vercel.d.mts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import * as http2 from 'http2';
|
||||
import * as http from 'http';
|
||||
import { Hono } from 'hono';
|
||||
|
||||
declare const handle: (app: Hono<any, any, any>) => (incoming: http.IncomingMessage | http2.Http2ServerRequest, outgoing: http.ServerResponse | http2.Http2ServerResponse) => Promise<void>;
|
||||
|
||||
export { handle };
|
||||
7
projects/stt-mcp/node_modules/@hono/node-server/dist/vercel.d.ts
generated
vendored
Normal file
7
projects/stt-mcp/node_modules/@hono/node-server/dist/vercel.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import * as http2 from 'http2';
|
||||
import * as http from 'http';
|
||||
import { Hono } from 'hono';
|
||||
|
||||
declare const handle: (app: Hono<any, any, any>) => (incoming: http.IncomingMessage | http2.Http2ServerRequest, outgoing: http.ServerResponse | http2.Http2ServerResponse) => Promise<void>;
|
||||
|
||||
export { handle };
|
||||
607
projects/stt-mcp/node_modules/@hono/node-server/dist/vercel.js
generated
vendored
Normal file
607
projects/stt-mcp/node_modules/@hono/node-server/dist/vercel.js
generated
vendored
Normal file
@@ -0,0 +1,607 @@
|
||||
"use strict";
|
||||
var __create = Object.create;
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __getProtoOf = Object.getPrototypeOf;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
||||
// If the importer is in node compatibility mode or this is not an ESM
|
||||
// file that has been converted to a CommonJS file using a Babel-
|
||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
||||
mod
|
||||
));
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/vercel.ts
|
||||
var vercel_exports = {};
|
||||
__export(vercel_exports, {
|
||||
handle: () => handle
|
||||
});
|
||||
module.exports = __toCommonJS(vercel_exports);
|
||||
|
||||
// src/listener.ts
|
||||
var import_node_http22 = require("http2");
|
||||
|
||||
// src/request.ts
|
||||
var import_node_http2 = require("http2");
|
||||
var import_node_stream = require("stream");
|
||||
var RequestError = class extends Error {
|
||||
constructor(message, options) {
|
||||
super(message, options);
|
||||
this.name = "RequestError";
|
||||
}
|
||||
};
|
||||
var toRequestError = (e) => {
|
||||
if (e instanceof RequestError) {
|
||||
return e;
|
||||
}
|
||||
return new RequestError(e.message, { cause: e });
|
||||
};
|
||||
var GlobalRequest = global.Request;
|
||||
var Request = class extends GlobalRequest {
|
||||
constructor(input, options) {
|
||||
if (typeof input === "object" && getRequestCache in input) {
|
||||
input = input[getRequestCache]();
|
||||
}
|
||||
if (typeof options?.body?.getReader !== "undefined") {
|
||||
;
|
||||
options.duplex ??= "half";
|
||||
}
|
||||
super(input, options);
|
||||
}
|
||||
};
|
||||
var newHeadersFromIncoming = (incoming) => {
|
||||
const headerRecord = [];
|
||||
const rawHeaders = incoming.rawHeaders;
|
||||
for (let i = 0; i < rawHeaders.length; i += 2) {
|
||||
const { [i]: key, [i + 1]: value } = rawHeaders;
|
||||
if (key.charCodeAt(0) !== /*:*/
|
||||
58) {
|
||||
headerRecord.push([key, value]);
|
||||
}
|
||||
}
|
||||
return new Headers(headerRecord);
|
||||
};
|
||||
var wrapBodyStream = Symbol("wrapBodyStream");
|
||||
var newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
|
||||
const init = {
|
||||
method,
|
||||
headers,
|
||||
signal: abortController.signal
|
||||
};
|
||||
if (method === "TRACE") {
|
||||
init.method = "GET";
|
||||
const req = new Request(url, init);
|
||||
Object.defineProperty(req, "method", {
|
||||
get() {
|
||||
return "TRACE";
|
||||
}
|
||||
});
|
||||
return req;
|
||||
}
|
||||
if (!(method === "GET" || method === "HEAD")) {
|
||||
if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) {
|
||||
init.body = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(incoming.rawBody);
|
||||
controller.close();
|
||||
}
|
||||
});
|
||||
} else if (incoming[wrapBodyStream]) {
|
||||
let reader;
|
||||
init.body = new ReadableStream({
|
||||
async pull(controller) {
|
||||
try {
|
||||
reader ||= import_node_stream.Readable.toWeb(incoming).getReader();
|
||||
const { done, value } = await reader.read();
|
||||
if (done) {
|
||||
controller.close();
|
||||
} else {
|
||||
controller.enqueue(value);
|
||||
}
|
||||
} catch (error) {
|
||||
controller.error(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
init.body = import_node_stream.Readable.toWeb(incoming);
|
||||
}
|
||||
}
|
||||
return new Request(url, init);
|
||||
};
|
||||
var getRequestCache = Symbol("getRequestCache");
|
||||
var requestCache = Symbol("requestCache");
|
||||
var incomingKey = Symbol("incomingKey");
|
||||
var urlKey = Symbol("urlKey");
|
||||
var headersKey = Symbol("headersKey");
|
||||
var abortControllerKey = Symbol("abortControllerKey");
|
||||
var getAbortController = Symbol("getAbortController");
|
||||
var requestPrototype = {
|
||||
get method() {
|
||||
return this[incomingKey].method || "GET";
|
||||
},
|
||||
get url() {
|
||||
return this[urlKey];
|
||||
},
|
||||
get headers() {
|
||||
return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
|
||||
},
|
||||
[getAbortController]() {
|
||||
this[getRequestCache]();
|
||||
return this[abortControllerKey];
|
||||
},
|
||||
[getRequestCache]() {
|
||||
this[abortControllerKey] ||= new AbortController();
|
||||
return this[requestCache] ||= newRequestFromIncoming(
|
||||
this.method,
|
||||
this[urlKey],
|
||||
this.headers,
|
||||
this[incomingKey],
|
||||
this[abortControllerKey]
|
||||
);
|
||||
}
|
||||
};
|
||||
[
|
||||
"body",
|
||||
"bodyUsed",
|
||||
"cache",
|
||||
"credentials",
|
||||
"destination",
|
||||
"integrity",
|
||||
"mode",
|
||||
"redirect",
|
||||
"referrer",
|
||||
"referrerPolicy",
|
||||
"signal",
|
||||
"keepalive"
|
||||
].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
get() {
|
||||
return this[getRequestCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
value: function() {
|
||||
return this[getRequestCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(requestPrototype, Request.prototype);
|
||||
var newRequest = (incoming, defaultHostname) => {
|
||||
const req = Object.create(requestPrototype);
|
||||
req[incomingKey] = incoming;
|
||||
const incomingUrl = incoming.url || "";
|
||||
if (incomingUrl[0] !== "/" && // short-circuit for performance. most requests are relative URL.
|
||||
(incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) {
|
||||
if (incoming instanceof import_node_http2.Http2ServerRequest) {
|
||||
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
||||
}
|
||||
try {
|
||||
const url2 = new URL(incomingUrl);
|
||||
req[urlKey] = url2.href;
|
||||
} catch (e) {
|
||||
throw new RequestError("Invalid absolute URL", { cause: e });
|
||||
}
|
||||
return req;
|
||||
}
|
||||
const host = (incoming instanceof import_node_http2.Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;
|
||||
if (!host) {
|
||||
throw new RequestError("Missing host header");
|
||||
}
|
||||
let scheme;
|
||||
if (incoming instanceof import_node_http2.Http2ServerRequest) {
|
||||
scheme = incoming.scheme;
|
||||
if (!(scheme === "http" || scheme === "https")) {
|
||||
throw new RequestError("Unsupported scheme");
|
||||
}
|
||||
} else {
|
||||
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
||||
}
|
||||
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
||||
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
||||
throw new RequestError("Invalid host header");
|
||||
}
|
||||
req[urlKey] = url.href;
|
||||
return req;
|
||||
};
|
||||
|
||||
// src/response.ts
|
||||
var responseCache = Symbol("responseCache");
|
||||
var getResponseCache = Symbol("getResponseCache");
|
||||
var cacheKey = Symbol("cache");
|
||||
var GlobalResponse = global.Response;
|
||||
var Response2 = class _Response {
|
||||
#body;
|
||||
#init;
|
||||
[getResponseCache]() {
|
||||
delete this[cacheKey];
|
||||
return this[responseCache] ||= new GlobalResponse(this.#body, this.#init);
|
||||
}
|
||||
constructor(body, init) {
|
||||
let headers;
|
||||
this.#body = body;
|
||||
if (init instanceof _Response) {
|
||||
const cachedGlobalResponse = init[responseCache];
|
||||
if (cachedGlobalResponse) {
|
||||
this.#init = cachedGlobalResponse;
|
||||
this[getResponseCache]();
|
||||
return;
|
||||
} else {
|
||||
this.#init = init.#init;
|
||||
headers = new Headers(init.#init.headers);
|
||||
}
|
||||
} else {
|
||||
this.#init = init;
|
||||
}
|
||||
if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) {
|
||||
;
|
||||
this[cacheKey] = [init?.status || 200, body, headers || init?.headers];
|
||||
}
|
||||
}
|
||||
get headers() {
|
||||
const cache = this[cacheKey];
|
||||
if (cache) {
|
||||
if (!(cache[2] instanceof Headers)) {
|
||||
cache[2] = new Headers(
|
||||
cache[2] || { "content-type": "text/plain; charset=UTF-8" }
|
||||
);
|
||||
}
|
||||
return cache[2];
|
||||
}
|
||||
return this[getResponseCache]().headers;
|
||||
}
|
||||
get status() {
|
||||
return this[cacheKey]?.[0] ?? this[getResponseCache]().status;
|
||||
}
|
||||
get ok() {
|
||||
const status = this.status;
|
||||
return status >= 200 && status < 300;
|
||||
}
|
||||
};
|
||||
["body", "bodyUsed", "redirected", "statusText", "trailers", "type", "url"].forEach((k) => {
|
||||
Object.defineProperty(Response2.prototype, k, {
|
||||
get() {
|
||||
return this[getResponseCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(Response2.prototype, k, {
|
||||
value: function() {
|
||||
return this[getResponseCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(Response2, GlobalResponse);
|
||||
Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);
|
||||
|
||||
// src/utils.ts
|
||||
async function readWithoutBlocking(readPromise) {
|
||||
return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
|
||||
}
|
||||
function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
|
||||
const cancel = (error) => {
|
||||
reader.cancel(error).catch(() => {
|
||||
});
|
||||
};
|
||||
writable.on("close", cancel);
|
||||
writable.on("error", cancel);
|
||||
(currentReadPromise ?? reader.read()).then(flow, handleStreamError);
|
||||
return reader.closed.finally(() => {
|
||||
writable.off("close", cancel);
|
||||
writable.off("error", cancel);
|
||||
});
|
||||
function handleStreamError(error) {
|
||||
if (error) {
|
||||
writable.destroy(error);
|
||||
}
|
||||
}
|
||||
function onDrain() {
|
||||
reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
function flow({ done, value }) {
|
||||
try {
|
||||
if (done) {
|
||||
writable.end();
|
||||
} else if (!writable.write(value)) {
|
||||
writable.once("drain", onDrain);
|
||||
} else {
|
||||
return reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
} catch (e) {
|
||||
handleStreamError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
function writeFromReadableStream(stream, writable) {
|
||||
if (stream.locked) {
|
||||
throw new TypeError("ReadableStream is locked.");
|
||||
} else if (writable.destroyed) {
|
||||
return;
|
||||
}
|
||||
return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
|
||||
}
|
||||
var buildOutgoingHttpHeaders = (headers) => {
|
||||
const res = {};
|
||||
if (!(headers instanceof Headers)) {
|
||||
headers = new Headers(headers ?? void 0);
|
||||
}
|
||||
const cookies = [];
|
||||
for (const [k, v] of headers) {
|
||||
if (k === "set-cookie") {
|
||||
cookies.push(v);
|
||||
} else {
|
||||
res[k] = v;
|
||||
}
|
||||
}
|
||||
if (cookies.length > 0) {
|
||||
res["set-cookie"] = cookies;
|
||||
}
|
||||
res["content-type"] ??= "text/plain; charset=UTF-8";
|
||||
return res;
|
||||
};
|
||||
|
||||
// src/utils/response/constants.ts
|
||||
var X_ALREADY_SENT = "x-hono-already-sent";
|
||||
|
||||
// src/globals.ts
|
||||
var import_node_crypto = __toESM(require("crypto"));
|
||||
if (typeof global.crypto === "undefined") {
|
||||
global.crypto = import_node_crypto.default;
|
||||
}
|
||||
|
||||
// src/listener.ts
|
||||
var outgoingEnded = Symbol("outgoingEnded");
|
||||
var handleRequestError = () => new Response(null, {
|
||||
status: 400
|
||||
});
|
||||
var handleFetchError = (e) => new Response(null, {
|
||||
status: e instanceof Error && (e.name === "TimeoutError" || e.constructor.name === "TimeoutError") ? 504 : 500
|
||||
});
|
||||
var handleResponseError = (e, outgoing) => {
|
||||
const err = e instanceof Error ? e : new Error("unknown error", { cause: e });
|
||||
if (err.code === "ERR_STREAM_PREMATURE_CLOSE") {
|
||||
console.info("The user aborted a request.");
|
||||
} else {
|
||||
console.error(e);
|
||||
if (!outgoing.headersSent) {
|
||||
outgoing.writeHead(500, { "Content-Type": "text/plain" });
|
||||
}
|
||||
outgoing.end(`Error: ${err.message}`);
|
||||
outgoing.destroy(err);
|
||||
}
|
||||
};
|
||||
var flushHeaders = (outgoing) => {
|
||||
if ("flushHeaders" in outgoing && outgoing.writable) {
|
||||
outgoing.flushHeaders();
|
||||
}
|
||||
};
|
||||
var responseViaCache = async (res, outgoing) => {
|
||||
let [status, body, header] = res[cacheKey];
|
||||
let hasContentLength = false;
|
||||
if (!header) {
|
||||
header = { "content-type": "text/plain; charset=UTF-8" };
|
||||
} else if (header instanceof Headers) {
|
||||
hasContentLength = header.has("content-length");
|
||||
header = buildOutgoingHttpHeaders(header);
|
||||
} else if (Array.isArray(header)) {
|
||||
const headerObj = new Headers(header);
|
||||
hasContentLength = headerObj.has("content-length");
|
||||
header = buildOutgoingHttpHeaders(headerObj);
|
||||
} else {
|
||||
for (const key in header) {
|
||||
if (key.length === 14 && key.toLowerCase() === "content-length") {
|
||||
hasContentLength = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasContentLength) {
|
||||
if (typeof body === "string") {
|
||||
header["Content-Length"] = Buffer.byteLength(body);
|
||||
} else if (body instanceof Uint8Array) {
|
||||
header["Content-Length"] = body.byteLength;
|
||||
} else if (body instanceof Blob) {
|
||||
header["Content-Length"] = body.size;
|
||||
}
|
||||
}
|
||||
outgoing.writeHead(status, header);
|
||||
if (typeof body === "string" || body instanceof Uint8Array) {
|
||||
outgoing.end(body);
|
||||
} else if (body instanceof Blob) {
|
||||
outgoing.end(new Uint8Array(await body.arrayBuffer()));
|
||||
} else {
|
||||
flushHeaders(outgoing);
|
||||
await writeFromReadableStream(body, outgoing)?.catch(
|
||||
(e) => handleResponseError(e, outgoing)
|
||||
);
|
||||
}
|
||||
;
|
||||
outgoing[outgoingEnded]?.();
|
||||
};
|
||||
var isPromise = (res) => typeof res.then === "function";
|
||||
var responseViaResponseObject = async (res, outgoing, options = {}) => {
|
||||
if (isPromise(res)) {
|
||||
if (options.errorHandler) {
|
||||
try {
|
||||
res = await res;
|
||||
} catch (err) {
|
||||
const errRes = await options.errorHandler(err);
|
||||
if (!errRes) {
|
||||
return;
|
||||
}
|
||||
res = errRes;
|
||||
}
|
||||
} else {
|
||||
res = await res.catch(handleFetchError);
|
||||
}
|
||||
}
|
||||
if (cacheKey in res) {
|
||||
return responseViaCache(res, outgoing);
|
||||
}
|
||||
const resHeaderRecord = buildOutgoingHttpHeaders(res.headers);
|
||||
if (res.body) {
|
||||
const reader = res.body.getReader();
|
||||
const values = [];
|
||||
let done = false;
|
||||
let currentReadPromise = void 0;
|
||||
if (resHeaderRecord["transfer-encoding"] !== "chunked") {
|
||||
let maxReadCount = 2;
|
||||
for (let i = 0; i < maxReadCount; i++) {
|
||||
currentReadPromise ||= reader.read();
|
||||
const chunk = await readWithoutBlocking(currentReadPromise).catch((e) => {
|
||||
console.error(e);
|
||||
done = true;
|
||||
});
|
||||
if (!chunk) {
|
||||
if (i === 1) {
|
||||
await new Promise((resolve) => setTimeout(resolve));
|
||||
maxReadCount = 3;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
currentReadPromise = void 0;
|
||||
if (chunk.value) {
|
||||
values.push(chunk.value);
|
||||
}
|
||||
if (chunk.done) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (done && !("content-length" in resHeaderRecord)) {
|
||||
resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0);
|
||||
}
|
||||
}
|
||||
outgoing.writeHead(res.status, resHeaderRecord);
|
||||
values.forEach((value) => {
|
||||
;
|
||||
outgoing.write(value);
|
||||
});
|
||||
if (done) {
|
||||
outgoing.end();
|
||||
} else {
|
||||
if (values.length === 0) {
|
||||
flushHeaders(outgoing);
|
||||
}
|
||||
await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);
|
||||
}
|
||||
} else if (resHeaderRecord[X_ALREADY_SENT]) {
|
||||
} else {
|
||||
outgoing.writeHead(res.status, resHeaderRecord);
|
||||
outgoing.end();
|
||||
}
|
||||
;
|
||||
outgoing[outgoingEnded]?.();
|
||||
};
|
||||
var getRequestListener = (fetchCallback, options = {}) => {
|
||||
const autoCleanupIncoming = options.autoCleanupIncoming ?? true;
|
||||
if (options.overrideGlobalObjects !== false && global.Request !== Request) {
|
||||
Object.defineProperty(global, "Request", {
|
||||
value: Request
|
||||
});
|
||||
Object.defineProperty(global, "Response", {
|
||||
value: Response2
|
||||
});
|
||||
}
|
||||
return async (incoming, outgoing) => {
|
||||
let res, req;
|
||||
try {
|
||||
req = newRequest(incoming, options.hostname);
|
||||
let incomingEnded = !autoCleanupIncoming || incoming.method === "GET" || incoming.method === "HEAD";
|
||||
if (!incomingEnded) {
|
||||
;
|
||||
incoming[wrapBodyStream] = true;
|
||||
incoming.on("end", () => {
|
||||
incomingEnded = true;
|
||||
});
|
||||
if (incoming instanceof import_node_http22.Http2ServerRequest) {
|
||||
;
|
||||
outgoing[outgoingEnded] = () => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
incoming.destroy();
|
||||
outgoing.destroy();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
outgoing.on("close", () => {
|
||||
const abortController = req[abortControllerKey];
|
||||
if (abortController) {
|
||||
if (incoming.errored) {
|
||||
req[abortControllerKey].abort(incoming.errored.toString());
|
||||
} else if (!outgoing.writableFinished) {
|
||||
req[abortControllerKey].abort("Client connection prematurely closed.");
|
||||
}
|
||||
}
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
incoming.destroy();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
res = fetchCallback(req, { incoming, outgoing });
|
||||
if (cacheKey in res) {
|
||||
return responseViaCache(res, outgoing);
|
||||
}
|
||||
} catch (e) {
|
||||
if (!res) {
|
||||
if (options.errorHandler) {
|
||||
res = await options.errorHandler(req ? e : toRequestError(e));
|
||||
if (!res) {
|
||||
return;
|
||||
}
|
||||
} else if (!req) {
|
||||
res = handleRequestError();
|
||||
} else {
|
||||
res = handleFetchError(e);
|
||||
}
|
||||
} else {
|
||||
return handleResponseError(e, outgoing);
|
||||
}
|
||||
}
|
||||
try {
|
||||
return await responseViaResponseObject(res, outgoing, options);
|
||||
} catch (e) {
|
||||
return handleResponseError(e, outgoing);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// src/vercel.ts
|
||||
var handle = (app) => {
|
||||
return getRequestListener(app.fetch);
|
||||
};
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
handle
|
||||
});
|
||||
570
projects/stt-mcp/node_modules/@hono/node-server/dist/vercel.mjs
generated
vendored
Normal file
570
projects/stt-mcp/node_modules/@hono/node-server/dist/vercel.mjs
generated
vendored
Normal file
@@ -0,0 +1,570 @@
|
||||
// src/listener.ts
|
||||
import { Http2ServerRequest as Http2ServerRequest2 } from "http2";
|
||||
|
||||
// src/request.ts
|
||||
import { Http2ServerRequest } from "http2";
|
||||
import { Readable } from "stream";
|
||||
var RequestError = class extends Error {
|
||||
constructor(message, options) {
|
||||
super(message, options);
|
||||
this.name = "RequestError";
|
||||
}
|
||||
};
|
||||
var toRequestError = (e) => {
|
||||
if (e instanceof RequestError) {
|
||||
return e;
|
||||
}
|
||||
return new RequestError(e.message, { cause: e });
|
||||
};
|
||||
var GlobalRequest = global.Request;
|
||||
var Request = class extends GlobalRequest {
|
||||
constructor(input, options) {
|
||||
if (typeof input === "object" && getRequestCache in input) {
|
||||
input = input[getRequestCache]();
|
||||
}
|
||||
if (typeof options?.body?.getReader !== "undefined") {
|
||||
;
|
||||
options.duplex ??= "half";
|
||||
}
|
||||
super(input, options);
|
||||
}
|
||||
};
|
||||
var newHeadersFromIncoming = (incoming) => {
|
||||
const headerRecord = [];
|
||||
const rawHeaders = incoming.rawHeaders;
|
||||
for (let i = 0; i < rawHeaders.length; i += 2) {
|
||||
const { [i]: key, [i + 1]: value } = rawHeaders;
|
||||
if (key.charCodeAt(0) !== /*:*/
|
||||
58) {
|
||||
headerRecord.push([key, value]);
|
||||
}
|
||||
}
|
||||
return new Headers(headerRecord);
|
||||
};
|
||||
var wrapBodyStream = Symbol("wrapBodyStream");
|
||||
var newRequestFromIncoming = (method, url, headers, incoming, abortController) => {
|
||||
const init = {
|
||||
method,
|
||||
headers,
|
||||
signal: abortController.signal
|
||||
};
|
||||
if (method === "TRACE") {
|
||||
init.method = "GET";
|
||||
const req = new Request(url, init);
|
||||
Object.defineProperty(req, "method", {
|
||||
get() {
|
||||
return "TRACE";
|
||||
}
|
||||
});
|
||||
return req;
|
||||
}
|
||||
if (!(method === "GET" || method === "HEAD")) {
|
||||
if ("rawBody" in incoming && incoming.rawBody instanceof Buffer) {
|
||||
init.body = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(incoming.rawBody);
|
||||
controller.close();
|
||||
}
|
||||
});
|
||||
} else if (incoming[wrapBodyStream]) {
|
||||
let reader;
|
||||
init.body = new ReadableStream({
|
||||
async pull(controller) {
|
||||
try {
|
||||
reader ||= Readable.toWeb(incoming).getReader();
|
||||
const { done, value } = await reader.read();
|
||||
if (done) {
|
||||
controller.close();
|
||||
} else {
|
||||
controller.enqueue(value);
|
||||
}
|
||||
} catch (error) {
|
||||
controller.error(error);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
init.body = Readable.toWeb(incoming);
|
||||
}
|
||||
}
|
||||
return new Request(url, init);
|
||||
};
|
||||
var getRequestCache = Symbol("getRequestCache");
|
||||
var requestCache = Symbol("requestCache");
|
||||
var incomingKey = Symbol("incomingKey");
|
||||
var urlKey = Symbol("urlKey");
|
||||
var headersKey = Symbol("headersKey");
|
||||
var abortControllerKey = Symbol("abortControllerKey");
|
||||
var getAbortController = Symbol("getAbortController");
|
||||
var requestPrototype = {
|
||||
get method() {
|
||||
return this[incomingKey].method || "GET";
|
||||
},
|
||||
get url() {
|
||||
return this[urlKey];
|
||||
},
|
||||
get headers() {
|
||||
return this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);
|
||||
},
|
||||
[getAbortController]() {
|
||||
this[getRequestCache]();
|
||||
return this[abortControllerKey];
|
||||
},
|
||||
[getRequestCache]() {
|
||||
this[abortControllerKey] ||= new AbortController();
|
||||
return this[requestCache] ||= newRequestFromIncoming(
|
||||
this.method,
|
||||
this[urlKey],
|
||||
this.headers,
|
||||
this[incomingKey],
|
||||
this[abortControllerKey]
|
||||
);
|
||||
}
|
||||
};
|
||||
[
|
||||
"body",
|
||||
"bodyUsed",
|
||||
"cache",
|
||||
"credentials",
|
||||
"destination",
|
||||
"integrity",
|
||||
"mode",
|
||||
"redirect",
|
||||
"referrer",
|
||||
"referrerPolicy",
|
||||
"signal",
|
||||
"keepalive"
|
||||
].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
get() {
|
||||
return this[getRequestCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(requestPrototype, k, {
|
||||
value: function() {
|
||||
return this[getRequestCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(requestPrototype, Request.prototype);
|
||||
var newRequest = (incoming, defaultHostname) => {
|
||||
const req = Object.create(requestPrototype);
|
||||
req[incomingKey] = incoming;
|
||||
const incomingUrl = incoming.url || "";
|
||||
if (incomingUrl[0] !== "/" && // short-circuit for performance. most requests are relative URL.
|
||||
(incomingUrl.startsWith("http://") || incomingUrl.startsWith("https://"))) {
|
||||
if (incoming instanceof Http2ServerRequest) {
|
||||
throw new RequestError("Absolute URL for :path is not allowed in HTTP/2");
|
||||
}
|
||||
try {
|
||||
const url2 = new URL(incomingUrl);
|
||||
req[urlKey] = url2.href;
|
||||
} catch (e) {
|
||||
throw new RequestError("Invalid absolute URL", { cause: e });
|
||||
}
|
||||
return req;
|
||||
}
|
||||
const host = (incoming instanceof Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;
|
||||
if (!host) {
|
||||
throw new RequestError("Missing host header");
|
||||
}
|
||||
let scheme;
|
||||
if (incoming instanceof Http2ServerRequest) {
|
||||
scheme = incoming.scheme;
|
||||
if (!(scheme === "http" || scheme === "https")) {
|
||||
throw new RequestError("Unsupported scheme");
|
||||
}
|
||||
} else {
|
||||
scheme = incoming.socket && incoming.socket.encrypted ? "https" : "http";
|
||||
}
|
||||
const url = new URL(`${scheme}://${host}${incomingUrl}`);
|
||||
if (url.hostname.length !== host.length && url.hostname !== host.replace(/:\d+$/, "")) {
|
||||
throw new RequestError("Invalid host header");
|
||||
}
|
||||
req[urlKey] = url.href;
|
||||
return req;
|
||||
};
|
||||
|
||||
// src/response.ts
|
||||
var responseCache = Symbol("responseCache");
|
||||
var getResponseCache = Symbol("getResponseCache");
|
||||
var cacheKey = Symbol("cache");
|
||||
var GlobalResponse = global.Response;
|
||||
var Response2 = class _Response {
|
||||
#body;
|
||||
#init;
|
||||
[getResponseCache]() {
|
||||
delete this[cacheKey];
|
||||
return this[responseCache] ||= new GlobalResponse(this.#body, this.#init);
|
||||
}
|
||||
constructor(body, init) {
|
||||
let headers;
|
||||
this.#body = body;
|
||||
if (init instanceof _Response) {
|
||||
const cachedGlobalResponse = init[responseCache];
|
||||
if (cachedGlobalResponse) {
|
||||
this.#init = cachedGlobalResponse;
|
||||
this[getResponseCache]();
|
||||
return;
|
||||
} else {
|
||||
this.#init = init.#init;
|
||||
headers = new Headers(init.#init.headers);
|
||||
}
|
||||
} else {
|
||||
this.#init = init;
|
||||
}
|
||||
if (typeof body === "string" || typeof body?.getReader !== "undefined" || body instanceof Blob || body instanceof Uint8Array) {
|
||||
;
|
||||
this[cacheKey] = [init?.status || 200, body, headers || init?.headers];
|
||||
}
|
||||
}
|
||||
get headers() {
|
||||
const cache = this[cacheKey];
|
||||
if (cache) {
|
||||
if (!(cache[2] instanceof Headers)) {
|
||||
cache[2] = new Headers(
|
||||
cache[2] || { "content-type": "text/plain; charset=UTF-8" }
|
||||
);
|
||||
}
|
||||
return cache[2];
|
||||
}
|
||||
return this[getResponseCache]().headers;
|
||||
}
|
||||
get status() {
|
||||
return this[cacheKey]?.[0] ?? this[getResponseCache]().status;
|
||||
}
|
||||
get ok() {
|
||||
const status = this.status;
|
||||
return status >= 200 && status < 300;
|
||||
}
|
||||
};
|
||||
["body", "bodyUsed", "redirected", "statusText", "trailers", "type", "url"].forEach((k) => {
|
||||
Object.defineProperty(Response2.prototype, k, {
|
||||
get() {
|
||||
return this[getResponseCache]()[k];
|
||||
}
|
||||
});
|
||||
});
|
||||
["arrayBuffer", "blob", "clone", "formData", "json", "text"].forEach((k) => {
|
||||
Object.defineProperty(Response2.prototype, k, {
|
||||
value: function() {
|
||||
return this[getResponseCache]()[k]();
|
||||
}
|
||||
});
|
||||
});
|
||||
Object.setPrototypeOf(Response2, GlobalResponse);
|
||||
Object.setPrototypeOf(Response2.prototype, GlobalResponse.prototype);
|
||||
|
||||
// src/utils.ts
|
||||
async function readWithoutBlocking(readPromise) {
|
||||
return Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);
|
||||
}
|
||||
function writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {
|
||||
const cancel = (error) => {
|
||||
reader.cancel(error).catch(() => {
|
||||
});
|
||||
};
|
||||
writable.on("close", cancel);
|
||||
writable.on("error", cancel);
|
||||
(currentReadPromise ?? reader.read()).then(flow, handleStreamError);
|
||||
return reader.closed.finally(() => {
|
||||
writable.off("close", cancel);
|
||||
writable.off("error", cancel);
|
||||
});
|
||||
function handleStreamError(error) {
|
||||
if (error) {
|
||||
writable.destroy(error);
|
||||
}
|
||||
}
|
||||
function onDrain() {
|
||||
reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
function flow({ done, value }) {
|
||||
try {
|
||||
if (done) {
|
||||
writable.end();
|
||||
} else if (!writable.write(value)) {
|
||||
writable.once("drain", onDrain);
|
||||
} else {
|
||||
return reader.read().then(flow, handleStreamError);
|
||||
}
|
||||
} catch (e) {
|
||||
handleStreamError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
function writeFromReadableStream(stream, writable) {
|
||||
if (stream.locked) {
|
||||
throw new TypeError("ReadableStream is locked.");
|
||||
} else if (writable.destroyed) {
|
||||
return;
|
||||
}
|
||||
return writeFromReadableStreamDefaultReader(stream.getReader(), writable);
|
||||
}
|
||||
var buildOutgoingHttpHeaders = (headers) => {
|
||||
const res = {};
|
||||
if (!(headers instanceof Headers)) {
|
||||
headers = new Headers(headers ?? void 0);
|
||||
}
|
||||
const cookies = [];
|
||||
for (const [k, v] of headers) {
|
||||
if (k === "set-cookie") {
|
||||
cookies.push(v);
|
||||
} else {
|
||||
res[k] = v;
|
||||
}
|
||||
}
|
||||
if (cookies.length > 0) {
|
||||
res["set-cookie"] = cookies;
|
||||
}
|
||||
res["content-type"] ??= "text/plain; charset=UTF-8";
|
||||
return res;
|
||||
};
|
||||
|
||||
// src/utils/response/constants.ts
|
||||
var X_ALREADY_SENT = "x-hono-already-sent";
|
||||
|
||||
// src/globals.ts
|
||||
import crypto from "crypto";
|
||||
if (typeof global.crypto === "undefined") {
|
||||
global.crypto = crypto;
|
||||
}
|
||||
|
||||
// src/listener.ts
|
||||
var outgoingEnded = Symbol("outgoingEnded");
|
||||
var handleRequestError = () => new Response(null, {
|
||||
status: 400
|
||||
});
|
||||
var handleFetchError = (e) => new Response(null, {
|
||||
status: e instanceof Error && (e.name === "TimeoutError" || e.constructor.name === "TimeoutError") ? 504 : 500
|
||||
});
|
||||
var handleResponseError = (e, outgoing) => {
|
||||
const err = e instanceof Error ? e : new Error("unknown error", { cause: e });
|
||||
if (err.code === "ERR_STREAM_PREMATURE_CLOSE") {
|
||||
console.info("The user aborted a request.");
|
||||
} else {
|
||||
console.error(e);
|
||||
if (!outgoing.headersSent) {
|
||||
outgoing.writeHead(500, { "Content-Type": "text/plain" });
|
||||
}
|
||||
outgoing.end(`Error: ${err.message}`);
|
||||
outgoing.destroy(err);
|
||||
}
|
||||
};
|
||||
var flushHeaders = (outgoing) => {
|
||||
if ("flushHeaders" in outgoing && outgoing.writable) {
|
||||
outgoing.flushHeaders();
|
||||
}
|
||||
};
|
||||
var responseViaCache = async (res, outgoing) => {
|
||||
let [status, body, header] = res[cacheKey];
|
||||
let hasContentLength = false;
|
||||
if (!header) {
|
||||
header = { "content-type": "text/plain; charset=UTF-8" };
|
||||
} else if (header instanceof Headers) {
|
||||
hasContentLength = header.has("content-length");
|
||||
header = buildOutgoingHttpHeaders(header);
|
||||
} else if (Array.isArray(header)) {
|
||||
const headerObj = new Headers(header);
|
||||
hasContentLength = headerObj.has("content-length");
|
||||
header = buildOutgoingHttpHeaders(headerObj);
|
||||
} else {
|
||||
for (const key in header) {
|
||||
if (key.length === 14 && key.toLowerCase() === "content-length") {
|
||||
hasContentLength = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasContentLength) {
|
||||
if (typeof body === "string") {
|
||||
header["Content-Length"] = Buffer.byteLength(body);
|
||||
} else if (body instanceof Uint8Array) {
|
||||
header["Content-Length"] = body.byteLength;
|
||||
} else if (body instanceof Blob) {
|
||||
header["Content-Length"] = body.size;
|
||||
}
|
||||
}
|
||||
outgoing.writeHead(status, header);
|
||||
if (typeof body === "string" || body instanceof Uint8Array) {
|
||||
outgoing.end(body);
|
||||
} else if (body instanceof Blob) {
|
||||
outgoing.end(new Uint8Array(await body.arrayBuffer()));
|
||||
} else {
|
||||
flushHeaders(outgoing);
|
||||
await writeFromReadableStream(body, outgoing)?.catch(
|
||||
(e) => handleResponseError(e, outgoing)
|
||||
);
|
||||
}
|
||||
;
|
||||
outgoing[outgoingEnded]?.();
|
||||
};
|
||||
var isPromise = (res) => typeof res.then === "function";
|
||||
var responseViaResponseObject = async (res, outgoing, options = {}) => {
|
||||
if (isPromise(res)) {
|
||||
if (options.errorHandler) {
|
||||
try {
|
||||
res = await res;
|
||||
} catch (err) {
|
||||
const errRes = await options.errorHandler(err);
|
||||
if (!errRes) {
|
||||
return;
|
||||
}
|
||||
res = errRes;
|
||||
}
|
||||
} else {
|
||||
res = await res.catch(handleFetchError);
|
||||
}
|
||||
}
|
||||
if (cacheKey in res) {
|
||||
return responseViaCache(res, outgoing);
|
||||
}
|
||||
const resHeaderRecord = buildOutgoingHttpHeaders(res.headers);
|
||||
if (res.body) {
|
||||
const reader = res.body.getReader();
|
||||
const values = [];
|
||||
let done = false;
|
||||
let currentReadPromise = void 0;
|
||||
if (resHeaderRecord["transfer-encoding"] !== "chunked") {
|
||||
let maxReadCount = 2;
|
||||
for (let i = 0; i < maxReadCount; i++) {
|
||||
currentReadPromise ||= reader.read();
|
||||
const chunk = await readWithoutBlocking(currentReadPromise).catch((e) => {
|
||||
console.error(e);
|
||||
done = true;
|
||||
});
|
||||
if (!chunk) {
|
||||
if (i === 1) {
|
||||
await new Promise((resolve) => setTimeout(resolve));
|
||||
maxReadCount = 3;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
currentReadPromise = void 0;
|
||||
if (chunk.value) {
|
||||
values.push(chunk.value);
|
||||
}
|
||||
if (chunk.done) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (done && !("content-length" in resHeaderRecord)) {
|
||||
resHeaderRecord["content-length"] = values.reduce((acc, value) => acc + value.length, 0);
|
||||
}
|
||||
}
|
||||
outgoing.writeHead(res.status, resHeaderRecord);
|
||||
values.forEach((value) => {
|
||||
;
|
||||
outgoing.write(value);
|
||||
});
|
||||
if (done) {
|
||||
outgoing.end();
|
||||
} else {
|
||||
if (values.length === 0) {
|
||||
flushHeaders(outgoing);
|
||||
}
|
||||
await writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);
|
||||
}
|
||||
} else if (resHeaderRecord[X_ALREADY_SENT]) {
|
||||
} else {
|
||||
outgoing.writeHead(res.status, resHeaderRecord);
|
||||
outgoing.end();
|
||||
}
|
||||
;
|
||||
outgoing[outgoingEnded]?.();
|
||||
};
|
||||
var getRequestListener = (fetchCallback, options = {}) => {
|
||||
const autoCleanupIncoming = options.autoCleanupIncoming ?? true;
|
||||
if (options.overrideGlobalObjects !== false && global.Request !== Request) {
|
||||
Object.defineProperty(global, "Request", {
|
||||
value: Request
|
||||
});
|
||||
Object.defineProperty(global, "Response", {
|
||||
value: Response2
|
||||
});
|
||||
}
|
||||
return async (incoming, outgoing) => {
|
||||
let res, req;
|
||||
try {
|
||||
req = newRequest(incoming, options.hostname);
|
||||
let incomingEnded = !autoCleanupIncoming || incoming.method === "GET" || incoming.method === "HEAD";
|
||||
if (!incomingEnded) {
|
||||
;
|
||||
incoming[wrapBodyStream] = true;
|
||||
incoming.on("end", () => {
|
||||
incomingEnded = true;
|
||||
});
|
||||
if (incoming instanceof Http2ServerRequest2) {
|
||||
;
|
||||
outgoing[outgoingEnded] = () => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
incoming.destroy();
|
||||
outgoing.destroy();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
outgoing.on("close", () => {
|
||||
const abortController = req[abortControllerKey];
|
||||
if (abortController) {
|
||||
if (incoming.errored) {
|
||||
req[abortControllerKey].abort(incoming.errored.toString());
|
||||
} else if (!outgoing.writableFinished) {
|
||||
req[abortControllerKey].abort("Client connection prematurely closed.");
|
||||
}
|
||||
}
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
if (!incomingEnded) {
|
||||
setTimeout(() => {
|
||||
incoming.destroy();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
res = fetchCallback(req, { incoming, outgoing });
|
||||
if (cacheKey in res) {
|
||||
return responseViaCache(res, outgoing);
|
||||
}
|
||||
} catch (e) {
|
||||
if (!res) {
|
||||
if (options.errorHandler) {
|
||||
res = await options.errorHandler(req ? e : toRequestError(e));
|
||||
if (!res) {
|
||||
return;
|
||||
}
|
||||
} else if (!req) {
|
||||
res = handleRequestError();
|
||||
} else {
|
||||
res = handleFetchError(e);
|
||||
}
|
||||
} else {
|
||||
return handleResponseError(e, outgoing);
|
||||
}
|
||||
}
|
||||
try {
|
||||
return await responseViaResponseObject(res, outgoing, options);
|
||||
} catch (e) {
|
||||
return handleResponseError(e, outgoing);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
// src/vercel.ts
|
||||
var handle = (app) => {
|
||||
return getRequestListener(app.fetch);
|
||||
};
|
||||
export {
|
||||
handle
|
||||
};
|
||||
103
projects/stt-mcp/node_modules/@hono/node-server/package.json
generated
vendored
Normal file
103
projects/stt-mcp/node_modules/@hono/node-server/package.json
generated
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
{
|
||||
"name": "@hono/node-server",
|
||||
"version": "1.19.11",
|
||||
"description": "Node.js Adapter for Hono",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./dist/index.d.ts",
|
||||
"require": "./dist/index.js",
|
||||
"import": "./dist/index.mjs"
|
||||
},
|
||||
"./serve-static": {
|
||||
"types": "./dist/serve-static.d.ts",
|
||||
"require": "./dist/serve-static.js",
|
||||
"import": "./dist/serve-static.mjs"
|
||||
},
|
||||
"./vercel": {
|
||||
"types": "./dist/vercel.d.ts",
|
||||
"require": "./dist/vercel.js",
|
||||
"import": "./dist/vercel.mjs"
|
||||
},
|
||||
"./utils/*": {
|
||||
"types": "./dist/utils/*.d.ts",
|
||||
"require": "./dist/utils/*.js",
|
||||
"import": "./dist/utils/*.mjs"
|
||||
},
|
||||
"./conninfo": {
|
||||
"types": "./dist/conninfo.d.ts",
|
||||
"require": "./dist/conninfo.js",
|
||||
"import": "./dist/conninfo.mjs"
|
||||
}
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
".": [
|
||||
"./dist/index.d.ts"
|
||||
],
|
||||
"serve-static": [
|
||||
"./dist/serve-static.d.ts"
|
||||
],
|
||||
"vercel": [
|
||||
"./dist/vercel.d.ts"
|
||||
],
|
||||
"utils/*": [
|
||||
"./dist/utils/*.d.ts"
|
||||
],
|
||||
"conninfo": [
|
||||
"./dist/conninfo.d.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"test": "node --expose-gc node_modules/jest/bin/jest.js",
|
||||
"build": "tsup --external hono",
|
||||
"watch": "tsup --watch",
|
||||
"postbuild": "publint",
|
||||
"prerelease": "bun run build && bun run test",
|
||||
"release": "np",
|
||||
"lint": "eslint src test",
|
||||
"lint:fix": "eslint src test --fix",
|
||||
"format": "prettier --check \"src/**/*.{js,ts}\" \"test/**/*.{js,ts}\"",
|
||||
"format:fix": "prettier --write \"src/**/*.{js,ts}\" \"test/**/*.{js,ts}\""
|
||||
},
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/honojs/node-server.git"
|
||||
},
|
||||
"homepage": "https://github.com/honojs/node-server",
|
||||
"author": "Yusuke Wada <yusuke@kamawada.com> (https://github.com/yusukebe)",
|
||||
"publishConfig": {
|
||||
"registry": "https://registry.npmjs.org",
|
||||
"access": "public"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.14.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hono/eslint-config": "^1.0.1",
|
||||
"@types/jest": "^29.5.3",
|
||||
"@types/node": "^20.10.0",
|
||||
"@types/supertest": "^2.0.12",
|
||||
"@whatwg-node/fetch": "^0.9.14",
|
||||
"eslint": "^9.10.0",
|
||||
"hono": "^4.4.10",
|
||||
"jest": "^29.6.1",
|
||||
"np": "^7.7.0",
|
||||
"prettier": "^3.2.4",
|
||||
"publint": "^0.1.16",
|
||||
"supertest": "^6.3.3",
|
||||
"ts-jest": "^29.1.1",
|
||||
"tsup": "^7.2.0",
|
||||
"typescript": "^5.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"hono": "^4"
|
||||
},
|
||||
"packageManager": "bun@1.2.20"
|
||||
}
|
||||
21
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/LICENSE
generated
vendored
Normal file
21
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 Anthropic, PBC
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
172
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/README.md
generated
vendored
Normal file
172
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/README.md
generated
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
# MCP TypeScript SDK [](https://www.npmjs.com/package/@modelcontextprotocol/sdk) [](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/LICENSE)
|
||||
|
||||
<details>
|
||||
<summary>Table of Contents</summary>
|
||||
|
||||
- [Overview](#overview)
|
||||
- [Installation](#installation)
|
||||
- [Quick Start](#quick-start)
|
||||
- [Core Concepts](#core-concepts)
|
||||
- [Examples](#examples)
|
||||
- [Documentation](#documentation)
|
||||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
|
||||
</details>
|
||||
|
||||
## Overview
|
||||
|
||||
The Model Context Protocol allows applications to provide context for LLMs in a standardized way, separating the concerns of providing context from the actual LLM interaction. This TypeScript SDK implements
|
||||
[the full MCP specification](https://modelcontextprotocol.io/specification/draft), making it easy to:
|
||||
|
||||
- Create MCP servers that expose resources, prompts and tools
|
||||
- Build MCP clients that can connect to any MCP server
|
||||
- Use standard transports like stdio and Streamable HTTP
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @modelcontextprotocol/sdk zod
|
||||
```
|
||||
|
||||
This SDK has a **required peer dependency** on `zod` for schema validation. The SDK internally imports from `zod/v4`, but maintains backwards compatibility with projects using Zod v3.25 or later. You can use either API in your code by importing from `zod/v3` or `zod/v4`:
|
||||
|
||||
## Quick Start
|
||||
|
||||
To see the SDK in action end-to-end, start from the runnable examples in `src/examples`:
|
||||
|
||||
1. **Install dependencies** (from the SDK repo root):
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
2. **Run the example Streamable HTTP server**:
|
||||
|
||||
```bash
|
||||
npx tsx src/examples/server/simpleStreamableHttp.ts
|
||||
```
|
||||
|
||||
3. **Run the interactive client in another terminal**:
|
||||
|
||||
```bash
|
||||
npx tsx src/examples/client/simpleStreamableHttp.ts
|
||||
```
|
||||
|
||||
This pair of examples demonstrates tools, resources, prompts, sampling, elicitation, tasks and logging. For a guided walkthrough and variations (stateless servers, JSON-only responses, SSE compatibility, OAuth, etc.), see [docs/server.md](docs/server.md) and
|
||||
[docs/client.md](docs/client.md).
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### Servers and transports
|
||||
|
||||
An MCP server is typically created with `McpServer` and connected to a transport such as Streamable HTTP or stdio. The SDK supports:
|
||||
|
||||
- **Streamable HTTP** for remote servers (recommended).
|
||||
- **HTTP + SSE** for backwards compatibility only.
|
||||
- **stdio** for local, process-spawned integrations.
|
||||
|
||||
Runnable server examples live under `src/examples/server` and are documented in [docs/server.md](docs/server.md).
|
||||
|
||||
### Tools, resources, prompts
|
||||
|
||||
- **Tools** let LLMs ask your server to take actions (computation, side effects, network calls).
|
||||
- **Resources** expose read-only data that clients can surface to users or models.
|
||||
- **Prompts** are reusable templates that help users talk to models in a consistent way.
|
||||
|
||||
The detailed APIs, including `ResourceTemplate`, completions, and display-name metadata, are covered in [docs/server.md](docs/server.md#tools-resources-and-prompts), with runnable implementations in [`simpleStreamableHttp.ts`](src/examples/server/simpleStreamableHttp.ts).
|
||||
|
||||
### Capabilities: sampling, elicitation, and tasks
|
||||
|
||||
The SDK includes higher-level capabilities for richer workflows:
|
||||
|
||||
- **Sampling**: server-side tools can ask connected clients to run LLM completions.
|
||||
- **Form elicitation**: tools can request non-sensitive input via structured forms.
|
||||
- **URL elicitation**: servers can ask users to complete secure flows in a browser (e.g., API key entry, payments, OAuth).
|
||||
- **Tasks (experimental)**: long-running tool calls can be turned into tasks that you poll or resume later.
|
||||
|
||||
Conceptual overviews and links to runnable examples are in:
|
||||
|
||||
- [docs/capabilities.md](docs/capabilities.md)
|
||||
|
||||
Key example servers include:
|
||||
|
||||
- [`toolWithSampleServer.ts`](src/examples/server/toolWithSampleServer.ts)
|
||||
- [`elicitationFormExample.ts`](src/examples/server/elicitationFormExample.ts)
|
||||
- [`elicitationUrlExample.ts`](src/examples/server/elicitationUrlExample.ts)
|
||||
|
||||
### Clients
|
||||
|
||||
The high-level `Client` class connects to MCP servers over different transports and exposes helpers like `listTools`, `callTool`, `listResources`, `readResource`, `listPrompts`, and `getPrompt`.
|
||||
|
||||
Runnable clients live under `src/examples/client` and are described in [docs/client.md](docs/client.md), including:
|
||||
|
||||
- Interactive Streamable HTTP client ([`simpleStreamableHttp.ts`](src/examples/client/simpleStreamableHttp.ts))
|
||||
- Streamable HTTP client with SSE fallback ([`streamableHttpWithSseFallbackClient.ts`](src/examples/client/streamableHttpWithSseFallbackClient.ts))
|
||||
- OAuth-enabled clients and polling/parallel examples
|
||||
|
||||
### Node.js Web Crypto (globalThis.crypto) compatibility
|
||||
|
||||
Some parts of the SDK (for example, JWT-based client authentication in `auth-extensions.ts` via `jose`) rely on the Web Crypto API exposed as `globalThis.crypto`.
|
||||
|
||||
See [docs/faq.md](docs/faq.md) for details on supported Node.js versions and how to polyfill `globalThis.crypto` when running on older Node.js runtimes.
|
||||
|
||||
## Examples
|
||||
|
||||
The SDK ships runnable examples under `src/examples`. Use these tables to find the scenario you care about and jump straight to the corresponding code and docs.
|
||||
|
||||
### Server examples
|
||||
|
||||
| Scenario | Description | Example file(s) | Related docs |
|
||||
| --------------------------------------------------- | ------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
|
||||
| Streamable HTTP server (stateful) | Feature-rich server with tools, resources, prompts, logging, tasks, sampling, and optional OAuth. | [`simpleStreamableHttp.ts`](src/examples/server/simpleStreamableHttp.ts) | [`server.md`](docs/server.md), [`capabilities.md`](docs/capabilities.md) |
|
||||
| Streamable HTTP server (stateless) | No session tracking; good for simple API-style servers. | [`simpleStatelessStreamableHttp.ts`](src/examples/server/simpleStatelessStreamableHttp.ts) | [`server.md`](docs/server.md) |
|
||||
| JSON response mode (no SSE) | Streamable HTTP with JSON responses only and limited notifications. | [`jsonResponseStreamableHttp.ts`](src/examples/server/jsonResponseStreamableHttp.ts) | [`server.md`](docs/server.md) |
|
||||
| Server notifications over Streamable HTTP | Demonstrates server-initiated notifications using SSE with Streamable HTTP. | [`standaloneSseWithGetStreamableHttp.ts`](src/examples/server/standaloneSseWithGetStreamableHttp.ts) | [`server.md`](docs/server.md) |
|
||||
| Deprecated HTTP+SSE server | Legacy HTTP+SSE transport for backwards-compatibility testing. | [`simpleSseServer.ts`](src/examples/server/simpleSseServer.ts) | [`server.md`](docs/server.md) |
|
||||
| Backwards-compatible server (Streamable HTTP + SSE) | Single server that supports both Streamable HTTP and legacy SSE clients. | [`sseAndStreamableHttpCompatibleServer.ts`](src/examples/server/sseAndStreamableHttpCompatibleServer.ts) | [`server.md`](docs/server.md) |
|
||||
| Form elicitation server | Uses form elicitation to collect non-sensitive user input. | [`elicitationFormExample.ts`](src/examples/server/elicitationFormExample.ts) | [`capabilities.md`](docs/capabilities.md#elicitation) |
|
||||
| URL elicitation server | Demonstrates URL-mode elicitation in an OAuth-protected server. | [`elicitationUrlExample.ts`](src/examples/server/elicitationUrlExample.ts) | [`capabilities.md`](docs/capabilities.md#elicitation) |
|
||||
| Sampling and tasks server | Combines tools, logging, sampling, and experimental task-based execution. | [`toolWithSampleServer.ts`](src/examples/server/toolWithSampleServer.ts) | [`capabilities.md`](docs/capabilities.md) |
|
||||
| OAuth demo authorization server | In-memory OAuth provider used with the example servers. | [`demoInMemoryOAuthProvider.ts`](src/examples/server/demoInMemoryOAuthProvider.ts) | [`server.md`](docs/server.md) |
|
||||
|
||||
### Client examples
|
||||
|
||||
| Scenario | Description | Example file(s) | Related docs |
|
||||
| --------------------------------------------------- | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
|
||||
| Interactive Streamable HTTP client | CLI client that exercises tools, resources, prompts, elicitation, and tasks. | [`simpleStreamableHttp.ts`](src/examples/client/simpleStreamableHttp.ts) | [`client.md`](docs/client.md) |
|
||||
| Backwards-compatible client (Streamable HTTP → SSE) | Tries Streamable HTTP first, then falls back to SSE on 4xx responses. | [`streamableHttpWithSseFallbackClient.ts`](src/examples/client/streamableHttpWithSseFallbackClient.ts) | [`client.md`](docs/client.md), [`server.md`](docs/server.md) |
|
||||
| SSE polling client | Polls a legacy SSE server and demonstrates notification handling. | [`ssePollingClient.ts`](src/examples/client/ssePollingClient.ts) | [`client.md`](docs/client.md) |
|
||||
| Parallel tool calls client | Shows how to run multiple tool calls in parallel. | [`parallelToolCallsClient.ts`](src/examples/client/parallelToolCallsClient.ts) | [`client.md`](docs/client.md) |
|
||||
| Multiple clients in parallel | Demonstrates connecting multiple clients concurrently to the same server. | [`multipleClientsParallel.ts`](src/examples/client/multipleClientsParallel.ts) | [`client.md`](docs/client.md) |
|
||||
| OAuth clients | Examples of client_credentials (basic and private_key_jwt) and reusable providers. | [`simpleOAuthClient.ts`](src/examples/client/simpleOAuthClient.ts), [`simpleOAuthClientProvider.ts`](src/examples/client/simpleOAuthClientProvider.ts), [`simpleClientCredentials.ts`](src/examples/client/simpleClientCredentials.ts) | [`client.md`](docs/client.md) |
|
||||
| URL elicitation client | Works with the URL elicitation server to drive secure browser flows. | [`elicitationUrlExample.ts`](src/examples/client/elicitationUrlExample.ts) | [`capabilities.md`](docs/capabilities.md#elicitation) |
|
||||
|
||||
Shared utilities:
|
||||
|
||||
- In-memory event store for resumability: [`inMemoryEventStore.ts`](src/examples/shared/inMemoryEventStore.ts) (see [`server.md`](docs/server.md)).
|
||||
|
||||
For more details on how to run these examples (including recommended commands and deployment diagrams), see `src/examples/README.md`.
|
||||
|
||||
## Documentation
|
||||
|
||||
- Local SDK docs:
|
||||
- [docs/server.md](docs/server.md) – building and running MCP servers, transports, tools/resources/prompts, CORS, DNS rebinding, and multi-node deployment.
|
||||
- [docs/client.md](docs/client.md) – using the high-level client, transports, backwards compatibility, and OAuth helpers.
|
||||
- [docs/capabilities.md](docs/capabilities.md) – sampling, elicitation (form and URL), and experimental task-based execution.
|
||||
- [docs/protocol.md](docs/protocol.md) – protocol features: ping, progress, cancellation, pagination, capability negotiation, and JSON Schema.
|
||||
- [docs/faq.md](docs/faq.md) – environment and troubleshooting FAQs (including Node.js Web Crypto support).
|
||||
- External references:
|
||||
- [V1 API reference](https://modelcontextprotocol.github.io/typescript-sdk/)
|
||||
- [V2 API reference](https://modelcontextprotocol.github.io/typescript-sdk/v2/)
|
||||
- [Model Context Protocol documentation](https://modelcontextprotocol.io)
|
||||
- [MCP Specification](https://spec.modelcontextprotocol.io)
|
||||
- [Example Servers](https://github.com/modelcontextprotocol/servers)
|
||||
|
||||
## Contributing
|
||||
|
||||
Issues and pull requests are welcome on GitHub at <https://github.com/modelcontextprotocol/typescript-sdk>.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License—see the [LICENSE](LICENSE) file for details.
|
||||
190
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth-extensions.d.ts
generated
vendored
Normal file
190
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth-extensions.d.ts
generated
vendored
Normal file
@@ -0,0 +1,190 @@
|
||||
/**
|
||||
* OAuth provider extensions for specialized authentication flows.
|
||||
*
|
||||
* This module provides ready-to-use OAuthClientProvider implementations
|
||||
* for common machine-to-machine authentication scenarios.
|
||||
*/
|
||||
import { OAuthClientInformation, OAuthClientMetadata, OAuthTokens } from '../shared/auth.js';
|
||||
import { AddClientAuthentication, OAuthClientProvider } from './auth.js';
|
||||
/**
|
||||
* Helper to produce a private_key_jwt client authentication function.
|
||||
*
|
||||
* Usage:
|
||||
* const addClientAuth = createPrivateKeyJwtAuth({ issuer, subject, privateKey, alg, audience? });
|
||||
* // pass addClientAuth as provider.addClientAuthentication implementation
|
||||
*/
|
||||
export declare function createPrivateKeyJwtAuth(options: {
|
||||
issuer: string;
|
||||
subject: string;
|
||||
privateKey: string | Uint8Array | Record<string, unknown>;
|
||||
alg: string;
|
||||
audience?: string | URL;
|
||||
lifetimeSeconds?: number;
|
||||
claims?: Record<string, unknown>;
|
||||
}): AddClientAuthentication;
|
||||
/**
|
||||
* Options for creating a ClientCredentialsProvider.
|
||||
*/
|
||||
export interface ClientCredentialsProviderOptions {
|
||||
/**
|
||||
* The client_id for this OAuth client.
|
||||
*/
|
||||
clientId: string;
|
||||
/**
|
||||
* The client_secret for client_secret_basic authentication.
|
||||
*/
|
||||
clientSecret: string;
|
||||
/**
|
||||
* Optional client name for metadata.
|
||||
*/
|
||||
clientName?: string;
|
||||
/**
|
||||
* Space-separated scopes values requested by the client.
|
||||
*/
|
||||
scope?: string;
|
||||
}
|
||||
/**
|
||||
* OAuth provider for client_credentials grant with client_secret_basic authentication.
|
||||
*
|
||||
* This provider is designed for machine-to-machine authentication where
|
||||
* the client authenticates using a client_id and client_secret.
|
||||
*
|
||||
* @example
|
||||
* const provider = new ClientCredentialsProvider({
|
||||
* clientId: 'my-client',
|
||||
* clientSecret: 'my-secret'
|
||||
* });
|
||||
*
|
||||
* const transport = new StreamableHTTPClientTransport(serverUrl, {
|
||||
* authProvider: provider
|
||||
* });
|
||||
*/
|
||||
export declare class ClientCredentialsProvider implements OAuthClientProvider {
|
||||
private _tokens?;
|
||||
private _clientInfo;
|
||||
private _clientMetadata;
|
||||
constructor(options: ClientCredentialsProviderOptions);
|
||||
get redirectUrl(): undefined;
|
||||
get clientMetadata(): OAuthClientMetadata;
|
||||
clientInformation(): OAuthClientInformation;
|
||||
saveClientInformation(info: OAuthClientInformation): void;
|
||||
tokens(): OAuthTokens | undefined;
|
||||
saveTokens(tokens: OAuthTokens): void;
|
||||
redirectToAuthorization(): void;
|
||||
saveCodeVerifier(): void;
|
||||
codeVerifier(): string;
|
||||
prepareTokenRequest(scope?: string): URLSearchParams;
|
||||
}
|
||||
/**
|
||||
* Options for creating a PrivateKeyJwtProvider.
|
||||
*/
|
||||
export interface PrivateKeyJwtProviderOptions {
|
||||
/**
|
||||
* The client_id for this OAuth client.
|
||||
*/
|
||||
clientId: string;
|
||||
/**
|
||||
* The private key for signing JWT assertions.
|
||||
* Can be a PEM string, Uint8Array, or JWK object.
|
||||
*/
|
||||
privateKey: string | Uint8Array | Record<string, unknown>;
|
||||
/**
|
||||
* The algorithm to use for signing (e.g., 'RS256', 'ES256').
|
||||
*/
|
||||
algorithm: string;
|
||||
/**
|
||||
* Optional client name for metadata.
|
||||
*/
|
||||
clientName?: string;
|
||||
/**
|
||||
* Optional JWT lifetime in seconds (default: 300).
|
||||
*/
|
||||
jwtLifetimeSeconds?: number;
|
||||
/**
|
||||
* Space-separated scopes values requested by the client.
|
||||
*/
|
||||
scope?: string;
|
||||
}
|
||||
/**
|
||||
* OAuth provider for client_credentials grant with private_key_jwt authentication.
|
||||
*
|
||||
* This provider is designed for machine-to-machine authentication where
|
||||
* the client authenticates using a signed JWT assertion (RFC 7523 Section 2.2).
|
||||
*
|
||||
* @example
|
||||
* const provider = new PrivateKeyJwtProvider({
|
||||
* clientId: 'my-client',
|
||||
* privateKey: pemEncodedPrivateKey,
|
||||
* algorithm: 'RS256'
|
||||
* });
|
||||
*
|
||||
* const transport = new StreamableHTTPClientTransport(serverUrl, {
|
||||
* authProvider: provider
|
||||
* });
|
||||
*/
|
||||
export declare class PrivateKeyJwtProvider implements OAuthClientProvider {
|
||||
private _tokens?;
|
||||
private _clientInfo;
|
||||
private _clientMetadata;
|
||||
addClientAuthentication: AddClientAuthentication;
|
||||
constructor(options: PrivateKeyJwtProviderOptions);
|
||||
get redirectUrl(): undefined;
|
||||
get clientMetadata(): OAuthClientMetadata;
|
||||
clientInformation(): OAuthClientInformation;
|
||||
saveClientInformation(info: OAuthClientInformation): void;
|
||||
tokens(): OAuthTokens | undefined;
|
||||
saveTokens(tokens: OAuthTokens): void;
|
||||
redirectToAuthorization(): void;
|
||||
saveCodeVerifier(): void;
|
||||
codeVerifier(): string;
|
||||
prepareTokenRequest(scope?: string): URLSearchParams;
|
||||
}
|
||||
/**
|
||||
* Options for creating a StaticPrivateKeyJwtProvider.
|
||||
*/
|
||||
export interface StaticPrivateKeyJwtProviderOptions {
|
||||
/**
|
||||
* The client_id for this OAuth client.
|
||||
*/
|
||||
clientId: string;
|
||||
/**
|
||||
* A pre-built JWT client assertion to use for authentication.
|
||||
*
|
||||
* This token should already contain the appropriate claims
|
||||
* (iss, sub, aud, exp, etc.) and be signed by the client's key.
|
||||
*/
|
||||
jwtBearerAssertion: string;
|
||||
/**
|
||||
* Optional client name for metadata.
|
||||
*/
|
||||
clientName?: string;
|
||||
/**
|
||||
* Space-separated scopes values requested by the client.
|
||||
*/
|
||||
scope?: string;
|
||||
}
|
||||
/**
|
||||
* OAuth provider for client_credentials grant with a static private_key_jwt assertion.
|
||||
*
|
||||
* This provider mirrors {@link PrivateKeyJwtProvider} but instead of constructing and
|
||||
* signing a JWT on each request, it accepts a pre-built JWT assertion string and
|
||||
* uses it directly for authentication.
|
||||
*/
|
||||
export declare class StaticPrivateKeyJwtProvider implements OAuthClientProvider {
|
||||
private _tokens?;
|
||||
private _clientInfo;
|
||||
private _clientMetadata;
|
||||
addClientAuthentication: AddClientAuthentication;
|
||||
constructor(options: StaticPrivateKeyJwtProviderOptions);
|
||||
get redirectUrl(): undefined;
|
||||
get clientMetadata(): OAuthClientMetadata;
|
||||
clientInformation(): OAuthClientInformation;
|
||||
saveClientInformation(info: OAuthClientInformation): void;
|
||||
tokens(): OAuthTokens | undefined;
|
||||
saveTokens(tokens: OAuthTokens): void;
|
||||
redirectToAuthorization(): void;
|
||||
saveCodeVerifier(): void;
|
||||
codeVerifier(): string;
|
||||
prepareTokenRequest(scope?: string): URLSearchParams;
|
||||
}
|
||||
//# sourceMappingURL=auth-extensions.d.ts.map
|
||||
1
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth-extensions.d.ts.map
generated
vendored
Normal file
1
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth-extensions.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth-extensions.d.ts","sourceRoot":"","sources":["../../../src/client/auth-extensions.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC7F,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEzE;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC1D,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,GAAG,uBAAuB,CAgE1B;AAED;;GAEG;AACH,MAAM,WAAW,gCAAgC;IAC7C;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,yBAA0B,YAAW,mBAAmB;IACjE,OAAO,CAAC,OAAO,CAAC,CAAc;IAC9B,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,eAAe,CAAsB;gBAEjC,OAAO,EAAE,gCAAgC;IAcrD,IAAI,WAAW,IAAI,SAAS,CAE3B;IAED,IAAI,cAAc,IAAI,mBAAmB,CAExC;IAED,iBAAiB,IAAI,sBAAsB;IAI3C,qBAAqB,CAAC,IAAI,EAAE,sBAAsB,GAAG,IAAI;IAIzD,MAAM,IAAI,WAAW,GAAG,SAAS;IAIjC,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAIrC,uBAAuB,IAAI,IAAI;IAI/B,gBAAgB,IAAI,IAAI;IAIxB,YAAY,IAAI,MAAM;IAItB,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,eAAe;CAKvD;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IACzC;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE1D;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,qBAAsB,YAAW,mBAAmB;IAC7D,OAAO,CAAC,OAAO,CAAC,CAAc;IAC9B,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,eAAe,CAAsB;IAC7C,uBAAuB,EAAE,uBAAuB,CAAC;gBAErC,OAAO,EAAE,4BAA4B;IAoBjD,IAAI,WAAW,IAAI,SAAS,CAE3B;IAED,IAAI,cAAc,IAAI,mBAAmB,CAExC;IAED,iBAAiB,IAAI,sBAAsB;IAI3C,qBAAqB,CAAC,IAAI,EAAE,sBAAsB,GAAG,IAAI;IAIzD,MAAM,IAAI,WAAW,GAAG,SAAS;IAIjC,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAIrC,uBAAuB,IAAI,IAAI;IAI/B,gBAAgB,IAAI,IAAI;IAIxB,YAAY,IAAI,MAAM;IAItB,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,eAAe;CAKvD;AAED;;GAEG;AACH,MAAM,WAAW,kCAAkC;IAC/C;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;;OAKG;IACH,kBAAkB,EAAE,MAAM,CAAC;IAE3B;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,qBAAa,2BAA4B,YAAW,mBAAmB;IACnE,OAAO,CAAC,OAAO,CAAC,CAAc;IAC9B,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,eAAe,CAAsB;IAC7C,uBAAuB,EAAE,uBAAuB,CAAC;gBAErC,OAAO,EAAE,kCAAkC;IAmBvD,IAAI,WAAW,IAAI,SAAS,CAE3B;IAED,IAAI,cAAc,IAAI,mBAAmB,CAExC;IAED,iBAAiB,IAAI,sBAAsB;IAI3C,qBAAqB,CAAC,IAAI,EAAE,sBAAsB,GAAG,IAAI;IAIzD,MAAM,IAAI,WAAW,GAAG,SAAS;IAIjC,UAAU,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI;IAIrC,uBAAuB,IAAI,IAAI;IAI/B,gBAAgB,IAAI,IAAI;IAIxB,YAAY,IAAI,MAAM;IAItB,mBAAmB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,eAAe;CAKvD"}
|
||||
299
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth-extensions.js
generated
vendored
Normal file
299
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth-extensions.js
generated
vendored
Normal file
@@ -0,0 +1,299 @@
|
||||
"use strict";
|
||||
/**
|
||||
* OAuth provider extensions for specialized authentication flows.
|
||||
*
|
||||
* This module provides ready-to-use OAuthClientProvider implementations
|
||||
* for common machine-to-machine authentication scenarios.
|
||||
*/
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.StaticPrivateKeyJwtProvider = exports.PrivateKeyJwtProvider = exports.ClientCredentialsProvider = void 0;
|
||||
exports.createPrivateKeyJwtAuth = createPrivateKeyJwtAuth;
|
||||
/**
|
||||
* Helper to produce a private_key_jwt client authentication function.
|
||||
*
|
||||
* Usage:
|
||||
* const addClientAuth = createPrivateKeyJwtAuth({ issuer, subject, privateKey, alg, audience? });
|
||||
* // pass addClientAuth as provider.addClientAuthentication implementation
|
||||
*/
|
||||
function createPrivateKeyJwtAuth(options) {
|
||||
return async (_headers, params, url, metadata) => {
|
||||
// Lazy import to avoid heavy dependency unless used
|
||||
if (typeof globalThis.crypto === 'undefined') {
|
||||
throw new TypeError('crypto is not available, please ensure you add have Web Crypto API support for older Node.js versions (see https://github.com/modelcontextprotocol/typescript-sdk#nodejs-web-crypto-globalthiscrypto-compatibility)');
|
||||
}
|
||||
const jose = await Promise.resolve().then(() => __importStar(require('jose')));
|
||||
const audience = String(options.audience ?? metadata?.issuer ?? url);
|
||||
const lifetimeSeconds = options.lifetimeSeconds ?? 300;
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const jti = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
||||
const baseClaims = {
|
||||
iss: options.issuer,
|
||||
sub: options.subject,
|
||||
aud: audience,
|
||||
exp: now + lifetimeSeconds,
|
||||
iat: now,
|
||||
jti
|
||||
};
|
||||
const claims = options.claims ? { ...baseClaims, ...options.claims } : baseClaims;
|
||||
// Import key for the requested algorithm
|
||||
const alg = options.alg;
|
||||
let key;
|
||||
if (typeof options.privateKey === 'string') {
|
||||
if (alg.startsWith('RS') || alg.startsWith('ES') || alg.startsWith('PS')) {
|
||||
key = await jose.importPKCS8(options.privateKey, alg);
|
||||
}
|
||||
else if (alg.startsWith('HS')) {
|
||||
key = new TextEncoder().encode(options.privateKey);
|
||||
}
|
||||
else {
|
||||
throw new Error(`Unsupported algorithm ${alg}`);
|
||||
}
|
||||
}
|
||||
else if (options.privateKey instanceof Uint8Array) {
|
||||
if (alg.startsWith('HS')) {
|
||||
key = options.privateKey;
|
||||
}
|
||||
else {
|
||||
// Assume PKCS#8 DER in Uint8Array for asymmetric algorithms
|
||||
key = await jose.importPKCS8(new TextDecoder().decode(options.privateKey), alg);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Treat as JWK
|
||||
key = await jose.importJWK(options.privateKey, alg);
|
||||
}
|
||||
// Sign JWT
|
||||
const assertion = await new jose.SignJWT(claims)
|
||||
.setProtectedHeader({ alg, typ: 'JWT' })
|
||||
.setIssuer(options.issuer)
|
||||
.setSubject(options.subject)
|
||||
.setAudience(audience)
|
||||
.setIssuedAt(now)
|
||||
.setExpirationTime(now + lifetimeSeconds)
|
||||
.setJti(jti)
|
||||
.sign(key);
|
||||
params.set('client_assertion', assertion);
|
||||
params.set('client_assertion_type', 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer');
|
||||
};
|
||||
}
|
||||
/**
|
||||
* OAuth provider for client_credentials grant with client_secret_basic authentication.
|
||||
*
|
||||
* This provider is designed for machine-to-machine authentication where
|
||||
* the client authenticates using a client_id and client_secret.
|
||||
*
|
||||
* @example
|
||||
* const provider = new ClientCredentialsProvider({
|
||||
* clientId: 'my-client',
|
||||
* clientSecret: 'my-secret'
|
||||
* });
|
||||
*
|
||||
* const transport = new StreamableHTTPClientTransport(serverUrl, {
|
||||
* authProvider: provider
|
||||
* });
|
||||
*/
|
||||
class ClientCredentialsProvider {
|
||||
constructor(options) {
|
||||
this._clientInfo = {
|
||||
client_id: options.clientId,
|
||||
client_secret: options.clientSecret
|
||||
};
|
||||
this._clientMetadata = {
|
||||
client_name: options.clientName ?? 'client-credentials-client',
|
||||
redirect_uris: [],
|
||||
grant_types: ['client_credentials'],
|
||||
token_endpoint_auth_method: 'client_secret_basic',
|
||||
scope: options.scope
|
||||
};
|
||||
}
|
||||
get redirectUrl() {
|
||||
return undefined;
|
||||
}
|
||||
get clientMetadata() {
|
||||
return this._clientMetadata;
|
||||
}
|
||||
clientInformation() {
|
||||
return this._clientInfo;
|
||||
}
|
||||
saveClientInformation(info) {
|
||||
this._clientInfo = info;
|
||||
}
|
||||
tokens() {
|
||||
return this._tokens;
|
||||
}
|
||||
saveTokens(tokens) {
|
||||
this._tokens = tokens;
|
||||
}
|
||||
redirectToAuthorization() {
|
||||
throw new Error('redirectToAuthorization is not used for client_credentials flow');
|
||||
}
|
||||
saveCodeVerifier() {
|
||||
// Not used for client_credentials
|
||||
}
|
||||
codeVerifier() {
|
||||
throw new Error('codeVerifier is not used for client_credentials flow');
|
||||
}
|
||||
prepareTokenRequest(scope) {
|
||||
const params = new URLSearchParams({ grant_type: 'client_credentials' });
|
||||
if (scope)
|
||||
params.set('scope', scope);
|
||||
return params;
|
||||
}
|
||||
}
|
||||
exports.ClientCredentialsProvider = ClientCredentialsProvider;
|
||||
/**
|
||||
* OAuth provider for client_credentials grant with private_key_jwt authentication.
|
||||
*
|
||||
* This provider is designed for machine-to-machine authentication where
|
||||
* the client authenticates using a signed JWT assertion (RFC 7523 Section 2.2).
|
||||
*
|
||||
* @example
|
||||
* const provider = new PrivateKeyJwtProvider({
|
||||
* clientId: 'my-client',
|
||||
* privateKey: pemEncodedPrivateKey,
|
||||
* algorithm: 'RS256'
|
||||
* });
|
||||
*
|
||||
* const transport = new StreamableHTTPClientTransport(serverUrl, {
|
||||
* authProvider: provider
|
||||
* });
|
||||
*/
|
||||
class PrivateKeyJwtProvider {
|
||||
constructor(options) {
|
||||
this._clientInfo = {
|
||||
client_id: options.clientId
|
||||
};
|
||||
this._clientMetadata = {
|
||||
client_name: options.clientName ?? 'private-key-jwt-client',
|
||||
redirect_uris: [],
|
||||
grant_types: ['client_credentials'],
|
||||
token_endpoint_auth_method: 'private_key_jwt',
|
||||
scope: options.scope
|
||||
};
|
||||
this.addClientAuthentication = createPrivateKeyJwtAuth({
|
||||
issuer: options.clientId,
|
||||
subject: options.clientId,
|
||||
privateKey: options.privateKey,
|
||||
alg: options.algorithm,
|
||||
lifetimeSeconds: options.jwtLifetimeSeconds
|
||||
});
|
||||
}
|
||||
get redirectUrl() {
|
||||
return undefined;
|
||||
}
|
||||
get clientMetadata() {
|
||||
return this._clientMetadata;
|
||||
}
|
||||
clientInformation() {
|
||||
return this._clientInfo;
|
||||
}
|
||||
saveClientInformation(info) {
|
||||
this._clientInfo = info;
|
||||
}
|
||||
tokens() {
|
||||
return this._tokens;
|
||||
}
|
||||
saveTokens(tokens) {
|
||||
this._tokens = tokens;
|
||||
}
|
||||
redirectToAuthorization() {
|
||||
throw new Error('redirectToAuthorization is not used for client_credentials flow');
|
||||
}
|
||||
saveCodeVerifier() {
|
||||
// Not used for client_credentials
|
||||
}
|
||||
codeVerifier() {
|
||||
throw new Error('codeVerifier is not used for client_credentials flow');
|
||||
}
|
||||
prepareTokenRequest(scope) {
|
||||
const params = new URLSearchParams({ grant_type: 'client_credentials' });
|
||||
if (scope)
|
||||
params.set('scope', scope);
|
||||
return params;
|
||||
}
|
||||
}
|
||||
exports.PrivateKeyJwtProvider = PrivateKeyJwtProvider;
|
||||
/**
|
||||
* OAuth provider for client_credentials grant with a static private_key_jwt assertion.
|
||||
*
|
||||
* This provider mirrors {@link PrivateKeyJwtProvider} but instead of constructing and
|
||||
* signing a JWT on each request, it accepts a pre-built JWT assertion string and
|
||||
* uses it directly for authentication.
|
||||
*/
|
||||
class StaticPrivateKeyJwtProvider {
|
||||
constructor(options) {
|
||||
this._clientInfo = {
|
||||
client_id: options.clientId
|
||||
};
|
||||
this._clientMetadata = {
|
||||
client_name: options.clientName ?? 'static-private-key-jwt-client',
|
||||
redirect_uris: [],
|
||||
grant_types: ['client_credentials'],
|
||||
token_endpoint_auth_method: 'private_key_jwt',
|
||||
scope: options.scope
|
||||
};
|
||||
const assertion = options.jwtBearerAssertion;
|
||||
this.addClientAuthentication = async (_headers, params) => {
|
||||
params.set('client_assertion', assertion);
|
||||
params.set('client_assertion_type', 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer');
|
||||
};
|
||||
}
|
||||
get redirectUrl() {
|
||||
return undefined;
|
||||
}
|
||||
get clientMetadata() {
|
||||
return this._clientMetadata;
|
||||
}
|
||||
clientInformation() {
|
||||
return this._clientInfo;
|
||||
}
|
||||
saveClientInformation(info) {
|
||||
this._clientInfo = info;
|
||||
}
|
||||
tokens() {
|
||||
return this._tokens;
|
||||
}
|
||||
saveTokens(tokens) {
|
||||
this._tokens = tokens;
|
||||
}
|
||||
redirectToAuthorization() {
|
||||
throw new Error('redirectToAuthorization is not used for client_credentials flow');
|
||||
}
|
||||
saveCodeVerifier() {
|
||||
// Not used for client_credentials
|
||||
}
|
||||
codeVerifier() {
|
||||
throw new Error('codeVerifier is not used for client_credentials flow');
|
||||
}
|
||||
prepareTokenRequest(scope) {
|
||||
const params = new URLSearchParams({ grant_type: 'client_credentials' });
|
||||
if (scope)
|
||||
params.set('scope', scope);
|
||||
return params;
|
||||
}
|
||||
}
|
||||
exports.StaticPrivateKeyJwtProvider = StaticPrivateKeyJwtProvider;
|
||||
//# sourceMappingURL=auth-extensions.js.map
|
||||
1
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth-extensions.js.map
generated
vendored
Normal file
1
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth-extensions.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
451
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth.d.ts
generated
vendored
Normal file
451
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth.d.ts
generated
vendored
Normal file
@@ -0,0 +1,451 @@
|
||||
import { OAuthClientMetadata, OAuthClientInformationMixed, OAuthTokens, OAuthMetadata, OAuthClientInformationFull, OAuthProtectedResourceMetadata, AuthorizationServerMetadata } from '../shared/auth.js';
|
||||
import { OAuthError } from '../server/auth/errors.js';
|
||||
import { FetchLike } from '../shared/transport.js';
|
||||
/**
|
||||
* Function type for adding client authentication to token requests.
|
||||
*/
|
||||
export type AddClientAuthentication = (headers: Headers, params: URLSearchParams, url: string | URL, metadata?: AuthorizationServerMetadata) => void | Promise<void>;
|
||||
/**
|
||||
* Implements an end-to-end OAuth client to be used with one MCP server.
|
||||
*
|
||||
* This client relies upon a concept of an authorized "session," the exact
|
||||
* meaning of which is application-defined. Tokens, authorization codes, and
|
||||
* code verifiers should not cross different sessions.
|
||||
*/
|
||||
export interface OAuthClientProvider {
|
||||
/**
|
||||
* The URL to redirect the user agent to after authorization.
|
||||
* Return undefined for non-interactive flows that don't require user interaction
|
||||
* (e.g., client_credentials, jwt-bearer).
|
||||
*/
|
||||
get redirectUrl(): string | URL | undefined;
|
||||
/**
|
||||
* External URL the server should use to fetch client metadata document
|
||||
*/
|
||||
clientMetadataUrl?: string;
|
||||
/**
|
||||
* Metadata about this OAuth client.
|
||||
*/
|
||||
get clientMetadata(): OAuthClientMetadata;
|
||||
/**
|
||||
* Returns a OAuth2 state parameter.
|
||||
*/
|
||||
state?(): string | Promise<string>;
|
||||
/**
|
||||
* Loads information about this OAuth client, as registered already with the
|
||||
* server, or returns `undefined` if the client is not registered with the
|
||||
* server.
|
||||
*/
|
||||
clientInformation(): OAuthClientInformationMixed | undefined | Promise<OAuthClientInformationMixed | undefined>;
|
||||
/**
|
||||
* If implemented, this permits the OAuth client to dynamically register with
|
||||
* the server. Client information saved this way should later be read via
|
||||
* `clientInformation()`.
|
||||
*
|
||||
* This method is not required to be implemented if client information is
|
||||
* statically known (e.g., pre-registered).
|
||||
*/
|
||||
saveClientInformation?(clientInformation: OAuthClientInformationMixed): void | Promise<void>;
|
||||
/**
|
||||
* Loads any existing OAuth tokens for the current session, or returns
|
||||
* `undefined` if there are no saved tokens.
|
||||
*/
|
||||
tokens(): OAuthTokens | undefined | Promise<OAuthTokens | undefined>;
|
||||
/**
|
||||
* Stores new OAuth tokens for the current session, after a successful
|
||||
* authorization.
|
||||
*/
|
||||
saveTokens(tokens: OAuthTokens): void | Promise<void>;
|
||||
/**
|
||||
* Invoked to redirect the user agent to the given URL to begin the authorization flow.
|
||||
*/
|
||||
redirectToAuthorization(authorizationUrl: URL): void | Promise<void>;
|
||||
/**
|
||||
* Saves a PKCE code verifier for the current session, before redirecting to
|
||||
* the authorization flow.
|
||||
*/
|
||||
saveCodeVerifier(codeVerifier: string): void | Promise<void>;
|
||||
/**
|
||||
* Loads the PKCE code verifier for the current session, necessary to validate
|
||||
* the authorization result.
|
||||
*/
|
||||
codeVerifier(): string | Promise<string>;
|
||||
/**
|
||||
* Adds custom client authentication to OAuth token requests.
|
||||
*
|
||||
* This optional method allows implementations to customize how client credentials
|
||||
* are included in token exchange and refresh requests. When provided, this method
|
||||
* is called instead of the default authentication logic, giving full control over
|
||||
* the authentication mechanism.
|
||||
*
|
||||
* Common use cases include:
|
||||
* - Supporting authentication methods beyond the standard OAuth 2.0 methods
|
||||
* - Adding custom headers for proprietary authentication schemes
|
||||
* - Implementing client assertion-based authentication (e.g., JWT bearer tokens)
|
||||
*
|
||||
* @param headers - The request headers (can be modified to add authentication)
|
||||
* @param params - The request body parameters (can be modified to add credentials)
|
||||
* @param url - The token endpoint URL being called
|
||||
* @param metadata - Optional OAuth metadata for the server, which may include supported authentication methods
|
||||
*/
|
||||
addClientAuthentication?: AddClientAuthentication;
|
||||
/**
|
||||
* If defined, overrides the selection and validation of the
|
||||
* RFC 8707 Resource Indicator. If left undefined, default
|
||||
* validation behavior will be used.
|
||||
*
|
||||
* Implementations must verify the returned resource matches the MCP server.
|
||||
*/
|
||||
validateResourceURL?(serverUrl: string | URL, resource?: string): Promise<URL | undefined>;
|
||||
/**
|
||||
* If implemented, provides a way for the client to invalidate (e.g. delete) the specified
|
||||
* credentials, in the case where the server has indicated that they are no longer valid.
|
||||
* This avoids requiring the user to intervene manually.
|
||||
*/
|
||||
invalidateCredentials?(scope: 'all' | 'client' | 'tokens' | 'verifier' | 'discovery'): void | Promise<void>;
|
||||
/**
|
||||
* Prepares grant-specific parameters for a token request.
|
||||
*
|
||||
* This optional method allows providers to customize the token request based on
|
||||
* the grant type they support. When implemented, it returns the grant type and
|
||||
* any grant-specific parameters needed for the token exchange.
|
||||
*
|
||||
* If not implemented, the default behavior depends on the flow:
|
||||
* - For authorization code flow: uses code, code_verifier, and redirect_uri
|
||||
* - For client_credentials: detected via grant_types in clientMetadata
|
||||
*
|
||||
* @param scope - Optional scope to request
|
||||
* @returns Grant type and parameters, or undefined to use default behavior
|
||||
*
|
||||
* @example
|
||||
* // For client_credentials grant:
|
||||
* prepareTokenRequest(scope) {
|
||||
* return {
|
||||
* grantType: 'client_credentials',
|
||||
* params: scope ? { scope } : {}
|
||||
* };
|
||||
* }
|
||||
*
|
||||
* @example
|
||||
* // For authorization_code grant (default behavior):
|
||||
* async prepareTokenRequest() {
|
||||
* return {
|
||||
* grantType: 'authorization_code',
|
||||
* params: {
|
||||
* code: this.authorizationCode,
|
||||
* code_verifier: await this.codeVerifier(),
|
||||
* redirect_uri: String(this.redirectUrl)
|
||||
* }
|
||||
* };
|
||||
* }
|
||||
*/
|
||||
prepareTokenRequest?(scope?: string): URLSearchParams | Promise<URLSearchParams | undefined> | undefined;
|
||||
/**
|
||||
* Saves the OAuth discovery state after RFC 9728 and authorization server metadata
|
||||
* discovery. Providers can persist this state to avoid redundant discovery requests
|
||||
* on subsequent {@linkcode auth} calls.
|
||||
*
|
||||
* This state can also be provided out-of-band (e.g., from a previous session or
|
||||
* external configuration) to bootstrap the OAuth flow without discovery.
|
||||
*
|
||||
* Called by {@linkcode auth} after successful discovery.
|
||||
*/
|
||||
saveDiscoveryState?(state: OAuthDiscoveryState): void | Promise<void>;
|
||||
/**
|
||||
* Returns previously saved discovery state, or `undefined` if none is cached.
|
||||
*
|
||||
* When available, {@linkcode auth} restores the discovery state (authorization server
|
||||
* URL, resource metadata, etc.) instead of performing RFC 9728 discovery, reducing
|
||||
* latency on subsequent calls.
|
||||
*
|
||||
* Providers should clear cached discovery state on repeated authentication failures
|
||||
* (via {@linkcode invalidateCredentials} with scope `'discovery'` or `'all'`) to allow
|
||||
* re-discovery in case the authorization server has changed.
|
||||
*/
|
||||
discoveryState?(): OAuthDiscoveryState | undefined | Promise<OAuthDiscoveryState | undefined>;
|
||||
}
|
||||
/**
|
||||
* Discovery state that can be persisted across sessions by an {@linkcode OAuthClientProvider}.
|
||||
*
|
||||
* Contains the results of RFC 9728 protected resource metadata discovery and
|
||||
* authorization server metadata discovery. Persisting this state avoids
|
||||
* redundant discovery HTTP requests on subsequent {@linkcode auth} calls.
|
||||
*/
|
||||
export interface OAuthDiscoveryState extends OAuthServerInfo {
|
||||
/** The URL at which the protected resource metadata was found, if available. */
|
||||
resourceMetadataUrl?: string;
|
||||
}
|
||||
export type AuthResult = 'AUTHORIZED' | 'REDIRECT';
|
||||
export declare class UnauthorizedError extends Error {
|
||||
constructor(message?: string);
|
||||
}
|
||||
type ClientAuthMethod = 'client_secret_basic' | 'client_secret_post' | 'none';
|
||||
/**
|
||||
* Determines the best client authentication method to use based on server support and client configuration.
|
||||
*
|
||||
* Priority order (highest to lowest):
|
||||
* 1. client_secret_basic (if client secret is available)
|
||||
* 2. client_secret_post (if client secret is available)
|
||||
* 3. none (for public clients)
|
||||
*
|
||||
* @param clientInformation - OAuth client information containing credentials
|
||||
* @param supportedMethods - Authentication methods supported by the authorization server
|
||||
* @returns The selected authentication method
|
||||
*/
|
||||
export declare function selectClientAuthMethod(clientInformation: OAuthClientInformationMixed, supportedMethods: string[]): ClientAuthMethod;
|
||||
/**
|
||||
* Parses an OAuth error response from a string or Response object.
|
||||
*
|
||||
* If the input is a standard OAuth2.0 error response, it will be parsed according to the spec
|
||||
* and an instance of the appropriate OAuthError subclass will be returned.
|
||||
* If parsing fails, it falls back to a generic ServerError that includes
|
||||
* the response status (if available) and original content.
|
||||
*
|
||||
* @param input - A Response object or string containing the error response
|
||||
* @returns A Promise that resolves to an OAuthError instance
|
||||
*/
|
||||
export declare function parseErrorResponse(input: Response | string): Promise<OAuthError>;
|
||||
/**
|
||||
* Orchestrates the full auth flow with a server.
|
||||
*
|
||||
* This can be used as a single entry point for all authorization functionality,
|
||||
* instead of linking together the other lower-level functions in this module.
|
||||
*/
|
||||
export declare function auth(provider: OAuthClientProvider, options: {
|
||||
serverUrl: string | URL;
|
||||
authorizationCode?: string;
|
||||
scope?: string;
|
||||
resourceMetadataUrl?: URL;
|
||||
fetchFn?: FetchLike;
|
||||
}): Promise<AuthResult>;
|
||||
/**
|
||||
* SEP-991: URL-based Client IDs
|
||||
* Validate that the client_id is a valid URL with https scheme
|
||||
*/
|
||||
export declare function isHttpsUrl(value?: string): boolean;
|
||||
export declare function selectResourceURL(serverUrl: string | URL, provider: OAuthClientProvider, resourceMetadata?: OAuthProtectedResourceMetadata): Promise<URL | undefined>;
|
||||
/**
|
||||
* Extract resource_metadata, scope, and error from WWW-Authenticate header.
|
||||
*/
|
||||
export declare function extractWWWAuthenticateParams(res: Response): {
|
||||
resourceMetadataUrl?: URL;
|
||||
scope?: string;
|
||||
error?: string;
|
||||
};
|
||||
/**
|
||||
* Extract resource_metadata from response header.
|
||||
* @deprecated Use `extractWWWAuthenticateParams` instead.
|
||||
*/
|
||||
export declare function extractResourceMetadataUrl(res: Response): URL | undefined;
|
||||
/**
|
||||
* Looks up RFC 9728 OAuth 2.0 Protected Resource Metadata.
|
||||
*
|
||||
* If the server returns a 404 for the well-known endpoint, this function will
|
||||
* return `undefined`. Any other errors will be thrown as exceptions.
|
||||
*/
|
||||
export declare function discoverOAuthProtectedResourceMetadata(serverUrl: string | URL, opts?: {
|
||||
protocolVersion?: string;
|
||||
resourceMetadataUrl?: string | URL;
|
||||
}, fetchFn?: FetchLike): Promise<OAuthProtectedResourceMetadata>;
|
||||
/**
|
||||
* Looks up RFC 8414 OAuth 2.0 Authorization Server Metadata.
|
||||
*
|
||||
* If the server returns a 404 for the well-known endpoint, this function will
|
||||
* return `undefined`. Any other errors will be thrown as exceptions.
|
||||
*
|
||||
* @deprecated This function is deprecated in favor of `discoverAuthorizationServerMetadata`.
|
||||
*/
|
||||
export declare function discoverOAuthMetadata(issuer: string | URL, { authorizationServerUrl, protocolVersion }?: {
|
||||
authorizationServerUrl?: string | URL;
|
||||
protocolVersion?: string;
|
||||
}, fetchFn?: FetchLike): Promise<OAuthMetadata | undefined>;
|
||||
/**
|
||||
* Builds a list of discovery URLs to try for authorization server metadata.
|
||||
* URLs are returned in priority order:
|
||||
* 1. OAuth metadata at the given URL
|
||||
* 2. OIDC metadata endpoints at the given URL
|
||||
*/
|
||||
export declare function buildDiscoveryUrls(authorizationServerUrl: string | URL): {
|
||||
url: URL;
|
||||
type: 'oauth' | 'oidc';
|
||||
}[];
|
||||
/**
|
||||
* Discovers authorization server metadata with support for RFC 8414 OAuth 2.0 Authorization Server Metadata
|
||||
* and OpenID Connect Discovery 1.0 specifications.
|
||||
*
|
||||
* This function implements a fallback strategy for authorization server discovery:
|
||||
* 1. Attempts RFC 8414 OAuth metadata discovery first
|
||||
* 2. If OAuth discovery fails, falls back to OpenID Connect Discovery
|
||||
*
|
||||
* @param authorizationServerUrl - The authorization server URL obtained from the MCP Server's
|
||||
* protected resource metadata, or the MCP server's URL if the
|
||||
* metadata was not found.
|
||||
* @param options - Configuration options
|
||||
* @param options.fetchFn - Optional fetch function for making HTTP requests, defaults to global fetch
|
||||
* @param options.protocolVersion - MCP protocol version to use, defaults to LATEST_PROTOCOL_VERSION
|
||||
* @returns Promise resolving to authorization server metadata, or undefined if discovery fails
|
||||
*/
|
||||
export declare function discoverAuthorizationServerMetadata(authorizationServerUrl: string | URL, { fetchFn, protocolVersion }?: {
|
||||
fetchFn?: FetchLike;
|
||||
protocolVersion?: string;
|
||||
}): Promise<AuthorizationServerMetadata | undefined>;
|
||||
/**
|
||||
* Result of {@linkcode discoverOAuthServerInfo}.
|
||||
*/
|
||||
export interface OAuthServerInfo {
|
||||
/**
|
||||
* The authorization server URL, either discovered via RFC 9728
|
||||
* or derived from the MCP server URL as a fallback.
|
||||
*/
|
||||
authorizationServerUrl: string;
|
||||
/**
|
||||
* The authorization server metadata (endpoints, capabilities),
|
||||
* or `undefined` if metadata discovery failed.
|
||||
*/
|
||||
authorizationServerMetadata?: AuthorizationServerMetadata;
|
||||
/**
|
||||
* The OAuth 2.0 Protected Resource Metadata from RFC 9728,
|
||||
* or `undefined` if the server does not support it.
|
||||
*/
|
||||
resourceMetadata?: OAuthProtectedResourceMetadata;
|
||||
}
|
||||
/**
|
||||
* Discovers the authorization server for an MCP server following
|
||||
* {@link https://datatracker.ietf.org/doc/html/rfc9728 | RFC 9728} (OAuth 2.0 Protected
|
||||
* Resource Metadata), with fallback to treating the server URL as the
|
||||
* authorization server.
|
||||
*
|
||||
* This function combines two discovery steps into one call:
|
||||
* 1. Probes `/.well-known/oauth-protected-resource` on the MCP server to find the
|
||||
* authorization server URL (RFC 9728).
|
||||
* 2. Fetches authorization server metadata from that URL (RFC 8414 / OpenID Connect Discovery).
|
||||
*
|
||||
* Use this when you need the authorization server metadata for operations outside the
|
||||
* {@linkcode auth} orchestrator, such as token refresh or token revocation.
|
||||
*
|
||||
* @param serverUrl - The MCP resource server URL
|
||||
* @param opts - Optional configuration
|
||||
* @param opts.resourceMetadataUrl - Override URL for the protected resource metadata endpoint
|
||||
* @param opts.fetchFn - Custom fetch function for HTTP requests
|
||||
* @returns Authorization server URL, metadata, and resource metadata (if available)
|
||||
*/
|
||||
export declare function discoverOAuthServerInfo(serverUrl: string | URL, opts?: {
|
||||
resourceMetadataUrl?: URL;
|
||||
fetchFn?: FetchLike;
|
||||
}): Promise<OAuthServerInfo>;
|
||||
/**
|
||||
* Begins the authorization flow with the given server, by generating a PKCE challenge and constructing the authorization URL.
|
||||
*/
|
||||
export declare function startAuthorization(authorizationServerUrl: string | URL, { metadata, clientInformation, redirectUrl, scope, state, resource }: {
|
||||
metadata?: AuthorizationServerMetadata;
|
||||
clientInformation: OAuthClientInformationMixed;
|
||||
redirectUrl: string | URL;
|
||||
scope?: string;
|
||||
state?: string;
|
||||
resource?: URL;
|
||||
}): Promise<{
|
||||
authorizationUrl: URL;
|
||||
codeVerifier: string;
|
||||
}>;
|
||||
/**
|
||||
* Prepares token request parameters for an authorization code exchange.
|
||||
*
|
||||
* This is the default implementation used by fetchToken when the provider
|
||||
* doesn't implement prepareTokenRequest.
|
||||
*
|
||||
* @param authorizationCode - The authorization code received from the authorization endpoint
|
||||
* @param codeVerifier - The PKCE code verifier
|
||||
* @param redirectUri - The redirect URI used in the authorization request
|
||||
* @returns URLSearchParams for the authorization_code grant
|
||||
*/
|
||||
export declare function prepareAuthorizationCodeRequest(authorizationCode: string, codeVerifier: string, redirectUri: string | URL): URLSearchParams;
|
||||
/**
|
||||
* Exchanges an authorization code for an access token with the given server.
|
||||
*
|
||||
* Supports multiple client authentication methods as specified in OAuth 2.1:
|
||||
* - Automatically selects the best authentication method based on server support
|
||||
* - Falls back to appropriate defaults when server metadata is unavailable
|
||||
*
|
||||
* @param authorizationServerUrl - The authorization server's base URL
|
||||
* @param options - Configuration object containing client info, auth code, etc.
|
||||
* @returns Promise resolving to OAuth tokens
|
||||
* @throws {Error} When token exchange fails or authentication is invalid
|
||||
*/
|
||||
export declare function exchangeAuthorization(authorizationServerUrl: string | URL, { metadata, clientInformation, authorizationCode, codeVerifier, redirectUri, resource, addClientAuthentication, fetchFn }: {
|
||||
metadata?: AuthorizationServerMetadata;
|
||||
clientInformation: OAuthClientInformationMixed;
|
||||
authorizationCode: string;
|
||||
codeVerifier: string;
|
||||
redirectUri: string | URL;
|
||||
resource?: URL;
|
||||
addClientAuthentication?: OAuthClientProvider['addClientAuthentication'];
|
||||
fetchFn?: FetchLike;
|
||||
}): Promise<OAuthTokens>;
|
||||
/**
|
||||
* Exchange a refresh token for an updated access token.
|
||||
*
|
||||
* Supports multiple client authentication methods as specified in OAuth 2.1:
|
||||
* - Automatically selects the best authentication method based on server support
|
||||
* - Preserves the original refresh token if a new one is not returned
|
||||
*
|
||||
* @param authorizationServerUrl - The authorization server's base URL
|
||||
* @param options - Configuration object containing client info, refresh token, etc.
|
||||
* @returns Promise resolving to OAuth tokens (preserves original refresh_token if not replaced)
|
||||
* @throws {Error} When token refresh fails or authentication is invalid
|
||||
*/
|
||||
export declare function refreshAuthorization(authorizationServerUrl: string | URL, { metadata, clientInformation, refreshToken, resource, addClientAuthentication, fetchFn }: {
|
||||
metadata?: AuthorizationServerMetadata;
|
||||
clientInformation: OAuthClientInformationMixed;
|
||||
refreshToken: string;
|
||||
resource?: URL;
|
||||
addClientAuthentication?: OAuthClientProvider['addClientAuthentication'];
|
||||
fetchFn?: FetchLike;
|
||||
}): Promise<OAuthTokens>;
|
||||
/**
|
||||
* Unified token fetching that works with any grant type via provider.prepareTokenRequest().
|
||||
*
|
||||
* This function provides a single entry point for obtaining tokens regardless of the
|
||||
* OAuth grant type. The provider's prepareTokenRequest() method determines which grant
|
||||
* to use and supplies the grant-specific parameters.
|
||||
*
|
||||
* @param provider - OAuth client provider that implements prepareTokenRequest()
|
||||
* @param authorizationServerUrl - The authorization server's base URL
|
||||
* @param options - Configuration for the token request
|
||||
* @returns Promise resolving to OAuth tokens
|
||||
* @throws {Error} When provider doesn't implement prepareTokenRequest or token fetch fails
|
||||
*
|
||||
* @example
|
||||
* // Provider for client_credentials:
|
||||
* class MyProvider implements OAuthClientProvider {
|
||||
* prepareTokenRequest(scope) {
|
||||
* const params = new URLSearchParams({ grant_type: 'client_credentials' });
|
||||
* if (scope) params.set('scope', scope);
|
||||
* return params;
|
||||
* }
|
||||
* // ... other methods
|
||||
* }
|
||||
*
|
||||
* const tokens = await fetchToken(provider, authServerUrl, { metadata });
|
||||
*/
|
||||
export declare function fetchToken(provider: OAuthClientProvider, authorizationServerUrl: string | URL, { metadata, resource, authorizationCode, fetchFn }?: {
|
||||
metadata?: AuthorizationServerMetadata;
|
||||
resource?: URL;
|
||||
/** Authorization code for the default authorization_code grant flow */
|
||||
authorizationCode?: string;
|
||||
fetchFn?: FetchLike;
|
||||
}): Promise<OAuthTokens>;
|
||||
/**
|
||||
* Performs OAuth 2.0 Dynamic Client Registration according to RFC 7591.
|
||||
*
|
||||
* If `scope` is provided, it overrides `clientMetadata.scope` in the registration
|
||||
* request body. This allows callers to apply the Scope Selection Strategy (SEP-835)
|
||||
* consistently across both DCR and the subsequent authorization request.
|
||||
*/
|
||||
export declare function registerClient(authorizationServerUrl: string | URL, { metadata, clientMetadata, scope, fetchFn }: {
|
||||
metadata?: AuthorizationServerMetadata;
|
||||
clientMetadata: OAuthClientMetadata;
|
||||
scope?: string;
|
||||
fetchFn?: FetchLike;
|
||||
}): Promise<OAuthClientInformationFull>;
|
||||
export {};
|
||||
//# sourceMappingURL=auth.d.ts.map
|
||||
1
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth.d.ts.map
generated
vendored
Normal file
1
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth.d.ts.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
943
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth.js
generated
vendored
Normal file
943
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth.js
generated
vendored
Normal file
@@ -0,0 +1,943 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.UnauthorizedError = void 0;
|
||||
exports.selectClientAuthMethod = selectClientAuthMethod;
|
||||
exports.parseErrorResponse = parseErrorResponse;
|
||||
exports.auth = auth;
|
||||
exports.isHttpsUrl = isHttpsUrl;
|
||||
exports.selectResourceURL = selectResourceURL;
|
||||
exports.extractWWWAuthenticateParams = extractWWWAuthenticateParams;
|
||||
exports.extractResourceMetadataUrl = extractResourceMetadataUrl;
|
||||
exports.discoverOAuthProtectedResourceMetadata = discoverOAuthProtectedResourceMetadata;
|
||||
exports.discoverOAuthMetadata = discoverOAuthMetadata;
|
||||
exports.buildDiscoveryUrls = buildDiscoveryUrls;
|
||||
exports.discoverAuthorizationServerMetadata = discoverAuthorizationServerMetadata;
|
||||
exports.discoverOAuthServerInfo = discoverOAuthServerInfo;
|
||||
exports.startAuthorization = startAuthorization;
|
||||
exports.prepareAuthorizationCodeRequest = prepareAuthorizationCodeRequest;
|
||||
exports.exchangeAuthorization = exchangeAuthorization;
|
||||
exports.refreshAuthorization = refreshAuthorization;
|
||||
exports.fetchToken = fetchToken;
|
||||
exports.registerClient = registerClient;
|
||||
const pkce_challenge_1 = __importDefault(require("pkce-challenge"));
|
||||
const types_js_1 = require("../types.js");
|
||||
const auth_js_1 = require("../shared/auth.js");
|
||||
const auth_js_2 = require("../shared/auth.js");
|
||||
const auth_utils_js_1 = require("../shared/auth-utils.js");
|
||||
const errors_js_1 = require("../server/auth/errors.js");
|
||||
class UnauthorizedError extends Error {
|
||||
constructor(message) {
|
||||
super(message ?? 'Unauthorized');
|
||||
}
|
||||
}
|
||||
exports.UnauthorizedError = UnauthorizedError;
|
||||
function isClientAuthMethod(method) {
|
||||
return ['client_secret_basic', 'client_secret_post', 'none'].includes(method);
|
||||
}
|
||||
const AUTHORIZATION_CODE_RESPONSE_TYPE = 'code';
|
||||
const AUTHORIZATION_CODE_CHALLENGE_METHOD = 'S256';
|
||||
/**
|
||||
* Determines the best client authentication method to use based on server support and client configuration.
|
||||
*
|
||||
* Priority order (highest to lowest):
|
||||
* 1. client_secret_basic (if client secret is available)
|
||||
* 2. client_secret_post (if client secret is available)
|
||||
* 3. none (for public clients)
|
||||
*
|
||||
* @param clientInformation - OAuth client information containing credentials
|
||||
* @param supportedMethods - Authentication methods supported by the authorization server
|
||||
* @returns The selected authentication method
|
||||
*/
|
||||
function selectClientAuthMethod(clientInformation, supportedMethods) {
|
||||
const hasClientSecret = clientInformation.client_secret !== undefined;
|
||||
// Prefer the method returned by the server during client registration, if valid.
|
||||
// When server metadata is present we also require the method to be listed as supported;
|
||||
// when supportedMethods is empty (metadata omitted the field) the DCR hint stands alone.
|
||||
if ('token_endpoint_auth_method' in clientInformation &&
|
||||
clientInformation.token_endpoint_auth_method &&
|
||||
isClientAuthMethod(clientInformation.token_endpoint_auth_method) &&
|
||||
(supportedMethods.length === 0 || supportedMethods.includes(clientInformation.token_endpoint_auth_method))) {
|
||||
return clientInformation.token_endpoint_auth_method;
|
||||
}
|
||||
// If server metadata omits token_endpoint_auth_methods_supported, RFC 8414 §2 says the
|
||||
// default is client_secret_basic. RFC 6749 §2.3.1 also requires servers to support HTTP
|
||||
// Basic authentication for clients with a secret, making it the safest default.
|
||||
if (supportedMethods.length === 0) {
|
||||
return hasClientSecret ? 'client_secret_basic' : 'none';
|
||||
}
|
||||
// Try methods in priority order (most secure first)
|
||||
if (hasClientSecret && supportedMethods.includes('client_secret_basic')) {
|
||||
return 'client_secret_basic';
|
||||
}
|
||||
if (hasClientSecret && supportedMethods.includes('client_secret_post')) {
|
||||
return 'client_secret_post';
|
||||
}
|
||||
if (supportedMethods.includes('none')) {
|
||||
return 'none';
|
||||
}
|
||||
// Fallback: use what we have
|
||||
return hasClientSecret ? 'client_secret_post' : 'none';
|
||||
}
|
||||
/**
|
||||
* Applies client authentication to the request based on the specified method.
|
||||
*
|
||||
* Implements OAuth 2.1 client authentication methods:
|
||||
* - client_secret_basic: HTTP Basic authentication (RFC 6749 Section 2.3.1)
|
||||
* - client_secret_post: Credentials in request body (RFC 6749 Section 2.3.1)
|
||||
* - none: Public client authentication (RFC 6749 Section 2.1)
|
||||
*
|
||||
* @param method - The authentication method to use
|
||||
* @param clientInformation - OAuth client information containing credentials
|
||||
* @param headers - HTTP headers object to modify
|
||||
* @param params - URL search parameters to modify
|
||||
* @throws {Error} When required credentials are missing
|
||||
*/
|
||||
function applyClientAuthentication(method, clientInformation, headers, params) {
|
||||
const { client_id, client_secret } = clientInformation;
|
||||
switch (method) {
|
||||
case 'client_secret_basic':
|
||||
applyBasicAuth(client_id, client_secret, headers);
|
||||
return;
|
||||
case 'client_secret_post':
|
||||
applyPostAuth(client_id, client_secret, params);
|
||||
return;
|
||||
case 'none':
|
||||
applyPublicAuth(client_id, params);
|
||||
return;
|
||||
default:
|
||||
throw new Error(`Unsupported client authentication method: ${method}`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Applies HTTP Basic authentication (RFC 6749 Section 2.3.1)
|
||||
*/
|
||||
function applyBasicAuth(clientId, clientSecret, headers) {
|
||||
if (!clientSecret) {
|
||||
throw new Error('client_secret_basic authentication requires a client_secret');
|
||||
}
|
||||
const credentials = btoa(`${clientId}:${clientSecret}`);
|
||||
headers.set('Authorization', `Basic ${credentials}`);
|
||||
}
|
||||
/**
|
||||
* Applies POST body authentication (RFC 6749 Section 2.3.1)
|
||||
*/
|
||||
function applyPostAuth(clientId, clientSecret, params) {
|
||||
params.set('client_id', clientId);
|
||||
if (clientSecret) {
|
||||
params.set('client_secret', clientSecret);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Applies public client authentication (RFC 6749 Section 2.1)
|
||||
*/
|
||||
function applyPublicAuth(clientId, params) {
|
||||
params.set('client_id', clientId);
|
||||
}
|
||||
/**
|
||||
* Parses an OAuth error response from a string or Response object.
|
||||
*
|
||||
* If the input is a standard OAuth2.0 error response, it will be parsed according to the spec
|
||||
* and an instance of the appropriate OAuthError subclass will be returned.
|
||||
* If parsing fails, it falls back to a generic ServerError that includes
|
||||
* the response status (if available) and original content.
|
||||
*
|
||||
* @param input - A Response object or string containing the error response
|
||||
* @returns A Promise that resolves to an OAuthError instance
|
||||
*/
|
||||
async function parseErrorResponse(input) {
|
||||
const statusCode = input instanceof Response ? input.status : undefined;
|
||||
const body = input instanceof Response ? await input.text() : input;
|
||||
try {
|
||||
const result = auth_js_1.OAuthErrorResponseSchema.parse(JSON.parse(body));
|
||||
const { error, error_description, error_uri } = result;
|
||||
const errorClass = errors_js_1.OAUTH_ERRORS[error] || errors_js_1.ServerError;
|
||||
return new errorClass(error_description || '', error_uri);
|
||||
}
|
||||
catch (error) {
|
||||
// Not a valid OAuth error response, but try to inform the user of the raw data anyway
|
||||
const errorMessage = `${statusCode ? `HTTP ${statusCode}: ` : ''}Invalid OAuth error response: ${error}. Raw body: ${body}`;
|
||||
return new errors_js_1.ServerError(errorMessage);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Orchestrates the full auth flow with a server.
|
||||
*
|
||||
* This can be used as a single entry point for all authorization functionality,
|
||||
* instead of linking together the other lower-level functions in this module.
|
||||
*/
|
||||
async function auth(provider, options) {
|
||||
try {
|
||||
return await authInternal(provider, options);
|
||||
}
|
||||
catch (error) {
|
||||
// Handle recoverable error types by invalidating credentials and retrying
|
||||
if (error instanceof errors_js_1.InvalidClientError || error instanceof errors_js_1.UnauthorizedClientError) {
|
||||
await provider.invalidateCredentials?.('all');
|
||||
return await authInternal(provider, options);
|
||||
}
|
||||
else if (error instanceof errors_js_1.InvalidGrantError) {
|
||||
await provider.invalidateCredentials?.('tokens');
|
||||
return await authInternal(provider, options);
|
||||
}
|
||||
// Throw otherwise
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async function authInternal(provider, { serverUrl, authorizationCode, scope, resourceMetadataUrl, fetchFn }) {
|
||||
// Check if the provider has cached discovery state to skip discovery
|
||||
const cachedState = await provider.discoveryState?.();
|
||||
let resourceMetadata;
|
||||
let authorizationServerUrl;
|
||||
let metadata;
|
||||
// If resourceMetadataUrl is not provided, try to load it from cached state
|
||||
// This handles browser redirects where the URL was saved before navigation
|
||||
let effectiveResourceMetadataUrl = resourceMetadataUrl;
|
||||
if (!effectiveResourceMetadataUrl && cachedState?.resourceMetadataUrl) {
|
||||
effectiveResourceMetadataUrl = new URL(cachedState.resourceMetadataUrl);
|
||||
}
|
||||
if (cachedState?.authorizationServerUrl) {
|
||||
// Restore discovery state from cache
|
||||
authorizationServerUrl = cachedState.authorizationServerUrl;
|
||||
resourceMetadata = cachedState.resourceMetadata;
|
||||
metadata =
|
||||
cachedState.authorizationServerMetadata ?? (await discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn }));
|
||||
// If resource metadata wasn't cached, try to fetch it for selectResourceURL
|
||||
if (!resourceMetadata) {
|
||||
try {
|
||||
resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl: effectiveResourceMetadataUrl }, fetchFn);
|
||||
}
|
||||
catch {
|
||||
// RFC 9728 not available — selectResourceURL will handle undefined
|
||||
}
|
||||
}
|
||||
// Re-save if we enriched the cached state with missing metadata
|
||||
if (metadata !== cachedState.authorizationServerMetadata || resourceMetadata !== cachedState.resourceMetadata) {
|
||||
await provider.saveDiscoveryState?.({
|
||||
authorizationServerUrl: String(authorizationServerUrl),
|
||||
resourceMetadataUrl: effectiveResourceMetadataUrl?.toString(),
|
||||
resourceMetadata,
|
||||
authorizationServerMetadata: metadata
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Full discovery via RFC 9728
|
||||
const serverInfo = await discoverOAuthServerInfo(serverUrl, { resourceMetadataUrl: effectiveResourceMetadataUrl, fetchFn });
|
||||
authorizationServerUrl = serverInfo.authorizationServerUrl;
|
||||
metadata = serverInfo.authorizationServerMetadata;
|
||||
resourceMetadata = serverInfo.resourceMetadata;
|
||||
// Persist discovery state for future use
|
||||
// TODO: resourceMetadataUrl is only populated when explicitly provided via options
|
||||
// or loaded from cached state. The URL derived internally by
|
||||
// discoverOAuthProtectedResourceMetadata() is not captured back here.
|
||||
await provider.saveDiscoveryState?.({
|
||||
authorizationServerUrl: String(authorizationServerUrl),
|
||||
resourceMetadataUrl: effectiveResourceMetadataUrl?.toString(),
|
||||
resourceMetadata,
|
||||
authorizationServerMetadata: metadata
|
||||
});
|
||||
}
|
||||
const resource = await selectResourceURL(serverUrl, provider, resourceMetadata);
|
||||
// Apply scope selection strategy (SEP-835):
|
||||
// 1. WWW-Authenticate scope (passed via `scope` param)
|
||||
// 2. PRM scopes_supported
|
||||
// 3. Client metadata scope (user-configured fallback)
|
||||
// The resolved scope is used consistently for both DCR and the authorization request.
|
||||
const resolvedScope = scope || resourceMetadata?.scopes_supported?.join(' ') || provider.clientMetadata.scope;
|
||||
// Handle client registration if needed
|
||||
let clientInformation = await Promise.resolve(provider.clientInformation());
|
||||
if (!clientInformation) {
|
||||
if (authorizationCode !== undefined) {
|
||||
throw new Error('Existing OAuth client information is required when exchanging an authorization code');
|
||||
}
|
||||
const supportsUrlBasedClientId = metadata?.client_id_metadata_document_supported === true;
|
||||
const clientMetadataUrl = provider.clientMetadataUrl;
|
||||
if (clientMetadataUrl && !isHttpsUrl(clientMetadataUrl)) {
|
||||
throw new errors_js_1.InvalidClientMetadataError(`clientMetadataUrl must be a valid HTTPS URL with a non-root pathname, got: ${clientMetadataUrl}`);
|
||||
}
|
||||
const shouldUseUrlBasedClientId = supportsUrlBasedClientId && clientMetadataUrl;
|
||||
if (shouldUseUrlBasedClientId) {
|
||||
// SEP-991: URL-based Client IDs
|
||||
clientInformation = {
|
||||
client_id: clientMetadataUrl
|
||||
};
|
||||
await provider.saveClientInformation?.(clientInformation);
|
||||
}
|
||||
else {
|
||||
// Fallback to dynamic registration
|
||||
if (!provider.saveClientInformation) {
|
||||
throw new Error('OAuth client information must be saveable for dynamic registration');
|
||||
}
|
||||
const fullInformation = await registerClient(authorizationServerUrl, {
|
||||
metadata,
|
||||
clientMetadata: provider.clientMetadata,
|
||||
scope: resolvedScope,
|
||||
fetchFn
|
||||
});
|
||||
await provider.saveClientInformation(fullInformation);
|
||||
clientInformation = fullInformation;
|
||||
}
|
||||
}
|
||||
// Non-interactive flows (e.g., client_credentials, jwt-bearer) don't need a redirect URL
|
||||
const nonInteractiveFlow = !provider.redirectUrl;
|
||||
// Exchange authorization code for tokens, or fetch tokens directly for non-interactive flows
|
||||
if (authorizationCode !== undefined || nonInteractiveFlow) {
|
||||
const tokens = await fetchToken(provider, authorizationServerUrl, {
|
||||
metadata,
|
||||
resource,
|
||||
authorizationCode,
|
||||
fetchFn
|
||||
});
|
||||
await provider.saveTokens(tokens);
|
||||
return 'AUTHORIZED';
|
||||
}
|
||||
const tokens = await provider.tokens();
|
||||
// Handle token refresh or new authorization
|
||||
if (tokens?.refresh_token) {
|
||||
try {
|
||||
// Attempt to refresh the token
|
||||
const newTokens = await refreshAuthorization(authorizationServerUrl, {
|
||||
metadata,
|
||||
clientInformation,
|
||||
refreshToken: tokens.refresh_token,
|
||||
resource,
|
||||
addClientAuthentication: provider.addClientAuthentication,
|
||||
fetchFn
|
||||
});
|
||||
await provider.saveTokens(newTokens);
|
||||
return 'AUTHORIZED';
|
||||
}
|
||||
catch (error) {
|
||||
// If this is a ServerError, or an unknown type, log it out and try to continue. Otherwise, escalate so we can fix things and retry.
|
||||
if (!(error instanceof errors_js_1.OAuthError) || error instanceof errors_js_1.ServerError) {
|
||||
// Could not refresh OAuth tokens
|
||||
}
|
||||
else {
|
||||
// Refresh failed for another reason, re-throw
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
const state = provider.state ? await provider.state() : undefined;
|
||||
// Start new authorization flow
|
||||
const { authorizationUrl, codeVerifier } = await startAuthorization(authorizationServerUrl, {
|
||||
metadata,
|
||||
clientInformation,
|
||||
state,
|
||||
redirectUrl: provider.redirectUrl,
|
||||
scope: resolvedScope,
|
||||
resource
|
||||
});
|
||||
await provider.saveCodeVerifier(codeVerifier);
|
||||
await provider.redirectToAuthorization(authorizationUrl);
|
||||
return 'REDIRECT';
|
||||
}
|
||||
/**
|
||||
* SEP-991: URL-based Client IDs
|
||||
* Validate that the client_id is a valid URL with https scheme
|
||||
*/
|
||||
function isHttpsUrl(value) {
|
||||
if (!value)
|
||||
return false;
|
||||
try {
|
||||
const url = new URL(value);
|
||||
return url.protocol === 'https:' && url.pathname !== '/';
|
||||
}
|
||||
catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
async function selectResourceURL(serverUrl, provider, resourceMetadata) {
|
||||
const defaultResource = (0, auth_utils_js_1.resourceUrlFromServerUrl)(serverUrl);
|
||||
// If provider has custom validation, delegate to it
|
||||
if (provider.validateResourceURL) {
|
||||
return await provider.validateResourceURL(defaultResource, resourceMetadata?.resource);
|
||||
}
|
||||
// Only include resource parameter when Protected Resource Metadata is present
|
||||
if (!resourceMetadata) {
|
||||
return undefined;
|
||||
}
|
||||
// Validate that the metadata's resource is compatible with our request
|
||||
if (!(0, auth_utils_js_1.checkResourceAllowed)({ requestedResource: defaultResource, configuredResource: resourceMetadata.resource })) {
|
||||
throw new Error(`Protected resource ${resourceMetadata.resource} does not match expected ${defaultResource} (or origin)`);
|
||||
}
|
||||
// Prefer the resource from metadata since it's what the server is telling us to request
|
||||
return new URL(resourceMetadata.resource);
|
||||
}
|
||||
/**
|
||||
* Extract resource_metadata, scope, and error from WWW-Authenticate header.
|
||||
*/
|
||||
function extractWWWAuthenticateParams(res) {
|
||||
const authenticateHeader = res.headers.get('WWW-Authenticate');
|
||||
if (!authenticateHeader) {
|
||||
return {};
|
||||
}
|
||||
const [type, scheme] = authenticateHeader.split(' ');
|
||||
if (type.toLowerCase() !== 'bearer' || !scheme) {
|
||||
return {};
|
||||
}
|
||||
const resourceMetadataMatch = extractFieldFromWwwAuth(res, 'resource_metadata') || undefined;
|
||||
let resourceMetadataUrl;
|
||||
if (resourceMetadataMatch) {
|
||||
try {
|
||||
resourceMetadataUrl = new URL(resourceMetadataMatch);
|
||||
}
|
||||
catch {
|
||||
// Ignore invalid URL
|
||||
}
|
||||
}
|
||||
const scope = extractFieldFromWwwAuth(res, 'scope') || undefined;
|
||||
const error = extractFieldFromWwwAuth(res, 'error') || undefined;
|
||||
return {
|
||||
resourceMetadataUrl,
|
||||
scope,
|
||||
error
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Extracts a specific field's value from the WWW-Authenticate header string.
|
||||
*
|
||||
* @param response The HTTP response object containing the headers.
|
||||
* @param fieldName The name of the field to extract (e.g., "realm", "nonce").
|
||||
* @returns The field value
|
||||
*/
|
||||
function extractFieldFromWwwAuth(response, fieldName) {
|
||||
const wwwAuthHeader = response.headers.get('WWW-Authenticate');
|
||||
if (!wwwAuthHeader) {
|
||||
return null;
|
||||
}
|
||||
const pattern = new RegExp(`${fieldName}=(?:"([^"]+)"|([^\\s,]+))`);
|
||||
const match = wwwAuthHeader.match(pattern);
|
||||
if (match) {
|
||||
// Pattern matches: field_name="value" or field_name=value (unquoted)
|
||||
return match[1] || match[2];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Extract resource_metadata from response header.
|
||||
* @deprecated Use `extractWWWAuthenticateParams` instead.
|
||||
*/
|
||||
function extractResourceMetadataUrl(res) {
|
||||
const authenticateHeader = res.headers.get('WWW-Authenticate');
|
||||
if (!authenticateHeader) {
|
||||
return undefined;
|
||||
}
|
||||
const [type, scheme] = authenticateHeader.split(' ');
|
||||
if (type.toLowerCase() !== 'bearer' || !scheme) {
|
||||
return undefined;
|
||||
}
|
||||
const regex = /resource_metadata="([^"]*)"/;
|
||||
const match = regex.exec(authenticateHeader);
|
||||
if (!match) {
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
return new URL(match[1]);
|
||||
}
|
||||
catch {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Looks up RFC 9728 OAuth 2.0 Protected Resource Metadata.
|
||||
*
|
||||
* If the server returns a 404 for the well-known endpoint, this function will
|
||||
* return `undefined`. Any other errors will be thrown as exceptions.
|
||||
*/
|
||||
async function discoverOAuthProtectedResourceMetadata(serverUrl, opts, fetchFn = fetch) {
|
||||
const response = await discoverMetadataWithFallback(serverUrl, 'oauth-protected-resource', fetchFn, {
|
||||
protocolVersion: opts?.protocolVersion,
|
||||
metadataUrl: opts?.resourceMetadataUrl
|
||||
});
|
||||
if (!response || response.status === 404) {
|
||||
await response?.body?.cancel();
|
||||
throw new Error(`Resource server does not implement OAuth 2.0 Protected Resource Metadata.`);
|
||||
}
|
||||
if (!response.ok) {
|
||||
await response.body?.cancel();
|
||||
throw new Error(`HTTP ${response.status} trying to load well-known OAuth protected resource metadata.`);
|
||||
}
|
||||
return auth_js_2.OAuthProtectedResourceMetadataSchema.parse(await response.json());
|
||||
}
|
||||
/**
|
||||
* Helper function to handle fetch with CORS retry logic
|
||||
*/
|
||||
async function fetchWithCorsRetry(url, headers, fetchFn = fetch) {
|
||||
try {
|
||||
return await fetchFn(url, { headers });
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof TypeError) {
|
||||
if (headers) {
|
||||
// CORS errors come back as TypeError, retry without headers
|
||||
return fetchWithCorsRetry(url, undefined, fetchFn);
|
||||
}
|
||||
else {
|
||||
// We're getting CORS errors on retry too, return undefined
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Constructs the well-known path for auth-related metadata discovery
|
||||
*/
|
||||
function buildWellKnownPath(wellKnownPrefix, pathname = '', options = {}) {
|
||||
// Strip trailing slash from pathname to avoid double slashes
|
||||
if (pathname.endsWith('/')) {
|
||||
pathname = pathname.slice(0, -1);
|
||||
}
|
||||
return options.prependPathname ? `${pathname}/.well-known/${wellKnownPrefix}` : `/.well-known/${wellKnownPrefix}${pathname}`;
|
||||
}
|
||||
/**
|
||||
* Tries to discover OAuth metadata at a specific URL
|
||||
*/
|
||||
async function tryMetadataDiscovery(url, protocolVersion, fetchFn = fetch) {
|
||||
const headers = {
|
||||
'MCP-Protocol-Version': protocolVersion
|
||||
};
|
||||
return await fetchWithCorsRetry(url, headers, fetchFn);
|
||||
}
|
||||
/**
|
||||
* Determines if fallback to root discovery should be attempted
|
||||
*/
|
||||
function shouldAttemptFallback(response, pathname) {
|
||||
return !response || (response.status >= 400 && response.status < 500 && pathname !== '/');
|
||||
}
|
||||
/**
|
||||
* Generic function for discovering OAuth metadata with fallback support
|
||||
*/
|
||||
async function discoverMetadataWithFallback(serverUrl, wellKnownType, fetchFn, opts) {
|
||||
const issuer = new URL(serverUrl);
|
||||
const protocolVersion = opts?.protocolVersion ?? types_js_1.LATEST_PROTOCOL_VERSION;
|
||||
let url;
|
||||
if (opts?.metadataUrl) {
|
||||
url = new URL(opts.metadataUrl);
|
||||
}
|
||||
else {
|
||||
// Try path-aware discovery first
|
||||
const wellKnownPath = buildWellKnownPath(wellKnownType, issuer.pathname);
|
||||
url = new URL(wellKnownPath, opts?.metadataServerUrl ?? issuer);
|
||||
url.search = issuer.search;
|
||||
}
|
||||
let response = await tryMetadataDiscovery(url, protocolVersion, fetchFn);
|
||||
// If path-aware discovery fails with 404 and we're not already at root, try fallback to root discovery
|
||||
if (!opts?.metadataUrl && shouldAttemptFallback(response, issuer.pathname)) {
|
||||
const rootUrl = new URL(`/.well-known/${wellKnownType}`, issuer);
|
||||
response = await tryMetadataDiscovery(rootUrl, protocolVersion, fetchFn);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
/**
|
||||
* Looks up RFC 8414 OAuth 2.0 Authorization Server Metadata.
|
||||
*
|
||||
* If the server returns a 404 for the well-known endpoint, this function will
|
||||
* return `undefined`. Any other errors will be thrown as exceptions.
|
||||
*
|
||||
* @deprecated This function is deprecated in favor of `discoverAuthorizationServerMetadata`.
|
||||
*/
|
||||
async function discoverOAuthMetadata(issuer, { authorizationServerUrl, protocolVersion } = {}, fetchFn = fetch) {
|
||||
if (typeof issuer === 'string') {
|
||||
issuer = new URL(issuer);
|
||||
}
|
||||
if (!authorizationServerUrl) {
|
||||
authorizationServerUrl = issuer;
|
||||
}
|
||||
if (typeof authorizationServerUrl === 'string') {
|
||||
authorizationServerUrl = new URL(authorizationServerUrl);
|
||||
}
|
||||
protocolVersion ?? (protocolVersion = types_js_1.LATEST_PROTOCOL_VERSION);
|
||||
const response = await discoverMetadataWithFallback(authorizationServerUrl, 'oauth-authorization-server', fetchFn, {
|
||||
protocolVersion,
|
||||
metadataServerUrl: authorizationServerUrl
|
||||
});
|
||||
if (!response || response.status === 404) {
|
||||
await response?.body?.cancel();
|
||||
return undefined;
|
||||
}
|
||||
if (!response.ok) {
|
||||
await response.body?.cancel();
|
||||
throw new Error(`HTTP ${response.status} trying to load well-known OAuth metadata`);
|
||||
}
|
||||
return auth_js_2.OAuthMetadataSchema.parse(await response.json());
|
||||
}
|
||||
/**
|
||||
* Builds a list of discovery URLs to try for authorization server metadata.
|
||||
* URLs are returned in priority order:
|
||||
* 1. OAuth metadata at the given URL
|
||||
* 2. OIDC metadata endpoints at the given URL
|
||||
*/
|
||||
function buildDiscoveryUrls(authorizationServerUrl) {
|
||||
const url = typeof authorizationServerUrl === 'string' ? new URL(authorizationServerUrl) : authorizationServerUrl;
|
||||
const hasPath = url.pathname !== '/';
|
||||
const urlsToTry = [];
|
||||
if (!hasPath) {
|
||||
// Root path: https://example.com/.well-known/oauth-authorization-server
|
||||
urlsToTry.push({
|
||||
url: new URL('/.well-known/oauth-authorization-server', url.origin),
|
||||
type: 'oauth'
|
||||
});
|
||||
// OIDC: https://example.com/.well-known/openid-configuration
|
||||
urlsToTry.push({
|
||||
url: new URL(`/.well-known/openid-configuration`, url.origin),
|
||||
type: 'oidc'
|
||||
});
|
||||
return urlsToTry;
|
||||
}
|
||||
// Strip trailing slash from pathname to avoid double slashes
|
||||
let pathname = url.pathname;
|
||||
if (pathname.endsWith('/')) {
|
||||
pathname = pathname.slice(0, -1);
|
||||
}
|
||||
// 1. OAuth metadata at the given URL
|
||||
// Insert well-known before the path: https://example.com/.well-known/oauth-authorization-server/tenant1
|
||||
urlsToTry.push({
|
||||
url: new URL(`/.well-known/oauth-authorization-server${pathname}`, url.origin),
|
||||
type: 'oauth'
|
||||
});
|
||||
// 2. OIDC metadata endpoints
|
||||
// RFC 8414 style: Insert /.well-known/openid-configuration before the path
|
||||
urlsToTry.push({
|
||||
url: new URL(`/.well-known/openid-configuration${pathname}`, url.origin),
|
||||
type: 'oidc'
|
||||
});
|
||||
// OIDC Discovery 1.0 style: Append /.well-known/openid-configuration after the path
|
||||
urlsToTry.push({
|
||||
url: new URL(`${pathname}/.well-known/openid-configuration`, url.origin),
|
||||
type: 'oidc'
|
||||
});
|
||||
return urlsToTry;
|
||||
}
|
||||
/**
|
||||
* Discovers authorization server metadata with support for RFC 8414 OAuth 2.0 Authorization Server Metadata
|
||||
* and OpenID Connect Discovery 1.0 specifications.
|
||||
*
|
||||
* This function implements a fallback strategy for authorization server discovery:
|
||||
* 1. Attempts RFC 8414 OAuth metadata discovery first
|
||||
* 2. If OAuth discovery fails, falls back to OpenID Connect Discovery
|
||||
*
|
||||
* @param authorizationServerUrl - The authorization server URL obtained from the MCP Server's
|
||||
* protected resource metadata, or the MCP server's URL if the
|
||||
* metadata was not found.
|
||||
* @param options - Configuration options
|
||||
* @param options.fetchFn - Optional fetch function for making HTTP requests, defaults to global fetch
|
||||
* @param options.protocolVersion - MCP protocol version to use, defaults to LATEST_PROTOCOL_VERSION
|
||||
* @returns Promise resolving to authorization server metadata, or undefined if discovery fails
|
||||
*/
|
||||
async function discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn = fetch, protocolVersion = types_js_1.LATEST_PROTOCOL_VERSION } = {}) {
|
||||
const headers = {
|
||||
'MCP-Protocol-Version': protocolVersion,
|
||||
Accept: 'application/json'
|
||||
};
|
||||
// Get the list of URLs to try
|
||||
const urlsToTry = buildDiscoveryUrls(authorizationServerUrl);
|
||||
// Try each URL in order
|
||||
for (const { url: endpointUrl, type } of urlsToTry) {
|
||||
const response = await fetchWithCorsRetry(endpointUrl, headers, fetchFn);
|
||||
if (!response) {
|
||||
/**
|
||||
* CORS error occurred - don't throw as the endpoint may not allow CORS,
|
||||
* continue trying other possible endpoints
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
if (!response.ok) {
|
||||
await response.body?.cancel();
|
||||
// Continue looking for any 4xx response code.
|
||||
if (response.status >= 400 && response.status < 500) {
|
||||
continue; // Try next URL
|
||||
}
|
||||
throw new Error(`HTTP ${response.status} trying to load ${type === 'oauth' ? 'OAuth' : 'OpenID provider'} metadata from ${endpointUrl}`);
|
||||
}
|
||||
// Parse and validate based on type
|
||||
if (type === 'oauth') {
|
||||
return auth_js_2.OAuthMetadataSchema.parse(await response.json());
|
||||
}
|
||||
else {
|
||||
return auth_js_1.OpenIdProviderDiscoveryMetadataSchema.parse(await response.json());
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
/**
|
||||
* Discovers the authorization server for an MCP server following
|
||||
* {@link https://datatracker.ietf.org/doc/html/rfc9728 | RFC 9728} (OAuth 2.0 Protected
|
||||
* Resource Metadata), with fallback to treating the server URL as the
|
||||
* authorization server.
|
||||
*
|
||||
* This function combines two discovery steps into one call:
|
||||
* 1. Probes `/.well-known/oauth-protected-resource` on the MCP server to find the
|
||||
* authorization server URL (RFC 9728).
|
||||
* 2. Fetches authorization server metadata from that URL (RFC 8414 / OpenID Connect Discovery).
|
||||
*
|
||||
* Use this when you need the authorization server metadata for operations outside the
|
||||
* {@linkcode auth} orchestrator, such as token refresh or token revocation.
|
||||
*
|
||||
* @param serverUrl - The MCP resource server URL
|
||||
* @param opts - Optional configuration
|
||||
* @param opts.resourceMetadataUrl - Override URL for the protected resource metadata endpoint
|
||||
* @param opts.fetchFn - Custom fetch function for HTTP requests
|
||||
* @returns Authorization server URL, metadata, and resource metadata (if available)
|
||||
*/
|
||||
async function discoverOAuthServerInfo(serverUrl, opts) {
|
||||
let resourceMetadata;
|
||||
let authorizationServerUrl;
|
||||
try {
|
||||
resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl: opts?.resourceMetadataUrl }, opts?.fetchFn);
|
||||
if (resourceMetadata.authorization_servers && resourceMetadata.authorization_servers.length > 0) {
|
||||
authorizationServerUrl = resourceMetadata.authorization_servers[0];
|
||||
}
|
||||
}
|
||||
catch {
|
||||
// RFC 9728 not supported -- fall back to treating the server URL as the authorization server
|
||||
}
|
||||
// If we don't get a valid authorization server from protected resource metadata,
|
||||
// fall back to the legacy MCP spec behavior: MCP server base URL acts as the authorization server
|
||||
if (!authorizationServerUrl) {
|
||||
authorizationServerUrl = String(new URL('/', serverUrl));
|
||||
}
|
||||
const authorizationServerMetadata = await discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn: opts?.fetchFn });
|
||||
return {
|
||||
authorizationServerUrl,
|
||||
authorizationServerMetadata,
|
||||
resourceMetadata
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Begins the authorization flow with the given server, by generating a PKCE challenge and constructing the authorization URL.
|
||||
*/
|
||||
async function startAuthorization(authorizationServerUrl, { metadata, clientInformation, redirectUrl, scope, state, resource }) {
|
||||
let authorizationUrl;
|
||||
if (metadata) {
|
||||
authorizationUrl = new URL(metadata.authorization_endpoint);
|
||||
if (!metadata.response_types_supported.includes(AUTHORIZATION_CODE_RESPONSE_TYPE)) {
|
||||
throw new Error(`Incompatible auth server: does not support response type ${AUTHORIZATION_CODE_RESPONSE_TYPE}`);
|
||||
}
|
||||
if (metadata.code_challenge_methods_supported &&
|
||||
!metadata.code_challenge_methods_supported.includes(AUTHORIZATION_CODE_CHALLENGE_METHOD)) {
|
||||
throw new Error(`Incompatible auth server: does not support code challenge method ${AUTHORIZATION_CODE_CHALLENGE_METHOD}`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
authorizationUrl = new URL('/authorize', authorizationServerUrl);
|
||||
}
|
||||
// Generate PKCE challenge
|
||||
const challenge = await (0, pkce_challenge_1.default)();
|
||||
const codeVerifier = challenge.code_verifier;
|
||||
const codeChallenge = challenge.code_challenge;
|
||||
authorizationUrl.searchParams.set('response_type', AUTHORIZATION_CODE_RESPONSE_TYPE);
|
||||
authorizationUrl.searchParams.set('client_id', clientInformation.client_id);
|
||||
authorizationUrl.searchParams.set('code_challenge', codeChallenge);
|
||||
authorizationUrl.searchParams.set('code_challenge_method', AUTHORIZATION_CODE_CHALLENGE_METHOD);
|
||||
authorizationUrl.searchParams.set('redirect_uri', String(redirectUrl));
|
||||
if (state) {
|
||||
authorizationUrl.searchParams.set('state', state);
|
||||
}
|
||||
if (scope) {
|
||||
authorizationUrl.searchParams.set('scope', scope);
|
||||
}
|
||||
if (scope?.includes('offline_access')) {
|
||||
// if the request includes the OIDC-only "offline_access" scope,
|
||||
// we need to set the prompt to "consent" to ensure the user is prompted to grant offline access
|
||||
// https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess
|
||||
authorizationUrl.searchParams.append('prompt', 'consent');
|
||||
}
|
||||
if (resource) {
|
||||
authorizationUrl.searchParams.set('resource', resource.href);
|
||||
}
|
||||
return { authorizationUrl, codeVerifier };
|
||||
}
|
||||
/**
|
||||
* Prepares token request parameters for an authorization code exchange.
|
||||
*
|
||||
* This is the default implementation used by fetchToken when the provider
|
||||
* doesn't implement prepareTokenRequest.
|
||||
*
|
||||
* @param authorizationCode - The authorization code received from the authorization endpoint
|
||||
* @param codeVerifier - The PKCE code verifier
|
||||
* @param redirectUri - The redirect URI used in the authorization request
|
||||
* @returns URLSearchParams for the authorization_code grant
|
||||
*/
|
||||
function prepareAuthorizationCodeRequest(authorizationCode, codeVerifier, redirectUri) {
|
||||
return new URLSearchParams({
|
||||
grant_type: 'authorization_code',
|
||||
code: authorizationCode,
|
||||
code_verifier: codeVerifier,
|
||||
redirect_uri: String(redirectUri)
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Internal helper to execute a token request with the given parameters.
|
||||
* Used by exchangeAuthorization, refreshAuthorization, and fetchToken.
|
||||
*/
|
||||
async function executeTokenRequest(authorizationServerUrl, { metadata, tokenRequestParams, clientInformation, addClientAuthentication, resource, fetchFn }) {
|
||||
const tokenUrl = metadata?.token_endpoint ? new URL(metadata.token_endpoint) : new URL('/token', authorizationServerUrl);
|
||||
const headers = new Headers({
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
Accept: 'application/json'
|
||||
});
|
||||
if (resource) {
|
||||
tokenRequestParams.set('resource', resource.href);
|
||||
}
|
||||
if (addClientAuthentication) {
|
||||
await addClientAuthentication(headers, tokenRequestParams, tokenUrl, metadata);
|
||||
}
|
||||
else if (clientInformation) {
|
||||
const supportedMethods = metadata?.token_endpoint_auth_methods_supported ?? [];
|
||||
const authMethod = selectClientAuthMethod(clientInformation, supportedMethods);
|
||||
applyClientAuthentication(authMethod, clientInformation, headers, tokenRequestParams);
|
||||
}
|
||||
const response = await (fetchFn ?? fetch)(tokenUrl, {
|
||||
method: 'POST',
|
||||
headers,
|
||||
body: tokenRequestParams
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw await parseErrorResponse(response);
|
||||
}
|
||||
return auth_js_2.OAuthTokensSchema.parse(await response.json());
|
||||
}
|
||||
/**
|
||||
* Exchanges an authorization code for an access token with the given server.
|
||||
*
|
||||
* Supports multiple client authentication methods as specified in OAuth 2.1:
|
||||
* - Automatically selects the best authentication method based on server support
|
||||
* - Falls back to appropriate defaults when server metadata is unavailable
|
||||
*
|
||||
* @param authorizationServerUrl - The authorization server's base URL
|
||||
* @param options - Configuration object containing client info, auth code, etc.
|
||||
* @returns Promise resolving to OAuth tokens
|
||||
* @throws {Error} When token exchange fails or authentication is invalid
|
||||
*/
|
||||
async function exchangeAuthorization(authorizationServerUrl, { metadata, clientInformation, authorizationCode, codeVerifier, redirectUri, resource, addClientAuthentication, fetchFn }) {
|
||||
const tokenRequestParams = prepareAuthorizationCodeRequest(authorizationCode, codeVerifier, redirectUri);
|
||||
return executeTokenRequest(authorizationServerUrl, {
|
||||
metadata,
|
||||
tokenRequestParams,
|
||||
clientInformation,
|
||||
addClientAuthentication,
|
||||
resource,
|
||||
fetchFn
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Exchange a refresh token for an updated access token.
|
||||
*
|
||||
* Supports multiple client authentication methods as specified in OAuth 2.1:
|
||||
* - Automatically selects the best authentication method based on server support
|
||||
* - Preserves the original refresh token if a new one is not returned
|
||||
*
|
||||
* @param authorizationServerUrl - The authorization server's base URL
|
||||
* @param options - Configuration object containing client info, refresh token, etc.
|
||||
* @returns Promise resolving to OAuth tokens (preserves original refresh_token if not replaced)
|
||||
* @throws {Error} When token refresh fails or authentication is invalid
|
||||
*/
|
||||
async function refreshAuthorization(authorizationServerUrl, { metadata, clientInformation, refreshToken, resource, addClientAuthentication, fetchFn }) {
|
||||
const tokenRequestParams = new URLSearchParams({
|
||||
grant_type: 'refresh_token',
|
||||
refresh_token: refreshToken
|
||||
});
|
||||
const tokens = await executeTokenRequest(authorizationServerUrl, {
|
||||
metadata,
|
||||
tokenRequestParams,
|
||||
clientInformation,
|
||||
addClientAuthentication,
|
||||
resource,
|
||||
fetchFn
|
||||
});
|
||||
// Preserve original refresh token if server didn't return a new one
|
||||
return { refresh_token: refreshToken, ...tokens };
|
||||
}
|
||||
/**
|
||||
* Unified token fetching that works with any grant type via provider.prepareTokenRequest().
|
||||
*
|
||||
* This function provides a single entry point for obtaining tokens regardless of the
|
||||
* OAuth grant type. The provider's prepareTokenRequest() method determines which grant
|
||||
* to use and supplies the grant-specific parameters.
|
||||
*
|
||||
* @param provider - OAuth client provider that implements prepareTokenRequest()
|
||||
* @param authorizationServerUrl - The authorization server's base URL
|
||||
* @param options - Configuration for the token request
|
||||
* @returns Promise resolving to OAuth tokens
|
||||
* @throws {Error} When provider doesn't implement prepareTokenRequest or token fetch fails
|
||||
*
|
||||
* @example
|
||||
* // Provider for client_credentials:
|
||||
* class MyProvider implements OAuthClientProvider {
|
||||
* prepareTokenRequest(scope) {
|
||||
* const params = new URLSearchParams({ grant_type: 'client_credentials' });
|
||||
* if (scope) params.set('scope', scope);
|
||||
* return params;
|
||||
* }
|
||||
* // ... other methods
|
||||
* }
|
||||
*
|
||||
* const tokens = await fetchToken(provider, authServerUrl, { metadata });
|
||||
*/
|
||||
async function fetchToken(provider, authorizationServerUrl, { metadata, resource, authorizationCode, fetchFn } = {}) {
|
||||
const scope = provider.clientMetadata.scope;
|
||||
// Use provider's prepareTokenRequest if available, otherwise fall back to authorization_code
|
||||
let tokenRequestParams;
|
||||
if (provider.prepareTokenRequest) {
|
||||
tokenRequestParams = await provider.prepareTokenRequest(scope);
|
||||
}
|
||||
// Default to authorization_code grant if no custom prepareTokenRequest
|
||||
if (!tokenRequestParams) {
|
||||
if (!authorizationCode) {
|
||||
throw new Error('Either provider.prepareTokenRequest() or authorizationCode is required');
|
||||
}
|
||||
if (!provider.redirectUrl) {
|
||||
throw new Error('redirectUrl is required for authorization_code flow');
|
||||
}
|
||||
const codeVerifier = await provider.codeVerifier();
|
||||
tokenRequestParams = prepareAuthorizationCodeRequest(authorizationCode, codeVerifier, provider.redirectUrl);
|
||||
}
|
||||
const clientInformation = await provider.clientInformation();
|
||||
return executeTokenRequest(authorizationServerUrl, {
|
||||
metadata,
|
||||
tokenRequestParams,
|
||||
clientInformation: clientInformation ?? undefined,
|
||||
addClientAuthentication: provider.addClientAuthentication,
|
||||
resource,
|
||||
fetchFn
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Performs OAuth 2.0 Dynamic Client Registration according to RFC 7591.
|
||||
*
|
||||
* If `scope` is provided, it overrides `clientMetadata.scope` in the registration
|
||||
* request body. This allows callers to apply the Scope Selection Strategy (SEP-835)
|
||||
* consistently across both DCR and the subsequent authorization request.
|
||||
*/
|
||||
async function registerClient(authorizationServerUrl, { metadata, clientMetadata, scope, fetchFn }) {
|
||||
let registrationUrl;
|
||||
if (metadata) {
|
||||
if (!metadata.registration_endpoint) {
|
||||
throw new Error('Incompatible auth server: does not support dynamic client registration');
|
||||
}
|
||||
registrationUrl = new URL(metadata.registration_endpoint);
|
||||
}
|
||||
else {
|
||||
registrationUrl = new URL('/register', authorizationServerUrl);
|
||||
}
|
||||
const response = await (fetchFn ?? fetch)(registrationUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
...clientMetadata,
|
||||
...(scope !== undefined ? { scope } : {})
|
||||
})
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw await parseErrorResponse(response);
|
||||
}
|
||||
return auth_js_2.OAuthClientInformationFullSchema.parse(await response.json());
|
||||
}
|
||||
//# sourceMappingURL=auth.js.map
|
||||
1
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth.js.map
generated
vendored
Normal file
1
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/auth.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
588
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/index.d.ts
generated
vendored
Normal file
588
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,588 @@
|
||||
import { Protocol, type ProtocolOptions, type RequestOptions } from '../shared/protocol.js';
|
||||
import type { Transport } from '../shared/transport.js';
|
||||
import { type CallToolRequest, CallToolResultSchema, type ClientCapabilities, type ClientNotification, type ClientRequest, type ClientResult, type CompatibilityCallToolResultSchema, type CompleteRequest, type GetPromptRequest, type Implementation, type ListPromptsRequest, type ListResourcesRequest, type ListResourceTemplatesRequest, type ListToolsRequest, type LoggingLevel, type ReadResourceRequest, type ServerCapabilities, type SubscribeRequest, type UnsubscribeRequest, type ListChangedHandlers, type Request, type Notification, type Result } from '../types.js';
|
||||
import type { jsonSchemaValidator } from '../validation/types.js';
|
||||
import { AnyObjectSchema, SchemaOutput } from '../server/zod-compat.js';
|
||||
import type { RequestHandlerExtra } from '../shared/protocol.js';
|
||||
import { ExperimentalClientTasks } from '../experimental/tasks/client.js';
|
||||
/**
|
||||
* Determines which elicitation modes are supported based on declared client capabilities.
|
||||
*
|
||||
* According to the spec:
|
||||
* - An empty elicitation capability object defaults to form mode support (backwards compatibility)
|
||||
* - URL mode is only supported if explicitly declared
|
||||
*
|
||||
* @param capabilities - The client's elicitation capabilities
|
||||
* @returns An object indicating which modes are supported
|
||||
*/
|
||||
export declare function getSupportedElicitationModes(capabilities: ClientCapabilities['elicitation']): {
|
||||
supportsFormMode: boolean;
|
||||
supportsUrlMode: boolean;
|
||||
};
|
||||
export type ClientOptions = ProtocolOptions & {
|
||||
/**
|
||||
* Capabilities to advertise as being supported by this client.
|
||||
*/
|
||||
capabilities?: ClientCapabilities;
|
||||
/**
|
||||
* JSON Schema validator for tool output validation.
|
||||
*
|
||||
* The validator is used to validate structured content returned by tools
|
||||
* against their declared output schemas.
|
||||
*
|
||||
* @default AjvJsonSchemaValidator
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // ajv
|
||||
* const client = new Client(
|
||||
* { name: 'my-client', version: '1.0.0' },
|
||||
* {
|
||||
* capabilities: {},
|
||||
* jsonSchemaValidator: new AjvJsonSchemaValidator()
|
||||
* }
|
||||
* );
|
||||
*
|
||||
* // @cfworker/json-schema
|
||||
* const client = new Client(
|
||||
* { name: 'my-client', version: '1.0.0' },
|
||||
* {
|
||||
* capabilities: {},
|
||||
* jsonSchemaValidator: new CfWorkerJsonSchemaValidator()
|
||||
* }
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
jsonSchemaValidator?: jsonSchemaValidator;
|
||||
/**
|
||||
* Configure handlers for list changed notifications (tools, prompts, resources).
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const client = new Client(
|
||||
* { name: 'my-client', version: '1.0.0' },
|
||||
* {
|
||||
* listChanged: {
|
||||
* tools: {
|
||||
* onChanged: (error, tools) => {
|
||||
* if (error) {
|
||||
* console.error('Failed to refresh tools:', error);
|
||||
* return;
|
||||
* }
|
||||
* console.log('Tools updated:', tools);
|
||||
* }
|
||||
* },
|
||||
* prompts: {
|
||||
* onChanged: (error, prompts) => console.log('Prompts updated:', prompts)
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
listChanged?: ListChangedHandlers;
|
||||
};
|
||||
/**
|
||||
* An MCP client on top of a pluggable transport.
|
||||
*
|
||||
* The client will automatically begin the initialization flow with the server when connect() is called.
|
||||
*
|
||||
* To use with custom types, extend the base Request/Notification/Result types and pass them as type parameters:
|
||||
*
|
||||
* ```typescript
|
||||
* // Custom schemas
|
||||
* const CustomRequestSchema = RequestSchema.extend({...})
|
||||
* const CustomNotificationSchema = NotificationSchema.extend({...})
|
||||
* const CustomResultSchema = ResultSchema.extend({...})
|
||||
*
|
||||
* // Type aliases
|
||||
* type CustomRequest = z.infer<typeof CustomRequestSchema>
|
||||
* type CustomNotification = z.infer<typeof CustomNotificationSchema>
|
||||
* type CustomResult = z.infer<typeof CustomResultSchema>
|
||||
*
|
||||
* // Create typed client
|
||||
* const client = new Client<CustomRequest, CustomNotification, CustomResult>({
|
||||
* name: "CustomClient",
|
||||
* version: "1.0.0"
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
export declare class Client<RequestT extends Request = Request, NotificationT extends Notification = Notification, ResultT extends Result = Result> extends Protocol<ClientRequest | RequestT, ClientNotification | NotificationT, ClientResult | ResultT> {
|
||||
private _clientInfo;
|
||||
private _serverCapabilities?;
|
||||
private _serverVersion?;
|
||||
private _capabilities;
|
||||
private _instructions?;
|
||||
private _jsonSchemaValidator;
|
||||
private _cachedToolOutputValidators;
|
||||
private _cachedKnownTaskTools;
|
||||
private _cachedRequiredTaskTools;
|
||||
private _experimental?;
|
||||
private _listChangedDebounceTimers;
|
||||
private _pendingListChangedConfig?;
|
||||
/**
|
||||
* Initializes this client with the given name and version information.
|
||||
*/
|
||||
constructor(_clientInfo: Implementation, options?: ClientOptions);
|
||||
/**
|
||||
* Set up handlers for list changed notifications based on config and server capabilities.
|
||||
* This should only be called after initialization when server capabilities are known.
|
||||
* Handlers are silently skipped if the server doesn't advertise the corresponding listChanged capability.
|
||||
* @internal
|
||||
*/
|
||||
private _setupListChangedHandlers;
|
||||
/**
|
||||
* Access experimental features.
|
||||
*
|
||||
* WARNING: These APIs are experimental and may change without notice.
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
get experimental(): {
|
||||
tasks: ExperimentalClientTasks<RequestT, NotificationT, ResultT>;
|
||||
};
|
||||
/**
|
||||
* Registers new capabilities. This can only be called before connecting to a transport.
|
||||
*
|
||||
* The new capabilities will be merged with any existing capabilities previously given (e.g., at initialization).
|
||||
*/
|
||||
registerCapabilities(capabilities: ClientCapabilities): void;
|
||||
/**
|
||||
* Override request handler registration to enforce client-side validation for elicitation.
|
||||
*/
|
||||
setRequestHandler<T extends AnyObjectSchema>(requestSchema: T, handler: (request: SchemaOutput<T>, extra: RequestHandlerExtra<ClientRequest | RequestT, ClientNotification | NotificationT>) => ClientResult | ResultT | Promise<ClientResult | ResultT>): void;
|
||||
protected assertCapability(capability: keyof ServerCapabilities, method: string): void;
|
||||
connect(transport: Transport, options?: RequestOptions): Promise<void>;
|
||||
/**
|
||||
* After initialization has completed, this will be populated with the server's reported capabilities.
|
||||
*/
|
||||
getServerCapabilities(): ServerCapabilities | undefined;
|
||||
/**
|
||||
* After initialization has completed, this will be populated with information about the server's name and version.
|
||||
*/
|
||||
getServerVersion(): Implementation | undefined;
|
||||
/**
|
||||
* After initialization has completed, this may be populated with information about the server's instructions.
|
||||
*/
|
||||
getInstructions(): string | undefined;
|
||||
protected assertCapabilityForMethod(method: RequestT['method']): void;
|
||||
protected assertNotificationCapability(method: NotificationT['method']): void;
|
||||
protected assertRequestHandlerCapability(method: string): void;
|
||||
protected assertTaskCapability(method: string): void;
|
||||
protected assertTaskHandlerCapability(method: string): void;
|
||||
ping(options?: RequestOptions): Promise<{
|
||||
_meta?: {
|
||||
[x: string]: unknown;
|
||||
progressToken?: string | number | undefined;
|
||||
"io.modelcontextprotocol/related-task"?: {
|
||||
taskId: string;
|
||||
} | undefined;
|
||||
} | undefined;
|
||||
}>;
|
||||
complete(params: CompleteRequest['params'], options?: RequestOptions): Promise<{
|
||||
[x: string]: unknown;
|
||||
completion: {
|
||||
[x: string]: unknown;
|
||||
values: string[];
|
||||
total?: number | undefined;
|
||||
hasMore?: boolean | undefined;
|
||||
};
|
||||
_meta?: {
|
||||
[x: string]: unknown;
|
||||
progressToken?: string | number | undefined;
|
||||
"io.modelcontextprotocol/related-task"?: {
|
||||
taskId: string;
|
||||
} | undefined;
|
||||
} | undefined;
|
||||
}>;
|
||||
setLoggingLevel(level: LoggingLevel, options?: RequestOptions): Promise<{
|
||||
_meta?: {
|
||||
[x: string]: unknown;
|
||||
progressToken?: string | number | undefined;
|
||||
"io.modelcontextprotocol/related-task"?: {
|
||||
taskId: string;
|
||||
} | undefined;
|
||||
} | undefined;
|
||||
}>;
|
||||
getPrompt(params: GetPromptRequest['params'], options?: RequestOptions): Promise<{
|
||||
[x: string]: unknown;
|
||||
messages: {
|
||||
role: "user" | "assistant";
|
||||
content: {
|
||||
type: "text";
|
||||
text: string;
|
||||
annotations?: {
|
||||
audience?: ("user" | "assistant")[] | undefined;
|
||||
priority?: number | undefined;
|
||||
lastModified?: string | undefined;
|
||||
} | undefined;
|
||||
_meta?: Record<string, unknown> | undefined;
|
||||
} | {
|
||||
type: "image";
|
||||
data: string;
|
||||
mimeType: string;
|
||||
annotations?: {
|
||||
audience?: ("user" | "assistant")[] | undefined;
|
||||
priority?: number | undefined;
|
||||
lastModified?: string | undefined;
|
||||
} | undefined;
|
||||
_meta?: Record<string, unknown> | undefined;
|
||||
} | {
|
||||
type: "audio";
|
||||
data: string;
|
||||
mimeType: string;
|
||||
annotations?: {
|
||||
audience?: ("user" | "assistant")[] | undefined;
|
||||
priority?: number | undefined;
|
||||
lastModified?: string | undefined;
|
||||
} | undefined;
|
||||
_meta?: Record<string, unknown> | undefined;
|
||||
} | {
|
||||
type: "resource";
|
||||
resource: {
|
||||
uri: string;
|
||||
text: string;
|
||||
mimeType?: string | undefined;
|
||||
_meta?: Record<string, unknown> | undefined;
|
||||
} | {
|
||||
uri: string;
|
||||
blob: string;
|
||||
mimeType?: string | undefined;
|
||||
_meta?: Record<string, unknown> | undefined;
|
||||
};
|
||||
annotations?: {
|
||||
audience?: ("user" | "assistant")[] | undefined;
|
||||
priority?: number | undefined;
|
||||
lastModified?: string | undefined;
|
||||
} | undefined;
|
||||
_meta?: Record<string, unknown> | undefined;
|
||||
} | {
|
||||
uri: string;
|
||||
name: string;
|
||||
type: "resource_link";
|
||||
description?: string | undefined;
|
||||
mimeType?: string | undefined;
|
||||
annotations?: {
|
||||
audience?: ("user" | "assistant")[] | undefined;
|
||||
priority?: number | undefined;
|
||||
lastModified?: string | undefined;
|
||||
} | undefined;
|
||||
_meta?: {
|
||||
[x: string]: unknown;
|
||||
} | undefined;
|
||||
icons?: {
|
||||
src: string;
|
||||
mimeType?: string | undefined;
|
||||
sizes?: string[] | undefined;
|
||||
theme?: "light" | "dark" | undefined;
|
||||
}[] | undefined;
|
||||
title?: string | undefined;
|
||||
};
|
||||
}[];
|
||||
_meta?: {
|
||||
[x: string]: unknown;
|
||||
progressToken?: string | number | undefined;
|
||||
"io.modelcontextprotocol/related-task"?: {
|
||||
taskId: string;
|
||||
} | undefined;
|
||||
} | undefined;
|
||||
description?: string | undefined;
|
||||
}>;
|
||||
listPrompts(params?: ListPromptsRequest['params'], options?: RequestOptions): Promise<{
|
||||
[x: string]: unknown;
|
||||
prompts: {
|
||||
name: string;
|
||||
description?: string | undefined;
|
||||
arguments?: {
|
||||
name: string;
|
||||
description?: string | undefined;
|
||||
required?: boolean | undefined;
|
||||
}[] | undefined;
|
||||
_meta?: {
|
||||
[x: string]: unknown;
|
||||
} | undefined;
|
||||
icons?: {
|
||||
src: string;
|
||||
mimeType?: string | undefined;
|
||||
sizes?: string[] | undefined;
|
||||
theme?: "light" | "dark" | undefined;
|
||||
}[] | undefined;
|
||||
title?: string | undefined;
|
||||
}[];
|
||||
_meta?: {
|
||||
[x: string]: unknown;
|
||||
progressToken?: string | number | undefined;
|
||||
"io.modelcontextprotocol/related-task"?: {
|
||||
taskId: string;
|
||||
} | undefined;
|
||||
} | undefined;
|
||||
nextCursor?: string | undefined;
|
||||
}>;
|
||||
listResources(params?: ListResourcesRequest['params'], options?: RequestOptions): Promise<{
|
||||
[x: string]: unknown;
|
||||
resources: {
|
||||
uri: string;
|
||||
name: string;
|
||||
description?: string | undefined;
|
||||
mimeType?: string | undefined;
|
||||
annotations?: {
|
||||
audience?: ("user" | "assistant")[] | undefined;
|
||||
priority?: number | undefined;
|
||||
lastModified?: string | undefined;
|
||||
} | undefined;
|
||||
_meta?: {
|
||||
[x: string]: unknown;
|
||||
} | undefined;
|
||||
icons?: {
|
||||
src: string;
|
||||
mimeType?: string | undefined;
|
||||
sizes?: string[] | undefined;
|
||||
theme?: "light" | "dark" | undefined;
|
||||
}[] | undefined;
|
||||
title?: string | undefined;
|
||||
}[];
|
||||
_meta?: {
|
||||
[x: string]: unknown;
|
||||
progressToken?: string | number | undefined;
|
||||
"io.modelcontextprotocol/related-task"?: {
|
||||
taskId: string;
|
||||
} | undefined;
|
||||
} | undefined;
|
||||
nextCursor?: string | undefined;
|
||||
}>;
|
||||
listResourceTemplates(params?: ListResourceTemplatesRequest['params'], options?: RequestOptions): Promise<{
|
||||
[x: string]: unknown;
|
||||
resourceTemplates: {
|
||||
uriTemplate: string;
|
||||
name: string;
|
||||
description?: string | undefined;
|
||||
mimeType?: string | undefined;
|
||||
annotations?: {
|
||||
audience?: ("user" | "assistant")[] | undefined;
|
||||
priority?: number | undefined;
|
||||
lastModified?: string | undefined;
|
||||
} | undefined;
|
||||
_meta?: {
|
||||
[x: string]: unknown;
|
||||
} | undefined;
|
||||
icons?: {
|
||||
src: string;
|
||||
mimeType?: string | undefined;
|
||||
sizes?: string[] | undefined;
|
||||
theme?: "light" | "dark" | undefined;
|
||||
}[] | undefined;
|
||||
title?: string | undefined;
|
||||
}[];
|
||||
_meta?: {
|
||||
[x: string]: unknown;
|
||||
progressToken?: string | number | undefined;
|
||||
"io.modelcontextprotocol/related-task"?: {
|
||||
taskId: string;
|
||||
} | undefined;
|
||||
} | undefined;
|
||||
nextCursor?: string | undefined;
|
||||
}>;
|
||||
readResource(params: ReadResourceRequest['params'], options?: RequestOptions): Promise<{
|
||||
[x: string]: unknown;
|
||||
contents: ({
|
||||
uri: string;
|
||||
text: string;
|
||||
mimeType?: string | undefined;
|
||||
_meta?: Record<string, unknown> | undefined;
|
||||
} | {
|
||||
uri: string;
|
||||
blob: string;
|
||||
mimeType?: string | undefined;
|
||||
_meta?: Record<string, unknown> | undefined;
|
||||
})[];
|
||||
_meta?: {
|
||||
[x: string]: unknown;
|
||||
progressToken?: string | number | undefined;
|
||||
"io.modelcontextprotocol/related-task"?: {
|
||||
taskId: string;
|
||||
} | undefined;
|
||||
} | undefined;
|
||||
}>;
|
||||
subscribeResource(params: SubscribeRequest['params'], options?: RequestOptions): Promise<{
|
||||
_meta?: {
|
||||
[x: string]: unknown;
|
||||
progressToken?: string | number | undefined;
|
||||
"io.modelcontextprotocol/related-task"?: {
|
||||
taskId: string;
|
||||
} | undefined;
|
||||
} | undefined;
|
||||
}>;
|
||||
unsubscribeResource(params: UnsubscribeRequest['params'], options?: RequestOptions): Promise<{
|
||||
_meta?: {
|
||||
[x: string]: unknown;
|
||||
progressToken?: string | number | undefined;
|
||||
"io.modelcontextprotocol/related-task"?: {
|
||||
taskId: string;
|
||||
} | undefined;
|
||||
} | undefined;
|
||||
}>;
|
||||
/**
|
||||
* Calls a tool and waits for the result. Automatically validates structured output if the tool has an outputSchema.
|
||||
*
|
||||
* For task-based execution with streaming behavior, use client.experimental.tasks.callToolStream() instead.
|
||||
*/
|
||||
callTool(params: CallToolRequest['params'], resultSchema?: typeof CallToolResultSchema | typeof CompatibilityCallToolResultSchema, options?: RequestOptions): Promise<{
|
||||
[x: string]: unknown;
|
||||
content: ({
|
||||
type: "text";
|
||||
text: string;
|
||||
annotations?: {
|
||||
audience?: ("user" | "assistant")[] | undefined;
|
||||
priority?: number | undefined;
|
||||
lastModified?: string | undefined;
|
||||
} | undefined;
|
||||
_meta?: Record<string, unknown> | undefined;
|
||||
} | {
|
||||
type: "image";
|
||||
data: string;
|
||||
mimeType: string;
|
||||
annotations?: {
|
||||
audience?: ("user" | "assistant")[] | undefined;
|
||||
priority?: number | undefined;
|
||||
lastModified?: string | undefined;
|
||||
} | undefined;
|
||||
_meta?: Record<string, unknown> | undefined;
|
||||
} | {
|
||||
type: "audio";
|
||||
data: string;
|
||||
mimeType: string;
|
||||
annotations?: {
|
||||
audience?: ("user" | "assistant")[] | undefined;
|
||||
priority?: number | undefined;
|
||||
lastModified?: string | undefined;
|
||||
} | undefined;
|
||||
_meta?: Record<string, unknown> | undefined;
|
||||
} | {
|
||||
type: "resource";
|
||||
resource: {
|
||||
uri: string;
|
||||
text: string;
|
||||
mimeType?: string | undefined;
|
||||
_meta?: Record<string, unknown> | undefined;
|
||||
} | {
|
||||
uri: string;
|
||||
blob: string;
|
||||
mimeType?: string | undefined;
|
||||
_meta?: Record<string, unknown> | undefined;
|
||||
};
|
||||
annotations?: {
|
||||
audience?: ("user" | "assistant")[] | undefined;
|
||||
priority?: number | undefined;
|
||||
lastModified?: string | undefined;
|
||||
} | undefined;
|
||||
_meta?: Record<string, unknown> | undefined;
|
||||
} | {
|
||||
uri: string;
|
||||
name: string;
|
||||
type: "resource_link";
|
||||
description?: string | undefined;
|
||||
mimeType?: string | undefined;
|
||||
annotations?: {
|
||||
audience?: ("user" | "assistant")[] | undefined;
|
||||
priority?: number | undefined;
|
||||
lastModified?: string | undefined;
|
||||
} | undefined;
|
||||
_meta?: {
|
||||
[x: string]: unknown;
|
||||
} | undefined;
|
||||
icons?: {
|
||||
src: string;
|
||||
mimeType?: string | undefined;
|
||||
sizes?: string[] | undefined;
|
||||
theme?: "light" | "dark" | undefined;
|
||||
}[] | undefined;
|
||||
title?: string | undefined;
|
||||
})[];
|
||||
_meta?: {
|
||||
[x: string]: unknown;
|
||||
progressToken?: string | number | undefined;
|
||||
"io.modelcontextprotocol/related-task"?: {
|
||||
taskId: string;
|
||||
} | undefined;
|
||||
} | undefined;
|
||||
structuredContent?: Record<string, unknown> | undefined;
|
||||
isError?: boolean | undefined;
|
||||
} | {
|
||||
[x: string]: unknown;
|
||||
toolResult: unknown;
|
||||
_meta?: {
|
||||
[x: string]: unknown;
|
||||
progressToken?: string | number | undefined;
|
||||
"io.modelcontextprotocol/related-task"?: {
|
||||
taskId: string;
|
||||
} | undefined;
|
||||
} | undefined;
|
||||
}>;
|
||||
private isToolTask;
|
||||
/**
|
||||
* Check if a tool requires task-based execution.
|
||||
* Unlike isToolTask which includes 'optional' tools, this only checks for 'required'.
|
||||
*/
|
||||
private isToolTaskRequired;
|
||||
/**
|
||||
* Cache validators for tool output schemas.
|
||||
* Called after listTools() to pre-compile validators for better performance.
|
||||
*/
|
||||
private cacheToolMetadata;
|
||||
/**
|
||||
* Get cached validator for a tool
|
||||
*/
|
||||
private getToolOutputValidator;
|
||||
listTools(params?: ListToolsRequest['params'], options?: RequestOptions): Promise<{
|
||||
[x: string]: unknown;
|
||||
tools: {
|
||||
inputSchema: {
|
||||
[x: string]: unknown;
|
||||
type: "object";
|
||||
properties?: Record<string, object> | undefined;
|
||||
required?: string[] | undefined;
|
||||
};
|
||||
name: string;
|
||||
description?: string | undefined;
|
||||
outputSchema?: {
|
||||
[x: string]: unknown;
|
||||
type: "object";
|
||||
properties?: Record<string, object> | undefined;
|
||||
required?: string[] | undefined;
|
||||
} | undefined;
|
||||
annotations?: {
|
||||
title?: string | undefined;
|
||||
readOnlyHint?: boolean | undefined;
|
||||
destructiveHint?: boolean | undefined;
|
||||
idempotentHint?: boolean | undefined;
|
||||
openWorldHint?: boolean | undefined;
|
||||
} | undefined;
|
||||
execution?: {
|
||||
taskSupport?: "optional" | "required" | "forbidden" | undefined;
|
||||
} | undefined;
|
||||
_meta?: Record<string, unknown> | undefined;
|
||||
icons?: {
|
||||
src: string;
|
||||
mimeType?: string | undefined;
|
||||
sizes?: string[] | undefined;
|
||||
theme?: "light" | "dark" | undefined;
|
||||
}[] | undefined;
|
||||
title?: string | undefined;
|
||||
}[];
|
||||
_meta?: {
|
||||
[x: string]: unknown;
|
||||
progressToken?: string | number | undefined;
|
||||
"io.modelcontextprotocol/related-task"?: {
|
||||
taskId: string;
|
||||
} | undefined;
|
||||
} | undefined;
|
||||
nextCursor?: string | undefined;
|
||||
}>;
|
||||
/**
|
||||
* Set up a single list changed handler.
|
||||
* @internal
|
||||
*/
|
||||
private _setupListChangedHandler;
|
||||
sendRootsListChanged(): Promise<void>;
|
||||
}
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
1
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/index.d.ts.map
generated
vendored
Normal file
1
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/index.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,QAAQ,EAAE,KAAK,eAAe,EAAE,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC/G,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD,OAAO,EACH,KAAK,eAAe,EACpB,oBAAoB,EACpB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,KAAK,iCAAiC,EACtC,KAAK,eAAe,EAIpB,KAAK,gBAAgB,EAErB,KAAK,cAAc,EAGnB,KAAK,kBAAkB,EAEvB,KAAK,oBAAoB,EAEzB,KAAK,4BAA4B,EAEjC,KAAK,gBAAgB,EAErB,KAAK,YAAY,EAEjB,KAAK,mBAAmB,EAExB,KAAK,kBAAkB,EAEvB,KAAK,gBAAgB,EAErB,KAAK,kBAAkB,EAYvB,KAAK,mBAAmB,EACxB,KAAK,OAAO,EACZ,KAAK,YAAY,EACjB,KAAK,MAAM,EACd,MAAM,aAAa,CAAC;AAErB,OAAO,KAAK,EAAuC,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AACvG,OAAO,EACH,eAAe,EACf,YAAY,EAMf,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAiD1E;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAAC,YAAY,EAAE,kBAAkB,CAAC,aAAa,CAAC,GAAG;IAC3F,gBAAgB,EAAE,OAAO,CAAC;IAC1B,eAAe,EAAE,OAAO,CAAC;CAC5B,CAaA;AAED,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG;IAC1C;;OAEG;IACH,YAAY,CAAC,EAAE,kBAAkB,CAAC;IAElC;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACH,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;IAE1C;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,WAAW,CAAC,EAAE,mBAAmB,CAAC;CACrC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,MAAM,CACf,QAAQ,SAAS,OAAO,GAAG,OAAO,EAClC,aAAa,SAAS,YAAY,GAAG,YAAY,EACjD,OAAO,SAAS,MAAM,GAAG,MAAM,CACjC,SAAQ,QAAQ,CAAC,aAAa,GAAG,QAAQ,EAAE,kBAAkB,GAAG,aAAa,EAAE,YAAY,GAAG,OAAO,CAAC;IAiBhG,OAAO,CAAC,WAAW;IAhBvB,OAAO,CAAC,mBAAmB,CAAC,CAAqB;IACjD,OAAO,CAAC,cAAc,CAAC,CAAiB;IACxC,OAAO,CAAC,aAAa,CAAqB;IAC1C,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,oBAAoB,CAAsB;IAClD,OAAO,CAAC,2BAA2B,CAAwD;IAC3F,OAAO,CAAC,qBAAqB,CAA0B;IACvD,OAAO,CAAC,wBAAwB,CAA0B;IAC1D,OAAO,CAAC,aAAa,CAAC,CAAuE;IAC7F,OAAO,CAAC,0BAA0B,CAAyD;IAC3F,OAAO,CAAC,yBAAyB,CAAC,CAAsB;IAExD;;OAEG;gBAES,WAAW,EAAE,cAAc,EACnC,OAAO,CAAC,EAAE,aAAa;IAY3B;;;;;OAKG;IACH,OAAO,CAAC,yBAAyB;IAuBjC;;;;;;OAMG;IACH,IAAI,YAAY,IAAI;QAAE,KAAK,EAAE,uBAAuB,CAAC,QAAQ,EAAE,aAAa,EAAE,OAAO,CAAC,CAAA;KAAE,CAOvF;IAED;;;;OAIG;IACI,oBAAoB,CAAC,YAAY,EAAE,kBAAkB,GAAG,IAAI;IAQnE;;OAEG;IACa,iBAAiB,CAAC,CAAC,SAAS,eAAe,EACvD,aAAa,EAAE,CAAC,EAChB,OAAO,EAAE,CACL,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EACxB,KAAK,EAAE,mBAAmB,CAAC,aAAa,GAAG,QAAQ,EAAE,kBAAkB,GAAG,aAAa,CAAC,KACvF,YAAY,GAAG,OAAO,GAAG,OAAO,CAAC,YAAY,GAAG,OAAO,CAAC,GAC9D,IAAI;IA8IP,SAAS,CAAC,gBAAgB,CAAC,UAAU,EAAE,MAAM,kBAAkB,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAMvE,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAsDrF;;OAEG;IACH,qBAAqB,IAAI,kBAAkB,GAAG,SAAS;IAIvD;;OAEG;IACH,gBAAgB,IAAI,cAAc,GAAG,SAAS;IAI9C;;OAEG;IACH,eAAe,IAAI,MAAM,GAAG,SAAS;IAIrC,SAAS,CAAC,yBAAyB,CAAC,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,GAAG,IAAI;IAqDrE,SAAS,CAAC,4BAA4B,CAAC,MAAM,EAAE,aAAa,CAAC,QAAQ,CAAC,GAAG,IAAI;IAsB7E,SAAS,CAAC,8BAA8B,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAyC9D,SAAS,CAAC,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAIpD,SAAS,CAAC,2BAA2B,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAUrD,IAAI,CAAC,OAAO,CAAC,EAAE,cAAc;;;;;;;;;IAI7B,QAAQ,CAAC,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,EAAE,cAAc;;;;;;;;;;;;;;;;IAIpE,eAAe,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,cAAc;;;;;;;;;IAI7D,SAAS,CAAC,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,EAAE,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAItE,WAAW,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,EAAE,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAI3E,aAAa,CAAC,MAAM,CAAC,EAAE,oBAAoB,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,EAAE,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAI/E,qBAAqB,CAAC,MAAM,CAAC,EAAE,4BAA4B,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,EAAE,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAI/F,YAAY,CAAC,MAAM,EAAE,mBAAmB,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,EAAE,cAAc;;;;;;;;;;;;;;;;;;;;;IAI5E,iBAAiB,CAAC,MAAM,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,EAAE,cAAc;;;;;;;;;IAI9E,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,EAAE,cAAc;;;;;;;;;IAIxF;;;;OAIG;IACG,QAAQ,CACV,MAAM,EAAE,eAAe,CAAC,QAAQ,CAAC,EACjC,YAAY,GAAE,OAAO,oBAAoB,GAAG,OAAO,iCAAwD,EAC3G,OAAO,CAAC,EAAE,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAkD5B,OAAO,CAAC,UAAU;IAQlB;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IAI1B;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAuBzB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAIxB,SAAS,CAAC,MAAM,CAAC,EAAE,gBAAgB,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,EAAE,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAS7E;;;OAGG;IACH,OAAO,CAAC,wBAAwB;IAwD1B,oBAAoB;CAG7B"}
|
||||
629
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/index.js
generated
vendored
Normal file
629
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/index.js
generated
vendored
Normal file
@@ -0,0 +1,629 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Client = void 0;
|
||||
exports.getSupportedElicitationModes = getSupportedElicitationModes;
|
||||
const protocol_js_1 = require("../shared/protocol.js");
|
||||
const types_js_1 = require("../types.js");
|
||||
const ajv_provider_js_1 = require("../validation/ajv-provider.js");
|
||||
const zod_compat_js_1 = require("../server/zod-compat.js");
|
||||
const client_js_1 = require("../experimental/tasks/client.js");
|
||||
const helpers_js_1 = require("../experimental/tasks/helpers.js");
|
||||
/**
|
||||
* Elicitation default application helper. Applies defaults to the data based on the schema.
|
||||
*
|
||||
* @param schema - The schema to apply defaults to.
|
||||
* @param data - The data to apply defaults to.
|
||||
*/
|
||||
function applyElicitationDefaults(schema, data) {
|
||||
if (!schema || data === null || typeof data !== 'object')
|
||||
return;
|
||||
// Handle object properties
|
||||
if (schema.type === 'object' && schema.properties && typeof schema.properties === 'object') {
|
||||
const obj = data;
|
||||
const props = schema.properties;
|
||||
for (const key of Object.keys(props)) {
|
||||
const propSchema = props[key];
|
||||
// If missing or explicitly undefined, apply default if present
|
||||
if (obj[key] === undefined && Object.prototype.hasOwnProperty.call(propSchema, 'default')) {
|
||||
obj[key] = propSchema.default;
|
||||
}
|
||||
// Recurse into existing nested objects/arrays
|
||||
if (obj[key] !== undefined) {
|
||||
applyElicitationDefaults(propSchema, obj[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Array.isArray(schema.anyOf)) {
|
||||
for (const sub of schema.anyOf) {
|
||||
// Skip boolean schemas (true/false are valid JSON Schemas but have no defaults)
|
||||
if (typeof sub !== 'boolean') {
|
||||
applyElicitationDefaults(sub, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Combine schemas
|
||||
if (Array.isArray(schema.oneOf)) {
|
||||
for (const sub of schema.oneOf) {
|
||||
// Skip boolean schemas (true/false are valid JSON Schemas but have no defaults)
|
||||
if (typeof sub !== 'boolean') {
|
||||
applyElicitationDefaults(sub, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Determines which elicitation modes are supported based on declared client capabilities.
|
||||
*
|
||||
* According to the spec:
|
||||
* - An empty elicitation capability object defaults to form mode support (backwards compatibility)
|
||||
* - URL mode is only supported if explicitly declared
|
||||
*
|
||||
* @param capabilities - The client's elicitation capabilities
|
||||
* @returns An object indicating which modes are supported
|
||||
*/
|
||||
function getSupportedElicitationModes(capabilities) {
|
||||
if (!capabilities) {
|
||||
return { supportsFormMode: false, supportsUrlMode: false };
|
||||
}
|
||||
const hasFormCapability = capabilities.form !== undefined;
|
||||
const hasUrlCapability = capabilities.url !== undefined;
|
||||
// If neither form nor url are explicitly declared, form mode is supported (backwards compatibility)
|
||||
const supportsFormMode = hasFormCapability || (!hasFormCapability && !hasUrlCapability);
|
||||
const supportsUrlMode = hasUrlCapability;
|
||||
return { supportsFormMode, supportsUrlMode };
|
||||
}
|
||||
/**
|
||||
* An MCP client on top of a pluggable transport.
|
||||
*
|
||||
* The client will automatically begin the initialization flow with the server when connect() is called.
|
||||
*
|
||||
* To use with custom types, extend the base Request/Notification/Result types and pass them as type parameters:
|
||||
*
|
||||
* ```typescript
|
||||
* // Custom schemas
|
||||
* const CustomRequestSchema = RequestSchema.extend({...})
|
||||
* const CustomNotificationSchema = NotificationSchema.extend({...})
|
||||
* const CustomResultSchema = ResultSchema.extend({...})
|
||||
*
|
||||
* // Type aliases
|
||||
* type CustomRequest = z.infer<typeof CustomRequestSchema>
|
||||
* type CustomNotification = z.infer<typeof CustomNotificationSchema>
|
||||
* type CustomResult = z.infer<typeof CustomResultSchema>
|
||||
*
|
||||
* // Create typed client
|
||||
* const client = new Client<CustomRequest, CustomNotification, CustomResult>({
|
||||
* name: "CustomClient",
|
||||
* version: "1.0.0"
|
||||
* })
|
||||
* ```
|
||||
*/
|
||||
class Client extends protocol_js_1.Protocol {
|
||||
/**
|
||||
* Initializes this client with the given name and version information.
|
||||
*/
|
||||
constructor(_clientInfo, options) {
|
||||
super(options);
|
||||
this._clientInfo = _clientInfo;
|
||||
this._cachedToolOutputValidators = new Map();
|
||||
this._cachedKnownTaskTools = new Set();
|
||||
this._cachedRequiredTaskTools = new Set();
|
||||
this._listChangedDebounceTimers = new Map();
|
||||
this._capabilities = options?.capabilities ?? {};
|
||||
this._jsonSchemaValidator = options?.jsonSchemaValidator ?? new ajv_provider_js_1.AjvJsonSchemaValidator();
|
||||
// Store list changed config for setup after connection (when we know server capabilities)
|
||||
if (options?.listChanged) {
|
||||
this._pendingListChangedConfig = options.listChanged;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Set up handlers for list changed notifications based on config and server capabilities.
|
||||
* This should only be called after initialization when server capabilities are known.
|
||||
* Handlers are silently skipped if the server doesn't advertise the corresponding listChanged capability.
|
||||
* @internal
|
||||
*/
|
||||
_setupListChangedHandlers(config) {
|
||||
if (config.tools && this._serverCapabilities?.tools?.listChanged) {
|
||||
this._setupListChangedHandler('tools', types_js_1.ToolListChangedNotificationSchema, config.tools, async () => {
|
||||
const result = await this.listTools();
|
||||
return result.tools;
|
||||
});
|
||||
}
|
||||
if (config.prompts && this._serverCapabilities?.prompts?.listChanged) {
|
||||
this._setupListChangedHandler('prompts', types_js_1.PromptListChangedNotificationSchema, config.prompts, async () => {
|
||||
const result = await this.listPrompts();
|
||||
return result.prompts;
|
||||
});
|
||||
}
|
||||
if (config.resources && this._serverCapabilities?.resources?.listChanged) {
|
||||
this._setupListChangedHandler('resources', types_js_1.ResourceListChangedNotificationSchema, config.resources, async () => {
|
||||
const result = await this.listResources();
|
||||
return result.resources;
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Access experimental features.
|
||||
*
|
||||
* WARNING: These APIs are experimental and may change without notice.
|
||||
*
|
||||
* @experimental
|
||||
*/
|
||||
get experimental() {
|
||||
if (!this._experimental) {
|
||||
this._experimental = {
|
||||
tasks: new client_js_1.ExperimentalClientTasks(this)
|
||||
};
|
||||
}
|
||||
return this._experimental;
|
||||
}
|
||||
/**
|
||||
* Registers new capabilities. This can only be called before connecting to a transport.
|
||||
*
|
||||
* The new capabilities will be merged with any existing capabilities previously given (e.g., at initialization).
|
||||
*/
|
||||
registerCapabilities(capabilities) {
|
||||
if (this.transport) {
|
||||
throw new Error('Cannot register capabilities after connecting to transport');
|
||||
}
|
||||
this._capabilities = (0, protocol_js_1.mergeCapabilities)(this._capabilities, capabilities);
|
||||
}
|
||||
/**
|
||||
* Override request handler registration to enforce client-side validation for elicitation.
|
||||
*/
|
||||
setRequestHandler(requestSchema, handler) {
|
||||
const shape = (0, zod_compat_js_1.getObjectShape)(requestSchema);
|
||||
const methodSchema = shape?.method;
|
||||
if (!methodSchema) {
|
||||
throw new Error('Schema is missing a method literal');
|
||||
}
|
||||
// Extract literal value using type-safe property access
|
||||
let methodValue;
|
||||
if ((0, zod_compat_js_1.isZ4Schema)(methodSchema)) {
|
||||
const v4Schema = methodSchema;
|
||||
const v4Def = v4Schema._zod?.def;
|
||||
methodValue = v4Def?.value ?? v4Schema.value;
|
||||
}
|
||||
else {
|
||||
const v3Schema = methodSchema;
|
||||
const legacyDef = v3Schema._def;
|
||||
methodValue = legacyDef?.value ?? v3Schema.value;
|
||||
}
|
||||
if (typeof methodValue !== 'string') {
|
||||
throw new Error('Schema method literal must be a string');
|
||||
}
|
||||
const method = methodValue;
|
||||
if (method === 'elicitation/create') {
|
||||
const wrappedHandler = async (request, extra) => {
|
||||
const validatedRequest = (0, zod_compat_js_1.safeParse)(types_js_1.ElicitRequestSchema, request);
|
||||
if (!validatedRequest.success) {
|
||||
// Type guard: if success is false, error is guaranteed to exist
|
||||
const errorMessage = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
|
||||
throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Invalid elicitation request: ${errorMessage}`);
|
||||
}
|
||||
const { params } = validatedRequest.data;
|
||||
params.mode = params.mode ?? 'form';
|
||||
const { supportsFormMode, supportsUrlMode } = getSupportedElicitationModes(this._capabilities.elicitation);
|
||||
if (params.mode === 'form' && !supportsFormMode) {
|
||||
throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, 'Client does not support form-mode elicitation requests');
|
||||
}
|
||||
if (params.mode === 'url' && !supportsUrlMode) {
|
||||
throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, 'Client does not support URL-mode elicitation requests');
|
||||
}
|
||||
const result = await Promise.resolve(handler(request, extra));
|
||||
// When task creation is requested, validate and return CreateTaskResult
|
||||
if (params.task) {
|
||||
const taskValidationResult = (0, zod_compat_js_1.safeParse)(types_js_1.CreateTaskResultSchema, result);
|
||||
if (!taskValidationResult.success) {
|
||||
const errorMessage = taskValidationResult.error instanceof Error
|
||||
? taskValidationResult.error.message
|
||||
: String(taskValidationResult.error);
|
||||
throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Invalid task creation result: ${errorMessage}`);
|
||||
}
|
||||
return taskValidationResult.data;
|
||||
}
|
||||
// For non-task requests, validate against ElicitResultSchema
|
||||
const validationResult = (0, zod_compat_js_1.safeParse)(types_js_1.ElicitResultSchema, result);
|
||||
if (!validationResult.success) {
|
||||
// Type guard: if success is false, error is guaranteed to exist
|
||||
const errorMessage = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
|
||||
throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Invalid elicitation result: ${errorMessage}`);
|
||||
}
|
||||
const validatedResult = validationResult.data;
|
||||
const requestedSchema = params.mode === 'form' ? params.requestedSchema : undefined;
|
||||
if (params.mode === 'form' && validatedResult.action === 'accept' && validatedResult.content && requestedSchema) {
|
||||
if (this._capabilities.elicitation?.form?.applyDefaults) {
|
||||
try {
|
||||
applyElicitationDefaults(requestedSchema, validatedResult.content);
|
||||
}
|
||||
catch {
|
||||
// gracefully ignore errors in default application
|
||||
}
|
||||
}
|
||||
}
|
||||
return validatedResult;
|
||||
};
|
||||
// Install the wrapped handler
|
||||
return super.setRequestHandler(requestSchema, wrappedHandler);
|
||||
}
|
||||
if (method === 'sampling/createMessage') {
|
||||
const wrappedHandler = async (request, extra) => {
|
||||
const validatedRequest = (0, zod_compat_js_1.safeParse)(types_js_1.CreateMessageRequestSchema, request);
|
||||
if (!validatedRequest.success) {
|
||||
const errorMessage = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
|
||||
throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Invalid sampling request: ${errorMessage}`);
|
||||
}
|
||||
const { params } = validatedRequest.data;
|
||||
const result = await Promise.resolve(handler(request, extra));
|
||||
// When task creation is requested, validate and return CreateTaskResult
|
||||
if (params.task) {
|
||||
const taskValidationResult = (0, zod_compat_js_1.safeParse)(types_js_1.CreateTaskResultSchema, result);
|
||||
if (!taskValidationResult.success) {
|
||||
const errorMessage = taskValidationResult.error instanceof Error
|
||||
? taskValidationResult.error.message
|
||||
: String(taskValidationResult.error);
|
||||
throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Invalid task creation result: ${errorMessage}`);
|
||||
}
|
||||
return taskValidationResult.data;
|
||||
}
|
||||
// For non-task requests, validate against appropriate schema based on tools presence
|
||||
const hasTools = params.tools || params.toolChoice;
|
||||
const resultSchema = hasTools ? types_js_1.CreateMessageResultWithToolsSchema : types_js_1.CreateMessageResultSchema;
|
||||
const validationResult = (0, zod_compat_js_1.safeParse)(resultSchema, result);
|
||||
if (!validationResult.success) {
|
||||
const errorMessage = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
|
||||
throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Invalid sampling result: ${errorMessage}`);
|
||||
}
|
||||
return validationResult.data;
|
||||
};
|
||||
// Install the wrapped handler
|
||||
return super.setRequestHandler(requestSchema, wrappedHandler);
|
||||
}
|
||||
// Other handlers use default behavior
|
||||
return super.setRequestHandler(requestSchema, handler);
|
||||
}
|
||||
assertCapability(capability, method) {
|
||||
if (!this._serverCapabilities?.[capability]) {
|
||||
throw new Error(`Server does not support ${capability} (required for ${method})`);
|
||||
}
|
||||
}
|
||||
async connect(transport, options) {
|
||||
await super.connect(transport);
|
||||
// When transport sessionId is already set this means we are trying to reconnect.
|
||||
// In this case we don't need to initialize again.
|
||||
if (transport.sessionId !== undefined) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const result = await this.request({
|
||||
method: 'initialize',
|
||||
params: {
|
||||
protocolVersion: types_js_1.LATEST_PROTOCOL_VERSION,
|
||||
capabilities: this._capabilities,
|
||||
clientInfo: this._clientInfo
|
||||
}
|
||||
}, types_js_1.InitializeResultSchema, options);
|
||||
if (result === undefined) {
|
||||
throw new Error(`Server sent invalid initialize result: ${result}`);
|
||||
}
|
||||
if (!types_js_1.SUPPORTED_PROTOCOL_VERSIONS.includes(result.protocolVersion)) {
|
||||
throw new Error(`Server's protocol version is not supported: ${result.protocolVersion}`);
|
||||
}
|
||||
this._serverCapabilities = result.capabilities;
|
||||
this._serverVersion = result.serverInfo;
|
||||
// HTTP transports must set the protocol version in each header after initialization.
|
||||
if (transport.setProtocolVersion) {
|
||||
transport.setProtocolVersion(result.protocolVersion);
|
||||
}
|
||||
this._instructions = result.instructions;
|
||||
await this.notification({
|
||||
method: 'notifications/initialized'
|
||||
});
|
||||
// Set up list changed handlers now that we know server capabilities
|
||||
if (this._pendingListChangedConfig) {
|
||||
this._setupListChangedHandlers(this._pendingListChangedConfig);
|
||||
this._pendingListChangedConfig = undefined;
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
// Disconnect if initialization fails.
|
||||
void this.close();
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* After initialization has completed, this will be populated with the server's reported capabilities.
|
||||
*/
|
||||
getServerCapabilities() {
|
||||
return this._serverCapabilities;
|
||||
}
|
||||
/**
|
||||
* After initialization has completed, this will be populated with information about the server's name and version.
|
||||
*/
|
||||
getServerVersion() {
|
||||
return this._serverVersion;
|
||||
}
|
||||
/**
|
||||
* After initialization has completed, this may be populated with information about the server's instructions.
|
||||
*/
|
||||
getInstructions() {
|
||||
return this._instructions;
|
||||
}
|
||||
assertCapabilityForMethod(method) {
|
||||
switch (method) {
|
||||
case 'logging/setLevel':
|
||||
if (!this._serverCapabilities?.logging) {
|
||||
throw new Error(`Server does not support logging (required for ${method})`);
|
||||
}
|
||||
break;
|
||||
case 'prompts/get':
|
||||
case 'prompts/list':
|
||||
if (!this._serverCapabilities?.prompts) {
|
||||
throw new Error(`Server does not support prompts (required for ${method})`);
|
||||
}
|
||||
break;
|
||||
case 'resources/list':
|
||||
case 'resources/templates/list':
|
||||
case 'resources/read':
|
||||
case 'resources/subscribe':
|
||||
case 'resources/unsubscribe':
|
||||
if (!this._serverCapabilities?.resources) {
|
||||
throw new Error(`Server does not support resources (required for ${method})`);
|
||||
}
|
||||
if (method === 'resources/subscribe' && !this._serverCapabilities.resources.subscribe) {
|
||||
throw new Error(`Server does not support resource subscriptions (required for ${method})`);
|
||||
}
|
||||
break;
|
||||
case 'tools/call':
|
||||
case 'tools/list':
|
||||
if (!this._serverCapabilities?.tools) {
|
||||
throw new Error(`Server does not support tools (required for ${method})`);
|
||||
}
|
||||
break;
|
||||
case 'completion/complete':
|
||||
if (!this._serverCapabilities?.completions) {
|
||||
throw new Error(`Server does not support completions (required for ${method})`);
|
||||
}
|
||||
break;
|
||||
case 'initialize':
|
||||
// No specific capability required for initialize
|
||||
break;
|
||||
case 'ping':
|
||||
// No specific capability required for ping
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertNotificationCapability(method) {
|
||||
switch (method) {
|
||||
case 'notifications/roots/list_changed':
|
||||
if (!this._capabilities.roots?.listChanged) {
|
||||
throw new Error(`Client does not support roots list changed notifications (required for ${method})`);
|
||||
}
|
||||
break;
|
||||
case 'notifications/initialized':
|
||||
// No specific capability required for initialized
|
||||
break;
|
||||
case 'notifications/cancelled':
|
||||
// Cancellation notifications are always allowed
|
||||
break;
|
||||
case 'notifications/progress':
|
||||
// Progress notifications are always allowed
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertRequestHandlerCapability(method) {
|
||||
// Task handlers are registered in Protocol constructor before _capabilities is initialized
|
||||
// Skip capability check for task methods during initialization
|
||||
if (!this._capabilities) {
|
||||
return;
|
||||
}
|
||||
switch (method) {
|
||||
case 'sampling/createMessage':
|
||||
if (!this._capabilities.sampling) {
|
||||
throw new Error(`Client does not support sampling capability (required for ${method})`);
|
||||
}
|
||||
break;
|
||||
case 'elicitation/create':
|
||||
if (!this._capabilities.elicitation) {
|
||||
throw new Error(`Client does not support elicitation capability (required for ${method})`);
|
||||
}
|
||||
break;
|
||||
case 'roots/list':
|
||||
if (!this._capabilities.roots) {
|
||||
throw new Error(`Client does not support roots capability (required for ${method})`);
|
||||
}
|
||||
break;
|
||||
case 'tasks/get':
|
||||
case 'tasks/list':
|
||||
case 'tasks/result':
|
||||
case 'tasks/cancel':
|
||||
if (!this._capabilities.tasks) {
|
||||
throw new Error(`Client does not support tasks capability (required for ${method})`);
|
||||
}
|
||||
break;
|
||||
case 'ping':
|
||||
// No specific capability required for ping
|
||||
break;
|
||||
}
|
||||
}
|
||||
assertTaskCapability(method) {
|
||||
(0, helpers_js_1.assertToolsCallTaskCapability)(this._serverCapabilities?.tasks?.requests, method, 'Server');
|
||||
}
|
||||
assertTaskHandlerCapability(method) {
|
||||
// Task handlers are registered in Protocol constructor before _capabilities is initialized
|
||||
// Skip capability check for task methods during initialization
|
||||
if (!this._capabilities) {
|
||||
return;
|
||||
}
|
||||
(0, helpers_js_1.assertClientRequestTaskCapability)(this._capabilities.tasks?.requests, method, 'Client');
|
||||
}
|
||||
async ping(options) {
|
||||
return this.request({ method: 'ping' }, types_js_1.EmptyResultSchema, options);
|
||||
}
|
||||
async complete(params, options) {
|
||||
return this.request({ method: 'completion/complete', params }, types_js_1.CompleteResultSchema, options);
|
||||
}
|
||||
async setLoggingLevel(level, options) {
|
||||
return this.request({ method: 'logging/setLevel', params: { level } }, types_js_1.EmptyResultSchema, options);
|
||||
}
|
||||
async getPrompt(params, options) {
|
||||
return this.request({ method: 'prompts/get', params }, types_js_1.GetPromptResultSchema, options);
|
||||
}
|
||||
async listPrompts(params, options) {
|
||||
return this.request({ method: 'prompts/list', params }, types_js_1.ListPromptsResultSchema, options);
|
||||
}
|
||||
async listResources(params, options) {
|
||||
return this.request({ method: 'resources/list', params }, types_js_1.ListResourcesResultSchema, options);
|
||||
}
|
||||
async listResourceTemplates(params, options) {
|
||||
return this.request({ method: 'resources/templates/list', params }, types_js_1.ListResourceTemplatesResultSchema, options);
|
||||
}
|
||||
async readResource(params, options) {
|
||||
return this.request({ method: 'resources/read', params }, types_js_1.ReadResourceResultSchema, options);
|
||||
}
|
||||
async subscribeResource(params, options) {
|
||||
return this.request({ method: 'resources/subscribe', params }, types_js_1.EmptyResultSchema, options);
|
||||
}
|
||||
async unsubscribeResource(params, options) {
|
||||
return this.request({ method: 'resources/unsubscribe', params }, types_js_1.EmptyResultSchema, options);
|
||||
}
|
||||
/**
|
||||
* Calls a tool and waits for the result. Automatically validates structured output if the tool has an outputSchema.
|
||||
*
|
||||
* For task-based execution with streaming behavior, use client.experimental.tasks.callToolStream() instead.
|
||||
*/
|
||||
async callTool(params, resultSchema = types_js_1.CallToolResultSchema, options) {
|
||||
// Guard: required-task tools need experimental API
|
||||
if (this.isToolTaskRequired(params.name)) {
|
||||
throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest, `Tool "${params.name}" requires task-based execution. Use client.experimental.tasks.callToolStream() instead.`);
|
||||
}
|
||||
const result = await this.request({ method: 'tools/call', params }, resultSchema, options);
|
||||
// Check if the tool has an outputSchema
|
||||
const validator = this.getToolOutputValidator(params.name);
|
||||
if (validator) {
|
||||
// If tool has outputSchema, it MUST return structuredContent (unless it's an error)
|
||||
if (!result.structuredContent && !result.isError) {
|
||||
throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidRequest, `Tool ${params.name} has an output schema but did not return structured content`);
|
||||
}
|
||||
// Only validate structured content if present (not when there's an error)
|
||||
if (result.structuredContent) {
|
||||
try {
|
||||
// Validate the structured content against the schema
|
||||
const validationResult = validator(result.structuredContent);
|
||||
if (!validationResult.valid) {
|
||||
throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Structured content does not match the tool's output schema: ${validationResult.errorMessage}`);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof types_js_1.McpError) {
|
||||
throw error;
|
||||
}
|
||||
throw new types_js_1.McpError(types_js_1.ErrorCode.InvalidParams, `Failed to validate structured content: ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
isToolTask(toolName) {
|
||||
if (!this._serverCapabilities?.tasks?.requests?.tools?.call) {
|
||||
return false;
|
||||
}
|
||||
return this._cachedKnownTaskTools.has(toolName);
|
||||
}
|
||||
/**
|
||||
* Check if a tool requires task-based execution.
|
||||
* Unlike isToolTask which includes 'optional' tools, this only checks for 'required'.
|
||||
*/
|
||||
isToolTaskRequired(toolName) {
|
||||
return this._cachedRequiredTaskTools.has(toolName);
|
||||
}
|
||||
/**
|
||||
* Cache validators for tool output schemas.
|
||||
* Called after listTools() to pre-compile validators for better performance.
|
||||
*/
|
||||
cacheToolMetadata(tools) {
|
||||
this._cachedToolOutputValidators.clear();
|
||||
this._cachedKnownTaskTools.clear();
|
||||
this._cachedRequiredTaskTools.clear();
|
||||
for (const tool of tools) {
|
||||
// If the tool has an outputSchema, create and cache the validator
|
||||
if (tool.outputSchema) {
|
||||
const toolValidator = this._jsonSchemaValidator.getValidator(tool.outputSchema);
|
||||
this._cachedToolOutputValidators.set(tool.name, toolValidator);
|
||||
}
|
||||
// If the tool supports task-based execution, cache that information
|
||||
const taskSupport = tool.execution?.taskSupport;
|
||||
if (taskSupport === 'required' || taskSupport === 'optional') {
|
||||
this._cachedKnownTaskTools.add(tool.name);
|
||||
}
|
||||
if (taskSupport === 'required') {
|
||||
this._cachedRequiredTaskTools.add(tool.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get cached validator for a tool
|
||||
*/
|
||||
getToolOutputValidator(toolName) {
|
||||
return this._cachedToolOutputValidators.get(toolName);
|
||||
}
|
||||
async listTools(params, options) {
|
||||
const result = await this.request({ method: 'tools/list', params }, types_js_1.ListToolsResultSchema, options);
|
||||
// Cache the tools and their output schemas for future validation
|
||||
this.cacheToolMetadata(result.tools);
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Set up a single list changed handler.
|
||||
* @internal
|
||||
*/
|
||||
_setupListChangedHandler(listType, notificationSchema, options, fetcher) {
|
||||
// Validate options using Zod schema (validates autoRefresh and debounceMs)
|
||||
const parseResult = types_js_1.ListChangedOptionsBaseSchema.safeParse(options);
|
||||
if (!parseResult.success) {
|
||||
throw new Error(`Invalid ${listType} listChanged options: ${parseResult.error.message}`);
|
||||
}
|
||||
// Validate callback
|
||||
if (typeof options.onChanged !== 'function') {
|
||||
throw new Error(`Invalid ${listType} listChanged options: onChanged must be a function`);
|
||||
}
|
||||
const { autoRefresh, debounceMs } = parseResult.data;
|
||||
const { onChanged } = options;
|
||||
const refresh = async () => {
|
||||
if (!autoRefresh) {
|
||||
onChanged(null, null);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const items = await fetcher();
|
||||
onChanged(null, items);
|
||||
}
|
||||
catch (e) {
|
||||
const error = e instanceof Error ? e : new Error(String(e));
|
||||
onChanged(error, null);
|
||||
}
|
||||
};
|
||||
const handler = () => {
|
||||
if (debounceMs) {
|
||||
// Clear any pending debounce timer for this list type
|
||||
const existingTimer = this._listChangedDebounceTimers.get(listType);
|
||||
if (existingTimer) {
|
||||
clearTimeout(existingTimer);
|
||||
}
|
||||
// Set up debounced refresh
|
||||
const timer = setTimeout(refresh, debounceMs);
|
||||
this._listChangedDebounceTimers.set(listType, timer);
|
||||
}
|
||||
else {
|
||||
// No debounce, refresh immediately
|
||||
refresh();
|
||||
}
|
||||
};
|
||||
// Register notification handler
|
||||
this.setNotificationHandler(notificationSchema, handler);
|
||||
}
|
||||
async sendRootsListChanged() {
|
||||
return this.notification({ method: 'notifications/roots/list_changed' });
|
||||
}
|
||||
}
|
||||
exports.Client = Client;
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/index.js.map
generated
vendored
Normal file
1
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/index.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
169
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/middleware.d.ts
generated
vendored
Normal file
169
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/middleware.d.ts
generated
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
import { OAuthClientProvider } from './auth.js';
|
||||
import { FetchLike } from '../shared/transport.js';
|
||||
/**
|
||||
* Middleware function that wraps and enhances fetch functionality.
|
||||
* Takes a fetch handler and returns an enhanced fetch handler.
|
||||
*/
|
||||
export type Middleware = (next: FetchLike) => FetchLike;
|
||||
/**
|
||||
* Creates a fetch wrapper that handles OAuth authentication automatically.
|
||||
*
|
||||
* This wrapper will:
|
||||
* - Add Authorization headers with access tokens
|
||||
* - Handle 401 responses by attempting re-authentication
|
||||
* - Retry the original request after successful auth
|
||||
* - Handle OAuth errors appropriately (InvalidClientError, etc.)
|
||||
*
|
||||
* The baseUrl parameter is optional and defaults to using the domain from the request URL.
|
||||
* However, you should explicitly provide baseUrl when:
|
||||
* - Making requests to multiple subdomains (e.g., api.example.com, cdn.example.com)
|
||||
* - Using API paths that differ from OAuth discovery paths (e.g., requesting /api/v1/data but OAuth is at /)
|
||||
* - The OAuth server is on a different domain than your API requests
|
||||
* - You want to ensure consistent OAuth behavior regardless of request URLs
|
||||
*
|
||||
* For MCP transports, set baseUrl to the same URL you pass to the transport constructor.
|
||||
*
|
||||
* Note: This wrapper is designed for general-purpose fetch operations.
|
||||
* MCP transports (SSE and StreamableHTTP) already have built-in OAuth handling
|
||||
* and should not need this wrapper.
|
||||
*
|
||||
* @param provider - OAuth client provider for authentication
|
||||
* @param baseUrl - Base URL for OAuth server discovery (defaults to request URL domain)
|
||||
* @returns A fetch middleware function
|
||||
*/
|
||||
export declare const withOAuth: (provider: OAuthClientProvider, baseUrl?: string | URL) => Middleware;
|
||||
/**
|
||||
* Logger function type for HTTP requests
|
||||
*/
|
||||
export type RequestLogger = (input: {
|
||||
method: string;
|
||||
url: string | URL;
|
||||
status: number;
|
||||
statusText: string;
|
||||
duration: number;
|
||||
requestHeaders?: Headers;
|
||||
responseHeaders?: Headers;
|
||||
error?: Error;
|
||||
}) => void;
|
||||
/**
|
||||
* Configuration options for the logging middleware
|
||||
*/
|
||||
export type LoggingOptions = {
|
||||
/**
|
||||
* Custom logger function, defaults to console logging
|
||||
*/
|
||||
logger?: RequestLogger;
|
||||
/**
|
||||
* Whether to include request headers in logs
|
||||
* @default false
|
||||
*/
|
||||
includeRequestHeaders?: boolean;
|
||||
/**
|
||||
* Whether to include response headers in logs
|
||||
* @default false
|
||||
*/
|
||||
includeResponseHeaders?: boolean;
|
||||
/**
|
||||
* Status level filter - only log requests with status >= this value
|
||||
* Set to 0 to log all requests, 400 to log only errors
|
||||
* @default 0
|
||||
*/
|
||||
statusLevel?: number;
|
||||
};
|
||||
/**
|
||||
* Creates a fetch middleware that logs HTTP requests and responses.
|
||||
*
|
||||
* When called without arguments `withLogging()`, it uses the default logger that:
|
||||
* - Logs successful requests (2xx) to `console.log`
|
||||
* - Logs error responses (4xx/5xx) and network errors to `console.error`
|
||||
* - Logs all requests regardless of status (statusLevel: 0)
|
||||
* - Does not include request or response headers in logs
|
||||
* - Measures and displays request duration in milliseconds
|
||||
*
|
||||
* Important: the default logger uses both `console.log` and `console.error` so it should not be used with
|
||||
* `stdio` transports and applications.
|
||||
*
|
||||
* @param options - Logging configuration options
|
||||
* @returns A fetch middleware function
|
||||
*/
|
||||
export declare const withLogging: (options?: LoggingOptions) => Middleware;
|
||||
/**
|
||||
* Composes multiple fetch middleware functions into a single middleware pipeline.
|
||||
* Middleware are applied in the order they appear, creating a chain of handlers.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Create a middleware pipeline that handles both OAuth and logging
|
||||
* const enhancedFetch = applyMiddlewares(
|
||||
* withOAuth(oauthProvider, 'https://api.example.com'),
|
||||
* withLogging({ statusLevel: 400 })
|
||||
* )(fetch);
|
||||
*
|
||||
* // Use the enhanced fetch - it will handle auth and log errors
|
||||
* const response = await enhancedFetch('https://api.example.com/data');
|
||||
* ```
|
||||
*
|
||||
* @param middleware - Array of fetch middleware to compose into a pipeline
|
||||
* @returns A single composed middleware function
|
||||
*/
|
||||
export declare const applyMiddlewares: (...middleware: Middleware[]) => Middleware;
|
||||
/**
|
||||
* Helper function to create custom fetch middleware with cleaner syntax.
|
||||
* Provides the next handler and request details as separate parameters for easier access.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Create custom authentication middleware
|
||||
* const customAuthMiddleware = createMiddleware(async (next, input, init) => {
|
||||
* const headers = new Headers(init?.headers);
|
||||
* headers.set('X-Custom-Auth', 'my-token');
|
||||
*
|
||||
* const response = await next(input, { ...init, headers });
|
||||
*
|
||||
* if (response.status === 401) {
|
||||
* console.log('Authentication failed');
|
||||
* }
|
||||
*
|
||||
* return response;
|
||||
* });
|
||||
*
|
||||
* // Create conditional middleware
|
||||
* const conditionalMiddleware = createMiddleware(async (next, input, init) => {
|
||||
* const url = typeof input === 'string' ? input : input.toString();
|
||||
*
|
||||
* // Only add headers for API routes
|
||||
* if (url.includes('/api/')) {
|
||||
* const headers = new Headers(init?.headers);
|
||||
* headers.set('X-API-Version', 'v2');
|
||||
* return next(input, { ...init, headers });
|
||||
* }
|
||||
*
|
||||
* // Pass through for non-API routes
|
||||
* return next(input, init);
|
||||
* });
|
||||
*
|
||||
* // Create caching middleware
|
||||
* const cacheMiddleware = createMiddleware(async (next, input, init) => {
|
||||
* const cacheKey = typeof input === 'string' ? input : input.toString();
|
||||
*
|
||||
* // Check cache first
|
||||
* const cached = await getFromCache(cacheKey);
|
||||
* if (cached) {
|
||||
* return new Response(cached, { status: 200 });
|
||||
* }
|
||||
*
|
||||
* // Make request and cache result
|
||||
* const response = await next(input, init);
|
||||
* if (response.ok) {
|
||||
* await saveToCache(cacheKey, await response.clone().text());
|
||||
* }
|
||||
*
|
||||
* return response;
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @param handler - Function that receives the next handler and request parameters
|
||||
* @returns A fetch middleware function
|
||||
*/
|
||||
export declare const createMiddleware: (handler: (next: FetchLike, input: string | URL, init?: RequestInit) => Promise<Response>) => Middleware;
|
||||
//# sourceMappingURL=middleware.d.ts.map
|
||||
1
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/middleware.d.ts.map
generated
vendored
Normal file
1
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/middleware.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../../src/client/middleware.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,mBAAmB,EAAqB,MAAM,WAAW,CAAC;AACvG,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnD;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,SAAS,KAAK,SAAS,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,SAAS,aACP,mBAAmB,YAAY,MAAM,GAAG,GAAG,KAAG,UA0DxD,CAAC;AAEN;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC;CACjB,KAAK,IAAI,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IACzB;;OAEG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;IAEvB;;;OAGG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAEhC;;;OAGG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;;OAIG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,WAAW,aAAa,cAAc,KAAQ,UA6E1D,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,gBAAgB,kBAAmB,UAAU,EAAE,KAAG,UAI9D,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACH,eAAO,MAAM,gBAAgB,YAAa,CAAC,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,GAAG,GAAG,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,KAAG,UAE3H,CAAC"}
|
||||
252
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/middleware.js
generated
vendored
Normal file
252
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/middleware.js
generated
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.createMiddleware = exports.applyMiddlewares = exports.withLogging = exports.withOAuth = void 0;
|
||||
const auth_js_1 = require("./auth.js");
|
||||
/**
|
||||
* Creates a fetch wrapper that handles OAuth authentication automatically.
|
||||
*
|
||||
* This wrapper will:
|
||||
* - Add Authorization headers with access tokens
|
||||
* - Handle 401 responses by attempting re-authentication
|
||||
* - Retry the original request after successful auth
|
||||
* - Handle OAuth errors appropriately (InvalidClientError, etc.)
|
||||
*
|
||||
* The baseUrl parameter is optional and defaults to using the domain from the request URL.
|
||||
* However, you should explicitly provide baseUrl when:
|
||||
* - Making requests to multiple subdomains (e.g., api.example.com, cdn.example.com)
|
||||
* - Using API paths that differ from OAuth discovery paths (e.g., requesting /api/v1/data but OAuth is at /)
|
||||
* - The OAuth server is on a different domain than your API requests
|
||||
* - You want to ensure consistent OAuth behavior regardless of request URLs
|
||||
*
|
||||
* For MCP transports, set baseUrl to the same URL you pass to the transport constructor.
|
||||
*
|
||||
* Note: This wrapper is designed for general-purpose fetch operations.
|
||||
* MCP transports (SSE and StreamableHTTP) already have built-in OAuth handling
|
||||
* and should not need this wrapper.
|
||||
*
|
||||
* @param provider - OAuth client provider for authentication
|
||||
* @param baseUrl - Base URL for OAuth server discovery (defaults to request URL domain)
|
||||
* @returns A fetch middleware function
|
||||
*/
|
||||
const withOAuth = (provider, baseUrl) => next => {
|
||||
return async (input, init) => {
|
||||
const makeRequest = async () => {
|
||||
const headers = new Headers(init?.headers);
|
||||
// Add authorization header if tokens are available
|
||||
const tokens = await provider.tokens();
|
||||
if (tokens) {
|
||||
headers.set('Authorization', `Bearer ${tokens.access_token}`);
|
||||
}
|
||||
return await next(input, { ...init, headers });
|
||||
};
|
||||
let response = await makeRequest();
|
||||
// Handle 401 responses by attempting re-authentication
|
||||
if (response.status === 401) {
|
||||
try {
|
||||
const { resourceMetadataUrl, scope } = (0, auth_js_1.extractWWWAuthenticateParams)(response);
|
||||
// Use provided baseUrl or extract from request URL
|
||||
const serverUrl = baseUrl || (typeof input === 'string' ? new URL(input).origin : input.origin);
|
||||
const result = await (0, auth_js_1.auth)(provider, {
|
||||
serverUrl,
|
||||
resourceMetadataUrl,
|
||||
scope,
|
||||
fetchFn: next
|
||||
});
|
||||
if (result === 'REDIRECT') {
|
||||
throw new auth_js_1.UnauthorizedError('Authentication requires user authorization - redirect initiated');
|
||||
}
|
||||
if (result !== 'AUTHORIZED') {
|
||||
throw new auth_js_1.UnauthorizedError(`Authentication failed with result: ${result}`);
|
||||
}
|
||||
// Retry the request with fresh tokens
|
||||
response = await makeRequest();
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof auth_js_1.UnauthorizedError) {
|
||||
throw error;
|
||||
}
|
||||
throw new auth_js_1.UnauthorizedError(`Failed to re-authenticate: ${error instanceof Error ? error.message : String(error)}`);
|
||||
}
|
||||
}
|
||||
// If we still have a 401 after re-auth attempt, throw an error
|
||||
if (response.status === 401) {
|
||||
const url = typeof input === 'string' ? input : input.toString();
|
||||
throw new auth_js_1.UnauthorizedError(`Authentication failed for ${url}`);
|
||||
}
|
||||
return response;
|
||||
};
|
||||
};
|
||||
exports.withOAuth = withOAuth;
|
||||
/**
|
||||
* Creates a fetch middleware that logs HTTP requests and responses.
|
||||
*
|
||||
* When called without arguments `withLogging()`, it uses the default logger that:
|
||||
* - Logs successful requests (2xx) to `console.log`
|
||||
* - Logs error responses (4xx/5xx) and network errors to `console.error`
|
||||
* - Logs all requests regardless of status (statusLevel: 0)
|
||||
* - Does not include request or response headers in logs
|
||||
* - Measures and displays request duration in milliseconds
|
||||
*
|
||||
* Important: the default logger uses both `console.log` and `console.error` so it should not be used with
|
||||
* `stdio` transports and applications.
|
||||
*
|
||||
* @param options - Logging configuration options
|
||||
* @returns A fetch middleware function
|
||||
*/
|
||||
const withLogging = (options = {}) => {
|
||||
const { logger, includeRequestHeaders = false, includeResponseHeaders = false, statusLevel = 0 } = options;
|
||||
const defaultLogger = input => {
|
||||
const { method, url, status, statusText, duration, requestHeaders, responseHeaders, error } = input;
|
||||
let message = error
|
||||
? `HTTP ${method} ${url} failed: ${error.message} (${duration}ms)`
|
||||
: `HTTP ${method} ${url} ${status} ${statusText} (${duration}ms)`;
|
||||
// Add headers to message if requested
|
||||
if (includeRequestHeaders && requestHeaders) {
|
||||
const reqHeaders = Array.from(requestHeaders.entries())
|
||||
.map(([key, value]) => `${key}: ${value}`)
|
||||
.join(', ');
|
||||
message += `\n Request Headers: {${reqHeaders}}`;
|
||||
}
|
||||
if (includeResponseHeaders && responseHeaders) {
|
||||
const resHeaders = Array.from(responseHeaders.entries())
|
||||
.map(([key, value]) => `${key}: ${value}`)
|
||||
.join(', ');
|
||||
message += `\n Response Headers: {${resHeaders}}`;
|
||||
}
|
||||
if (error || status >= 400) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(message);
|
||||
}
|
||||
else {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(message);
|
||||
}
|
||||
};
|
||||
const logFn = logger || defaultLogger;
|
||||
return next => async (input, init) => {
|
||||
const startTime = performance.now();
|
||||
const method = init?.method || 'GET';
|
||||
const url = typeof input === 'string' ? input : input.toString();
|
||||
const requestHeaders = includeRequestHeaders ? new Headers(init?.headers) : undefined;
|
||||
try {
|
||||
const response = await next(input, init);
|
||||
const duration = performance.now() - startTime;
|
||||
// Only log if status meets the log level threshold
|
||||
if (response.status >= statusLevel) {
|
||||
logFn({
|
||||
method,
|
||||
url,
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
duration,
|
||||
requestHeaders,
|
||||
responseHeaders: includeResponseHeaders ? response.headers : undefined
|
||||
});
|
||||
}
|
||||
return response;
|
||||
}
|
||||
catch (error) {
|
||||
const duration = performance.now() - startTime;
|
||||
// Always log errors regardless of log level
|
||||
logFn({
|
||||
method,
|
||||
url,
|
||||
status: 0,
|
||||
statusText: 'Network Error',
|
||||
duration,
|
||||
requestHeaders,
|
||||
error: error
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
};
|
||||
exports.withLogging = withLogging;
|
||||
/**
|
||||
* Composes multiple fetch middleware functions into a single middleware pipeline.
|
||||
* Middleware are applied in the order they appear, creating a chain of handlers.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Create a middleware pipeline that handles both OAuth and logging
|
||||
* const enhancedFetch = applyMiddlewares(
|
||||
* withOAuth(oauthProvider, 'https://api.example.com'),
|
||||
* withLogging({ statusLevel: 400 })
|
||||
* )(fetch);
|
||||
*
|
||||
* // Use the enhanced fetch - it will handle auth and log errors
|
||||
* const response = await enhancedFetch('https://api.example.com/data');
|
||||
* ```
|
||||
*
|
||||
* @param middleware - Array of fetch middleware to compose into a pipeline
|
||||
* @returns A single composed middleware function
|
||||
*/
|
||||
const applyMiddlewares = (...middleware) => {
|
||||
return next => {
|
||||
return middleware.reduce((handler, mw) => mw(handler), next);
|
||||
};
|
||||
};
|
||||
exports.applyMiddlewares = applyMiddlewares;
|
||||
/**
|
||||
* Helper function to create custom fetch middleware with cleaner syntax.
|
||||
* Provides the next handler and request details as separate parameters for easier access.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* // Create custom authentication middleware
|
||||
* const customAuthMiddleware = createMiddleware(async (next, input, init) => {
|
||||
* const headers = new Headers(init?.headers);
|
||||
* headers.set('X-Custom-Auth', 'my-token');
|
||||
*
|
||||
* const response = await next(input, { ...init, headers });
|
||||
*
|
||||
* if (response.status === 401) {
|
||||
* console.log('Authentication failed');
|
||||
* }
|
||||
*
|
||||
* return response;
|
||||
* });
|
||||
*
|
||||
* // Create conditional middleware
|
||||
* const conditionalMiddleware = createMiddleware(async (next, input, init) => {
|
||||
* const url = typeof input === 'string' ? input : input.toString();
|
||||
*
|
||||
* // Only add headers for API routes
|
||||
* if (url.includes('/api/')) {
|
||||
* const headers = new Headers(init?.headers);
|
||||
* headers.set('X-API-Version', 'v2');
|
||||
* return next(input, { ...init, headers });
|
||||
* }
|
||||
*
|
||||
* // Pass through for non-API routes
|
||||
* return next(input, init);
|
||||
* });
|
||||
*
|
||||
* // Create caching middleware
|
||||
* const cacheMiddleware = createMiddleware(async (next, input, init) => {
|
||||
* const cacheKey = typeof input === 'string' ? input : input.toString();
|
||||
*
|
||||
* // Check cache first
|
||||
* const cached = await getFromCache(cacheKey);
|
||||
* if (cached) {
|
||||
* return new Response(cached, { status: 200 });
|
||||
* }
|
||||
*
|
||||
* // Make request and cache result
|
||||
* const response = await next(input, init);
|
||||
* if (response.ok) {
|
||||
* await saveToCache(cacheKey, await response.clone().text());
|
||||
* }
|
||||
*
|
||||
* return response;
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* @param handler - Function that receives the next handler and request parameters
|
||||
* @returns A fetch middleware function
|
||||
*/
|
||||
const createMiddleware = (handler) => {
|
||||
return next => (input, init) => handler(next, input, init);
|
||||
};
|
||||
exports.createMiddleware = createMiddleware;
|
||||
//# sourceMappingURL=middleware.js.map
|
||||
1
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/middleware.js.map
generated
vendored
Normal file
1
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/middleware.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../src/client/middleware.ts"],"names":[],"mappings":";;;AAAA,uCAAuG;AASvG;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACI,MAAM,SAAS,GAClB,CAAC,QAA6B,EAAE,OAAsB,EAAc,EAAE,CACtE,IAAI,CAAC,EAAE;IACH,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACzB,MAAM,WAAW,GAAG,KAAK,IAAuB,EAAE;YAC9C,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAE3C,mDAAmD;YACnD,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,EAAE,CAAC;YACvC,IAAI,MAAM,EAAE,CAAC;gBACT,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,UAAU,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC;YAClE,CAAC;YAED,OAAO,MAAM,IAAI,CAAC,KAAK,EAAE,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACnD,CAAC,CAAC;QAEF,IAAI,QAAQ,GAAG,MAAM,WAAW,EAAE,CAAC;QAEnC,uDAAuD;QACvD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC1B,IAAI,CAAC;gBACD,MAAM,EAAE,mBAAmB,EAAE,KAAK,EAAE,GAAG,IAAA,sCAA4B,EAAC,QAAQ,CAAC,CAAC;gBAE9E,mDAAmD;gBACnD,MAAM,SAAS,GAAG,OAAO,IAAI,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;gBAEhG,MAAM,MAAM,GAAG,MAAM,IAAA,cAAI,EAAC,QAAQ,EAAE;oBAChC,SAAS;oBACT,mBAAmB;oBACnB,KAAK;oBACL,OAAO,EAAE,IAAI;iBAChB,CAAC,CAAC;gBAEH,IAAI,MAAM,KAAK,UAAU,EAAE,CAAC;oBACxB,MAAM,IAAI,2BAAiB,CAAC,iEAAiE,CAAC,CAAC;gBACnG,CAAC;gBAED,IAAI,MAAM,KAAK,YAAY,EAAE,CAAC;oBAC1B,MAAM,IAAI,2BAAiB,CAAC,sCAAsC,MAAM,EAAE,CAAC,CAAC;gBAChF,CAAC;gBAED,sCAAsC;gBACtC,QAAQ,GAAG,MAAM,WAAW,EAAE,CAAC;YACnC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACb,IAAI,KAAK,YAAY,2BAAiB,EAAE,CAAC;oBACrC,MAAM,KAAK,CAAC;gBAChB,CAAC;gBACD,MAAM,IAAI,2BAAiB,CAAC,8BAA8B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACxH,CAAC;QACL,CAAC;QAED,+DAA+D;QAC/D,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC1B,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;YACjE,MAAM,IAAI,2BAAiB,CAAC,6BAA6B,GAAG,EAAE,CAAC,CAAC;QACpE,CAAC;QAED,OAAO,QAAQ,CAAC;IACpB,CAAC,CAAC;AACN,CAAC,CAAC;AA3DO,QAAA,SAAS,aA2DhB;AA6CN;;;;;;;;;;;;;;;GAeG;AACI,MAAM,WAAW,GAAG,CAAC,UAA0B,EAAE,EAAc,EAAE;IACpE,MAAM,EAAE,MAAM,EAAE,qBAAqB,GAAG,KAAK,EAAE,sBAAsB,GAAG,KAAK,EAAE,WAAW,GAAG,CAAC,EAAE,GAAG,OAAO,CAAC;IAE3G,MAAM,aAAa,GAAkB,KAAK,CAAC,EAAE;QACzC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,cAAc,EAAE,eAAe,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;QAEpG,IAAI,OAAO,GAAG,KAAK;YACf,CAAC,CAAC,QAAQ,MAAM,IAAI,GAAG,YAAY,KAAK,CAAC,OAAO,KAAK,QAAQ,KAAK;YAClE,CAAC,CAAC,QAAQ,MAAM,IAAI,GAAG,IAAI,MAAM,IAAI,UAAU,KAAK,QAAQ,KAAK,CAAC;QAEtE,sCAAsC;QACtC,IAAI,qBAAqB,IAAI,cAAc,EAAE,CAAC;YAC1C,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,CAAC;iBAClD,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,KAAK,EAAE,CAAC;iBACzC,IAAI,CAAC,IAAI,CAAC,CAAC;YAChB,OAAO,IAAI,yBAAyB,UAAU,GAAG,CAAC;QACtD,CAAC;QAED,IAAI,sBAAsB,IAAI,eAAe,EAAE,CAAC;YAC5C,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC;iBACnD,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,KAAK,KAAK,EAAE,CAAC;iBACzC,IAAI,CAAC,IAAI,CAAC,CAAC;YAChB,OAAO,IAAI,0BAA0B,UAAU,GAAG,CAAC;QACvD,CAAC;QAED,IAAI,KAAK,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;YACzB,sCAAsC;YACtC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;aAAM,CAAC;YACJ,sCAAsC;YACtC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;IACL,CAAC,CAAC;IAEF,MAAM,KAAK,GAAG,MAAM,IAAI,aAAa,CAAC;IAEtC,OAAO,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACjC,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,IAAI,EAAE,MAAM,IAAI,KAAK,CAAC;QACrC,MAAM,GAAG,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;QACjE,MAAM,cAAc,GAAG,qBAAqB,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAEtF,IAAI,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;YACzC,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YAE/C,mDAAmD;YACnD,IAAI,QAAQ,CAAC,MAAM,IAAI,WAAW,EAAE,CAAC;gBACjC,KAAK,CAAC;oBACF,MAAM;oBACN,GAAG;oBACH,MAAM,EAAE,QAAQ,CAAC,MAAM;oBACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;oBAC/B,QAAQ;oBACR,cAAc;oBACd,eAAe,EAAE,sBAAsB,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;iBACzE,CAAC,CAAC;YACP,CAAC;YAED,OAAO,QAAQ,CAAC;QACpB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YAE/C,4CAA4C;YAC5C,KAAK,CAAC;gBACF,MAAM;gBACN,GAAG;gBACH,MAAM,EAAE,CAAC;gBACT,UAAU,EAAE,eAAe;gBAC3B,QAAQ;gBACR,cAAc;gBACd,KAAK,EAAE,KAAc;aACxB,CAAC,CAAC;YAEH,MAAM,KAAK,CAAC;QAChB,CAAC;IACL,CAAC,CAAC;AACN,CAAC,CAAC;AA7EW,QAAA,WAAW,eA6EtB;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACI,MAAM,gBAAgB,GAAG,CAAC,GAAG,UAAwB,EAAc,EAAE;IACxE,OAAO,IAAI,CAAC,EAAE;QACV,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;IACjE,CAAC,CAAC;AACN,CAAC,CAAC;AAJW,QAAA,gBAAgB,oBAI3B;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyDG;AACI,MAAM,gBAAgB,GAAG,CAAC,OAAwF,EAAc,EAAE;IACrI,OAAO,IAAI,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,KAAqB,EAAE,IAAI,CAAC,CAAC;AAC/E,CAAC,CAAC;AAFW,QAAA,gBAAgB,oBAE3B"}
|
||||
81
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/sse.d.ts
generated
vendored
Normal file
81
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/sse.d.ts
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
import { type ErrorEvent, type EventSourceInit } from 'eventsource';
|
||||
import { Transport, FetchLike } from '../shared/transport.js';
|
||||
import { JSONRPCMessage } from '../types.js';
|
||||
import { OAuthClientProvider } from './auth.js';
|
||||
export declare class SseError extends Error {
|
||||
readonly code: number | undefined;
|
||||
readonly event: ErrorEvent;
|
||||
constructor(code: number | undefined, message: string | undefined, event: ErrorEvent);
|
||||
}
|
||||
/**
|
||||
* Configuration options for the `SSEClientTransport`.
|
||||
*/
|
||||
export type SSEClientTransportOptions = {
|
||||
/**
|
||||
* An OAuth client provider to use for authentication.
|
||||
*
|
||||
* When an `authProvider` is specified and the SSE connection is started:
|
||||
* 1. The connection is attempted with any existing access token from the `authProvider`.
|
||||
* 2. If the access token has expired, the `authProvider` is used to refresh the token.
|
||||
* 3. If token refresh fails or no access token exists, and auth is required, `OAuthClientProvider.redirectToAuthorization` is called, and an `UnauthorizedError` will be thrown from `connect`/`start`.
|
||||
*
|
||||
* After the user has finished authorizing via their user agent, and is redirected back to the MCP client application, call `SSEClientTransport.finishAuth` with the authorization code before retrying the connection.
|
||||
*
|
||||
* If an `authProvider` is not provided, and auth is required, an `UnauthorizedError` will be thrown.
|
||||
*
|
||||
* `UnauthorizedError` might also be thrown when sending any message over the SSE transport, indicating that the session has expired, and needs to be re-authed and reconnected.
|
||||
*/
|
||||
authProvider?: OAuthClientProvider;
|
||||
/**
|
||||
* Customizes the initial SSE request to the server (the request that begins the stream).
|
||||
*
|
||||
* NOTE: Setting this property will prevent an `Authorization` header from
|
||||
* being automatically attached to the SSE request, if an `authProvider` is
|
||||
* also given. This can be worked around by setting the `Authorization` header
|
||||
* manually.
|
||||
*/
|
||||
eventSourceInit?: EventSourceInit;
|
||||
/**
|
||||
* Customizes recurring POST requests to the server.
|
||||
*/
|
||||
requestInit?: RequestInit;
|
||||
/**
|
||||
* Custom fetch implementation used for all network requests.
|
||||
*/
|
||||
fetch?: FetchLike;
|
||||
};
|
||||
/**
|
||||
* Client transport for SSE: this will connect to a server using Server-Sent Events for receiving
|
||||
* messages and make separate POST requests for sending messages.
|
||||
* @deprecated SSEClientTransport is deprecated. Prefer to use StreamableHTTPClientTransport where possible instead. Note that because some servers are still using SSE, clients may need to support both transports during the migration period.
|
||||
*/
|
||||
export declare class SSEClientTransport implements Transport {
|
||||
private _eventSource?;
|
||||
private _endpoint?;
|
||||
private _abortController?;
|
||||
private _url;
|
||||
private _resourceMetadataUrl?;
|
||||
private _scope?;
|
||||
private _eventSourceInit?;
|
||||
private _requestInit?;
|
||||
private _authProvider?;
|
||||
private _fetch?;
|
||||
private _fetchWithInit;
|
||||
private _protocolVersion?;
|
||||
onclose?: () => void;
|
||||
onerror?: (error: Error) => void;
|
||||
onmessage?: (message: JSONRPCMessage) => void;
|
||||
constructor(url: URL, opts?: SSEClientTransportOptions);
|
||||
private _authThenStart;
|
||||
private _commonHeaders;
|
||||
private _startOrAuth;
|
||||
start(): Promise<void>;
|
||||
/**
|
||||
* Call this method after the user has finished authorizing via their user agent and is redirected back to the MCP client application. This will exchange the authorization code for an access token, enabling the next connection attempt to successfully auth.
|
||||
*/
|
||||
finishAuth(authorizationCode: string): Promise<void>;
|
||||
close(): Promise<void>;
|
||||
send(message: JSONRPCMessage): Promise<void>;
|
||||
setProtocolVersion(version: string): void;
|
||||
}
|
||||
//# sourceMappingURL=sse.d.ts.map
|
||||
1
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/sse.d.ts.map
generated
vendored
Normal file
1
projects/stt-mcp/node_modules/@modelcontextprotocol/sdk/dist/cjs/client/sse.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../../src/client/sse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,SAAS,EAAyC,MAAM,wBAAwB,CAAC;AACrG,OAAO,EAAE,cAAc,EAAwB,MAAM,aAAa,CAAC;AACnE,OAAO,EAAkD,mBAAmB,EAAqB,MAAM,WAAW,CAAC;AAEnH,qBAAa,QAAS,SAAQ,KAAK;aAEX,IAAI,EAAE,MAAM,GAAG,SAAS;aAExB,KAAK,EAAE,UAAU;gBAFjB,IAAI,EAAE,MAAM,GAAG,SAAS,EACxC,OAAO,EAAE,MAAM,GAAG,SAAS,EACX,KAAK,EAAE,UAAU;CAIxC;AAED;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACpC;;;;;;;;;;;;;OAaG;IACH,YAAY,CAAC,EAAE,mBAAmB,CAAC;IAEnC;;;;;;;OAOG;IACH,eAAe,CAAC,EAAE,eAAe,CAAC;IAElC;;OAEG;IACH,WAAW,CAAC,EAAE,WAAW,CAAC;IAE1B;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC;CACrB,CAAC;AAEF;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,SAAS;IAChD,OAAO,CAAC,YAAY,CAAC,CAAc;IACnC,OAAO,CAAC,SAAS,CAAC,CAAM;IACxB,OAAO,CAAC,gBAAgB,CAAC,CAAkB;IAC3C,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,oBAAoB,CAAC,CAAM;IACnC,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,gBAAgB,CAAC,CAAkB;IAC3C,OAAO,CAAC,YAAY,CAAC,CAAc;IACnC,OAAO,CAAC,aAAa,CAAC,CAAsB;IAC5C,OAAO,CAAC,MAAM,CAAC,CAAY;IAC3B,OAAO,CAAC,cAAc,CAAY;IAClC,OAAO,CAAC,gBAAgB,CAAC,CAAS;IAElC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;gBAElC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,EAAE,yBAAyB;YAWxC,cAAc;YAyBd,cAAc;IAoB5B,OAAO,CAAC,YAAY;IAyEd,KAAK;IAQX;;OAEG;IACG,UAAU,CAAC,iBAAiB,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBpD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAMtB,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAkDlD,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;CAG5C"}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user