@mostlyrightmd/markets 1.2.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +4 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.global.js +4 -0
- package/dist/index.global.js.map +1 -1
- package/dist/index.mjs +4 -0
- package/dist/index.mjs.map +1 -1
- package/dist/polymarket/index.cjs +4 -4
- package/dist/polymarket/index.cjs.map +1 -1
- package/dist/polymarket/index.d.cts +6 -6
- package/dist/polymarket/index.d.ts +6 -6
- package/dist/polymarket/index.mjs +5 -5
- package/dist/polymarket/index.mjs.map +1 -1
- package/package.json +3 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/polymarket/client.ts","../../src/polymarket/errors.ts","../../src/polymarket/types.ts","../../src/polymarket/description.ts","../../src/polymarket/discover.ts","../../src/polymarket/resolver.ts","../../src/data/generated/polymarket-city-stations.ts","../../src/polymarket/known-wrong-stations.ts","../../src/polymarket/settle.ts"],"sourcesContent":["// TS-W5 Wave 1 — Polymarket Gamma API client.\n//\n// Port of `packages/markets/src/mostlyright/markets/_polymarket_client.py`.\n// HTTP fetch + 0.2s politeness sleep + retry on 429/5xx + offset-paginated\n// discovery up to 10000 events. Gamma's Cloudfront edge 403s on blank\n// User-Agent, so we always set a mostlyright UA.\n\nimport { NotFoundError, fetchWithRetry } from \"@mostlyrightmd/core\";\n\nconst GAMMA_BASE = \"https://gamma-api.polymarket.com\";\nconst PAGE_SIZE = 100;\nconst MAX_EVENTS = 10_000;\nconst DEFAULT_USER_AGENT =\n \"mostlyright-ts/0.1.0 (+https://github.com/mostlyrightmd/mostlyright-sdk)\";\nconst DEFAULT_SLEEP_BETWEEN_MS = 200; // 0.2 s\nconst RETRY_STATUSES: ReadonlySet<number> = new Set([429, 500, 502, 503, 504]);\n\n/** Raw Gamma event payload — narrow shape we depend on. */\nexport interface PolymarketEventRaw {\n id?: string;\n slug?: string;\n title?: string;\n description?: string;\n endDate?: string;\n active?: boolean;\n closed?: boolean;\n archived?: boolean;\n tags?: Array<string | { label?: string; slug?: string }>;\n [key: string]: unknown;\n}\n\nexport interface FetchEventsOptions {\n /** Politeness sleep between requests, in ms. Default 200 (0.2 s). Pass 0 to skip. */\n readonly sleepBetweenMs?: number;\n /** AbortSignal for the whole paginator. */\n readonly signal?: AbortSignal;\n /** Override fetch (for tests). Defaults to global fetch. */\n readonly fetchFn?: typeof fetch;\n}\n\nasync function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (ms <= 0) return;\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n cleanup();\n resolve();\n }, ms);\n const onAbort = () => {\n cleanup();\n reject(signal?.reason ?? new DOMException(\"Aborted\", \"AbortError\"));\n };\n function cleanup() {\n clearTimeout(timer);\n if (signal !== undefined) signal.removeEventListener(\"abort\", onAbort);\n }\n if (signal !== undefined) {\n if (signal.aborted) {\n cleanup();\n reject(signal.reason ?? new DOMException(\"Aborted\", \"AbortError\"));\n return;\n }\n signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n });\n}\n\n/**\n * Fetch every active weather event from Gamma, paginated by `offset` in\n * `PAGE_SIZE` increments until either an empty page is returned or\n * `MAX_EVENTS` is reached. Dedup by slug to defend against the rare case\n * where pagination overlaps under concurrent edits on Gamma's side.\n */\nexport async function fetchEvents(opts: FetchEventsOptions = {}): Promise<PolymarketEventRaw[]> {\n const sleepMs = opts.sleepBetweenMs ?? DEFAULT_SLEEP_BETWEEN_MS;\n const seen = new Set<string>();\n const out: PolymarketEventRaw[] = [];\n for (let offset = 0; offset < MAX_EVENTS; offset += PAGE_SIZE) {\n const url = `${GAMMA_BASE}/events?limit=${PAGE_SIZE}&offset=${offset}&active=true&closed=false`;\n const fetchOpts: Parameters<typeof fetchWithRetry>[1] = {\n headers: { Accept: \"application/json\" },\n userAgent: DEFAULT_USER_AGENT,\n retryStatuses: RETRY_STATUSES,\n };\n if (opts.signal !== undefined) fetchOpts.signal = opts.signal;\n // Codex iter-5 P3: forward `signal` to the custom fetchFn override too\n // so callers can abort in-flight requests, not just inter-page sleeps.\n const customInit: RequestInit = {\n headers: { ...fetchOpts.headers, \"User-Agent\": DEFAULT_USER_AGENT },\n };\n if (opts.signal !== undefined) customInit.signal = opts.signal;\n const resp = await (opts.fetchFn !== undefined\n ? // Custom fetch override (tests). Bypass retry — caller mock-controls statuses.\n opts.fetchFn(url, customInit)\n : fetchWithRetry(url, fetchOpts));\n if (!resp.ok) {\n throw new Error(`Gamma API returned ${resp.status} ${resp.statusText} for offset=${offset}`);\n }\n const raw = (await resp.json()) as unknown;\n // Codex iter-2 P2: distinguish \"Gamma changed shape\" from \"empty page\".\n // Empty list → natural pagination terminator. Non-list → upstream\n // contract changed; surface loudly instead of returning {} as nothing.\n let page: PolymarketEventRaw[];\n if (Array.isArray(raw)) {\n page = raw as PolymarketEventRaw[];\n } else if (\n raw !== null &&\n typeof raw === \"object\" &&\n Array.isArray((raw as { data?: unknown }).data)\n ) {\n // Tolerate the documented `{data: [...]}` envelope shape.\n page = (raw as { data: PolymarketEventRaw[] }).data;\n } else {\n throw new Error(\n `Gamma API returned an unexpected page shape at offset=${offset} (expected array or {data: array}, got ${\n raw === null ? \"null\" : typeof raw\n }). The upstream contract may have changed; check https://docs.polymarket.com/.`,\n );\n }\n if (page.length === 0) break;\n for (const ev of page) {\n const slug = typeof ev.slug === \"string\" ? ev.slug : null;\n if (slug === null || seen.has(slug)) continue;\n seen.add(slug);\n out.push(ev);\n }\n if (page.length < PAGE_SIZE) break;\n if (sleepMs > 0 && offset + PAGE_SIZE < MAX_EVENTS) {\n await sleep(sleepMs, opts.signal);\n }\n }\n return out;\n}\n\n/** Fetch a single event by id. Useful for the settle() flow when only an id is known. */\nexport async function fetchEventById(\n eventId: string,\n opts: FetchEventsOptions = {},\n): Promise<PolymarketEventRaw | null> {\n const url = `${GAMMA_BASE}/events/${encodeURIComponent(eventId)}`;\n const fetchOpts: Parameters<typeof fetchWithRetry>[1] = {\n headers: { Accept: \"application/json\" },\n userAgent: DEFAULT_USER_AGENT,\n retryStatuses: RETRY_STATUSES,\n };\n if (opts.signal !== undefined) fetchOpts.signal = opts.signal;\n // Codex iter-2 P2: fetchWithRetry THROWS NotFoundError on 404 (it does\n // not return a Response); the resp.status check below is unreachable\n // through the default path. Catch + convert to the documented null\n // return so polymarketSettleById can surface PolymarketSettlementError.\n // Codex iter-5 P3: forward `signal` to custom fetchFn override too.\n const customInit: RequestInit = {\n headers: { ...fetchOpts.headers, \"User-Agent\": DEFAULT_USER_AGENT },\n };\n if (opts.signal !== undefined) customInit.signal = opts.signal;\n let resp: Response;\n try {\n resp =\n opts.fetchFn !== undefined\n ? await opts.fetchFn(url, customInit)\n : await fetchWithRetry(url, fetchOpts);\n } catch (err) {\n if (err instanceof NotFoundError) return null;\n throw err;\n }\n if (resp.status === 404) return null;\n if (!resp.ok) {\n throw new Error(`Gamma API returned ${resp.status} ${resp.statusText} for event=${eventId}`);\n }\n return (await resp.json()) as PolymarketEventRaw;\n}\n","// TS-W5 — Polymarket-specific errors. All subclass TradewindsError so they\n// gain toDict() and the standard request-id/error-code payload shape.\n\nimport { TradewindsError } from \"@mostlyrightmd/core\";\n\n/** Event payload is malformed (bad event id, oversized description, bad URL). */\nexport class PolymarketEventError extends TradewindsError {\n constructor(message: string) {\n super(message);\n this.name = \"PolymarketEventError\";\n }\n static readonly defaultErrorCode = \"POLYMARKET_EVENT_INVALID\";\n}\n\n/** Settlement engine couldn't resolve an event to a value. */\nexport class PolymarketSettlementError extends TradewindsError {\n constructor(message: string) {\n super(message);\n this.name = \"PolymarketSettlementError\";\n }\n static readonly defaultErrorCode = \"POLYMARKET_SETTLEMENT_FAILED\";\n}\n\n/**\n * Settlement attempted before the resolution source's publication delay\n * has elapsed. Carries `waitHours` so the caller can schedule a retry.\n *\n * Codex iter-1 P2: overrides `payload()` so `toDict()` (and any MCP\n * serializer downstream) includes the structured retry metadata. The\n * fields are otherwise only readable via the live JS error object.\n */\nexport class TooEarlyToSettleError extends TradewindsError {\n readonly waitHours: number;\n readonly resolutionSourceType: string;\n constructor(message: string, opts: { waitHours: number; resolutionSourceType: string }) {\n super(message);\n this.name = \"TooEarlyToSettleError\";\n this.waitHours = opts.waitHours;\n this.resolutionSourceType = opts.resolutionSourceType;\n }\n static readonly defaultErrorCode = \"POLYMARKET_TOO_EARLY\";\n\n protected override payload(): Record<string, unknown> {\n return {\n ...super.payload(),\n wait_hours: this.waitHours,\n resolution_source_type: this.resolutionSourceType,\n };\n }\n}\n\n/**\n * Description exceeded the 16 KB cap. Direct subclass of TradewindsError\n * (rather than PolymarketEventError) because TS prevents narrowing a\n * `static readonly` literal type in a subclass.\n */\nexport class PayloadTooLargeError extends TradewindsError {\n constructor(message: string) {\n super(message);\n this.name = \"PayloadTooLargeError\";\n }\n static readonly defaultErrorCode = \"POLYMARKET_PAYLOAD_TOO_LARGE\";\n}\n","// TS-W5 — Polymarket types + security constants.\n//\n// Ports the v0.14.1 + Phase 3.3 Python contract verbatim. Anything that\n// crosses the trust boundary (event description, resolution URL) is\n// validated against the constants here before reaching the HTTP fetch\n// or settlement engine.\n\n/**\n * Resolution-source netlocs we trust. Anything else throws\n * PolymarketEventError. Mirrors Python `RESOLUTION_SOURCE_ALLOWLIST`.\n */\nexport const RESOLUTION_SOURCE_ALLOWLIST: ReadonlySet<string> = new Set([\n \"wunderground.com\",\n \"www.wunderground.com\",\n \"weather.gov\",\n \"www.weather.gov\",\n]);\n\n/**\n * Per-netloc → enum value for the `resolutionSourceType` field on settlement\n * records. `hko` / `cwa` are predeclared for v0.2 (HKO/CWA clients).\n */\nexport const NETLOC_TO_RESOLUTION_TYPE: Readonly<Record<string, string>> = Object.freeze({\n \"wunderground.com\": \"wunderground\",\n \"www.wunderground.com\": \"wunderground\",\n \"weather.gov\": \"noaa_wrh\",\n \"www.weather.gov\": \"noaa_wrh\",\n});\n\n/** Enum values for the `resolutionSourceType` column. */\nexport const POLYMARKET_RESOLUTION_SOURCE_TYPES = Object.freeze([\n \"wunderground\",\n \"noaa_wrh\",\n \"hko\",\n \"cwa\",\n \"other\",\n] as const);\nexport type PolymarketResolutionSourceType = (typeof POLYMARKET_RESOLUTION_SOURCE_TYPES)[number];\n\n/**\n * Event id pattern. Python widened this in codex iter-2 P1: real Gamma IDs\n * are numeric strings (`\"12345\"`), but condition-tag UUIDs + slugs also\n * appear in the wild. Wide enough to accept real Gamma payloads but narrow\n * enough to defend against URL-path injection.\n *\n * The plan called this \"UUID4 regex\" but follows Python's actual behavior:\n * the strict UUID4 form rejected every real Gamma event, breaking the\n * discover → settle round-trip.\n */\nexport const EVENT_ID_RE = /^[A-Za-z0-9_-]{1,128}$/;\n\n/**\n * Max bytes of a Polymarket event description we'll parse. Polymarket\n * descriptions are concise; oversized payloads indicate hostile input\n * (ReDoS defense).\n */\nexport const MAX_DESCRIPTION_BYTES = 16 * 1024;\n\n/**\n * Per-resolution-source publication delay. Settlement refuses to settle\n * until `now - settlementDate >= delay` to avoid settling on values the\n * issuer hasn't published yet.\n *\n * Wunderground typically posts daily extremes ~6h after local midnight;\n * NOAA WRH ~4h. \"other\" gets a conservative 24h fallback.\n */\nexport const SETTLE_DELAY_HOURS: Readonly<Record<string, number>> = Object.freeze({\n wunderground: 6,\n noaa_wrh: 4,\n other: 24,\n});\n\n/**\n * Slug date extractor. Polymarket weather slugs embed the resolution date\n * (e.g. `will-nyc-be-above-80f-on-2026-05-23`). Used by `polymarketSettle`\n * to derive the resolution date from the slug instead of `event.endDate`.\n */\nexport const SLUG_DATE_RE = /(\\d{4})-(\\d{2})-(\\d{2})/g;\n\n/** Markets routed to v0.2 sources (CWA/HKO clients). */\nexport const DEFERRED_STATIONS: ReadonlySet<string> = new Set([\"VHHH\", \"RCTP\"]);\n\n/** Discovery row shape — one per active weather event. */\nexport interface PolymarketDiscoveryRow {\n readonly eventId: string | null;\n readonly slug: string | null;\n readonly title: string | null;\n readonly city: string | null;\n readonly icao: string | null;\n readonly measure: \"high\" | \"low\" | \"default\" | null;\n readonly endTime: string | null;\n readonly resolutionSourceType: PolymarketResolutionSourceType | null;\n}\n\n/**\n * Native unit of the market's published settlement value. Codex iter-3 P2:\n * international Polymarket markets publish in whole-°C, US in °F. The\n * settle engine returns the resolved value in BOTH units so the caller's\n * comparison against Polymarket's published value uses the matching unit.\n */\nexport type SettlementUnit = \"fahrenheit\" | \"celsius\";\n\n/** Settlement result shape. */\nexport interface PolymarketSettlementResult {\n readonly eventId: string;\n readonly settlementDate: string; // YYYY-MM-DD\n readonly icao: string;\n readonly measure: \"high\" | \"low\" | \"default\";\n /**\n * Resolved temperature in the unit the caller asked for (the `unit`\n * option; defaults to the station's native unit — F for US-registry\n * stations, C for international). Convenience pointer to `resolvedValueF`\n * or `resolvedValueC`.\n */\n readonly resolvedValue: number;\n readonly resolvedValueC: number;\n readonly resolvedValueF: number;\n /** Which unit `resolvedValue` carries. */\n readonly unit: SettlementUnit;\n readonly resolutionSourceType: PolymarketResolutionSourceType;\n readonly dataQualityAlert: string | null;\n}\n\n/** Settlement options. */\nexport interface PolymarketSettleOptions {\n /** Optional description override (live discovery normally supplies this). */\n readonly description?: string;\n /** Reference \"now\" for the finalization-delay check. Defaults to `new Date()`. */\n readonly now?: Date;\n /**\n * Polymarket's published settlement value, if known. The comparison\n * uses whichever unit `unit` is set to. ±1°F (or ±0.6°C) diff emits an\n * alert; values outside that band don't throw.\n */\n readonly polymarketPublishedValue?: number;\n /**\n * Resolved-value unit. Defaults to the station's native unit:\n * °F for the 20 US Kalshi cities; °C for international stations\n * (matches Polymarket's published-bucket convention per\n * .planning/research/INGEST-PLANNER-RESEARCH.md). Codex iter-3 P2.\n */\n readonly unit?: SettlementUnit;\n}\n","// TS-W5 — Description-validation primitives.\n//\n// Ports Python `_validate_description` + `_extract_resolution_source_type`.\n// All three security defenses (16 KB cap, netloc allowlist, ReDoS-safe\n// URL extraction) live here so they can be unit-tested independently of\n// the higher-level settle() flow.\n\nimport { PayloadTooLargeError, PolymarketEventError } from \"./errors.js\";\nimport {\n MAX_DESCRIPTION_BYTES,\n NETLOC_TO_RESOLUTION_TYPE,\n type PolymarketResolutionSourceType,\n RESOLUTION_SOURCE_ALLOWLIST,\n} from \"./types.js\";\n\n// Bounded URL regex (linear-time match, no nested quantifiers → ReDoS-safe).\n// Stops on whitespace, `<`, `>`, `\"`, `'`, `)`. Capped at 2 KB per URL.\nconst URL_RE = /https?:\\/\\/[^\\s<>\"')]{1,2048}/g;\n\n/**\n * Apply the 16 KB cap + netloc allowlist to a description string.\n *\n * @throws PayloadTooLargeError when the UTF-8 byte length exceeds 16 KB.\n * @throws PolymarketEventError when any URL has a netloc outside the allowlist.\n */\nexport function validateDescription(description: string): void {\n if (typeof description !== \"string\") {\n throw new PolymarketEventError(\n `description must be a string; got ${description === null ? \"null\" : typeof description}`,\n );\n }\n const byteLen = new TextEncoder().encode(description).length;\n if (byteLen > MAX_DESCRIPTION_BYTES) {\n throw new PayloadTooLargeError(\n `description exceeds 16 KB cap (got ${byteLen} bytes; oversized payloads indicate hostile input)`,\n );\n }\n for (const match of description.matchAll(URL_RE)) {\n const url = match[0];\n let netloc: string;\n try {\n netloc = new URL(url).host.toLowerCase();\n } catch {\n throw new PolymarketEventError(`unparseable resolution-source URL ${JSON.stringify(url)}`);\n }\n if (netloc.length > 0 && !RESOLUTION_SOURCE_ALLOWLIST.has(netloc)) {\n throw new PolymarketEventError(\n `resolution-source URL ${JSON.stringify(url)} not in allowlist [${[\n ...RESOLUTION_SOURCE_ALLOWLIST,\n ]\n .sort()\n .join(\", \")}]`,\n );\n }\n }\n}\n\n/**\n * Classify a description's resolution source by the first allowlisted netloc\n * found. Returns `\"other\"` when no allowlisted URL appears (the settlement\n * engine falls back to the 24-hour delay for \"other\").\n */\nexport function extractResolutionSourceType(description: string): PolymarketResolutionSourceType {\n for (const match of description.matchAll(URL_RE)) {\n const url = match[0];\n let netloc: string;\n try {\n netloc = new URL(url).host.toLowerCase();\n } catch {\n continue;\n }\n const mapped = NETLOC_TO_RESOLUTION_TYPE[netloc];\n if (mapped !== undefined) {\n return mapped as PolymarketResolutionSourceType;\n }\n }\n return \"other\";\n}\n","// TS-W5 Wave 3 — polymarketDiscover().\n//\n// Calls Gamma `/events`, enriches each event with city + ICAO + market\n// measure + resolution-source classification. Drops events that don't\n// resolve to a known city (logged for the caller). Surfaces deferred\n// markets (Taipei, HK-low) with `icao: null` so callers see they exist.\n\nimport { DeferredMarketError } from \"@mostlyrightmd/core\";\nimport { type FetchEventsOptions, type PolymarketEventRaw, fetchEvents } from \"./client.js\";\nimport { extractResolutionSourceType, validateDescription } from \"./description.js\";\nimport { PayloadTooLargeError, PolymarketEventError } from \"./errors.js\";\nimport { deriveCity, detectMarketMeasure, resolveStationForEvent } from \"./resolver.js\";\nimport type { PolymarketDiscoveryRow, PolymarketResolutionSourceType } from \"./types.js\";\n\nexport interface PolymarketDiscoverOptions extends FetchEventsOptions {\n /**\n * Sink for dropped events. Tests pass a recorder; production can pass\n * console.info or omit. Receives `{slug, reason}` per skipped event.\n */\n onSkip?: (info: { slug: string | null; reason: string }) => void;\n}\n\n/**\n * Discover active Polymarket weather events.\n *\n * Returns one row per resolvable event. Events the resolver can't match\n * are dropped silently (with optional `onSkip` callback). Events that\n * route to a deferred station (Taipei, HK-low) appear in the result with\n * `icao: null` and `measure: null` so callers can SEE them.\n */\nexport async function polymarketDiscover(\n opts: PolymarketDiscoverOptions = {},\n): Promise<PolymarketDiscoveryRow[]> {\n const raw = await fetchEvents(opts);\n const out: PolymarketDiscoveryRow[] = [];\n for (const ev of raw) {\n const slug = typeof ev.slug === \"string\" ? ev.slug : null;\n const title = typeof ev.title === \"string\" ? ev.title : null;\n const endTime = typeof ev.endDate === \"string\" ? ev.endDate : null;\n const eventId = typeof ev.id === \"string\" ? ev.id : null;\n\n const marketMeasure = detectMarketMeasure(ev);\n\n let icao: string | null = null;\n let cityKey: string | null = null;\n let measureOut: \"high\" | \"low\" | \"default\" | null = null;\n\n try {\n const resolved = resolveStationForEvent(ev, marketMeasure);\n if (resolved === null) {\n opts.onSkip?.({ slug, reason: \"no city match in catalog\" });\n continue;\n }\n icao = resolved.icao;\n // Phase 8 ts-architect iter-2 HIGH: normalize empty string → null at\n // the row boundary to mirror Python's\n // `(ev_enriched.get(\"city\") or \"\").lower() or None` semantics in\n // `polymarket_discover`. Tier 1.5 returns `\"\"` when no explicit nor\n // slug-derived city accompanies a URL-only resolution; emitting\n // `city: \"\"` on the row would drift from Python's `city: None`.\n cityKey = resolved.city === \"\" ? null : resolved.city;\n measureOut = marketMeasure;\n } catch (err) {\n if (err instanceof DeferredMarketError) {\n // Codex iter-4 P2: surface the matched city even when the market is\n // deferred. The catch path used to null out `city` along with `icao`\n // and `measure`, making deferred markets indistinguishable from\n // unresolved-city rows for downstream consumers. Recover the city\n // via deriveCity (cheap; the resolver had already done the same).\n cityKey = deriveCity(ev);\n icao = null;\n measureOut = null;\n } else {\n throw err;\n }\n }\n\n const description = typeof ev.description === \"string\" ? ev.description : \"\";\n // Codex iter-4 P2: an empty/missing description means \"no allowlisted\n // URL found\" — that's the `other` classification (24h fallback delay),\n // NOT `null` (unknown). Mirrors extractResolutionSourceType's contract.\n let resolutionSourceType: PolymarketResolutionSourceType | null = \"other\";\n if (description.length > 0) {\n try {\n validateDescription(description);\n resolutionSourceType = extractResolutionSourceType(description);\n } catch (err) {\n // Bad description on a single event shouldn't poison the whole\n // discovery batch. Codex iter-1 P2: catch both validation paths\n // (PolymarketEventError AND PayloadTooLargeError, which is a\n // sibling TradewindsError after the static-field flatten).\n if (err instanceof PolymarketEventError || err instanceof PayloadTooLargeError) {\n opts.onSkip?.({ slug, reason: `description rejected: ${err.message}` });\n resolutionSourceType = null;\n } else {\n throw err;\n }\n }\n }\n\n out.push(\n Object.freeze({\n eventId,\n slug,\n title,\n city: cityKey,\n icao,\n measure: measureOut,\n endTime,\n resolutionSourceType,\n }),\n );\n }\n return out;\n}\n\n/** Re-export for callers who want the raw shape. */\nexport type { PolymarketEventRaw } from \"./client.js\";\n","// TS-W5 Wave 2 — Tier 0/1/2/3 resolver chain + city catalog.\n//\n// Mirrors Python `_per_event_station.resolve_station_for_event` + the\n// `_derive_city` helper. The resolver chain:\n//\n// - Tier 0 (deferred check): if the resolved ICAO is in DEFERRED_STATIONS\n// (Taipei RCTP, Hong Kong VHHH) AND the market is low-extreme, raise\n// DeferredMarketError. The Python contract defers only HK-LOW + Taipei\n// because v0.2 will land CWA + HKO clients.\n// - Tier 1: explicit `event.city` field if a known city.\n// - Tier 2: derive city from slug + title + tags (lowercase substring\n// match against the catalog, longest-key-first so multi-token cities\n// like \"london_gatwick\" resolve before \"london\").\n// - Tier 3: bail with KeyError — discover() drops the row, settle()\n// surfaces PolymarketSettlementError.\n\nimport { DeferredMarketError } from \"@mostlyrightmd/core\";\n\nimport { POLYMARKET_CITY_STATIONS } from \"../data/generated/polymarket-city-stations.js\";\nimport type { PolymarketEventRaw } from \"./client.js\";\nimport { PolymarketSettlementError } from \"./errors.js\";\nimport { DEFERRED_STATIONS } from \"./types.js\";\n\n/**\n * Detect whether the market resolves on the daily HIGH or LOW from\n * keywords in the event title/slug/name. Distinct from the station-level\n * measure: many cities have one airport for both, but the market still\n * resolves on tmax XOR tmin.\n */\nexport function detectMarketMeasure(event: PolymarketEventRaw): \"high\" | \"low\" | \"default\" {\n const text = [event.title, event.slug, (event as { name?: string }).name]\n .filter((v): v is string => typeof v === \"string\")\n .join(\" \")\n .toLowerCase();\n const hasHigh = /\\b(highest|high|hottest|warmest|max(?:imum)?)\\b/.test(text);\n const hasLow = /\\b(lowest|low|coldest|coolest|min(?:imum)?)\\b/.test(text);\n if (hasLow && !hasHigh) return \"low\";\n if (hasHigh && !hasLow) return \"high\";\n return \"default\";\n}\n\nconst CITY_KEYS_SORTED: ReadonlyArray<string> = Object.freeze(\n Object.keys(POLYMARKET_CITY_STATIONS).sort((a, b) => b.length - a.length),\n);\n\n/**\n * Derive a city key from slug + title + tags. Lowercase substring match\n * against the catalog; longest-first so multi-token cities outrank prefixes.\n * Returns null when no match — caller decides whether to drop or surface.\n */\nexport function deriveCity(event: PolymarketEventRaw): string | null {\n const parts: string[] = [];\n const slug = typeof event.slug === \"string\" ? event.slug.toLowerCase() : \"\";\n const title = typeof event.title === \"string\" ? event.title.toLowerCase() : \"\";\n parts.push(slug, title);\n const tags = event.tags;\n if (Array.isArray(tags)) {\n for (const tag of tags) {\n if (typeof tag === \"string\") parts.push(tag.toLowerCase());\n else if (tag !== null && typeof tag === \"object\") {\n const label = tag.label ?? tag.slug;\n if (typeof label === \"string\") parts.push(label.toLowerCase());\n }\n }\n }\n // Codex iter-5 P2: require word-boundary matches so cities don't false-\n // positive inside ordinary words (e.g. \"comparison\" → \"paris\"). Build a\n // regex per needle with non-word-character boundaries on both sides.\n // Word characters are ASCII letters/digits + underscore; we treat \"-\",\n // \" \", \"/\", \"(\", \")\" etc. as boundaries (covers the slug/title/tag forms\n // we ingest).\n const haystack = ` ${parts.join(\" \")} `;\n for (const key of CITY_KEYS_SORTED) {\n const needles = [key, key.replace(/_/g, \"-\"), key.replace(/_/g, \" \")];\n for (const n of needles) {\n if (n.length === 0) continue;\n // Escape any regex metacharacters in `n` (city keys are alphanum +\n // underscore + hyphen + space; the latter two need no escaping but\n // be defensive).\n const escaped = n.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const re = new RegExp(`(^|[^A-Za-z0-9])${escaped}(?=[^A-Za-z0-9]|$)`);\n if (re.test(haystack)) return key;\n }\n }\n return null;\n}\n\n// Phase 8 — Tier 1.5 URL extraction (POLY-US-03).\n// Wunderground PWS / airport / history URL pattern; captures K-prefix ICAO\n// from CANONICAL settlement paths only — anchor allowlist: /pws/,\n// /dashboard/pws/, /history/daily/, /history/airport/, /weather-station/,\n// /cat/forecasts/. Real Polymarket settlement URLs carry country / state /\n// city slugs between the anchor and the ICAO (e.g.\n// /history/daily/us/ny/new-york-city/KLGA); the `(?:[a-z0-9-]+/)*` segment\n// captures zero or more such intermediate slugs (codex iter-2 +\n// python-architect iter-2 CRITICAL — prior tighter version that required\n// the ICAO to abut the anchor missed every real Polymarket URL).\n//\n// The trailing negative-lookahead `(?![A-Za-z0-9_-])` rejects any\n// alphanumeric / underscore / hyphen follower so we accept common URL\n// terminators (`/`, `?`, `#`, `)`, `.`, `,`, whitespace, EOF) but reject\n// extensions like `KIDS-summer` where `-` would otherwise pass `\\b`\n// (codex iter-2 CRITICAL — original `(?=[/?#\\s]|$)` lookahead missed\n// Markdown-embedded URLs that end with `)`, `.`, etc.).\n// Iter-3 codex CRITICAL: case-insensitive flag let `[a-z0-9-]+/` consume\n// uppercase segments, so `/history/daily/KORD/date/KLAX` extracted `KLAX`\n// (the LAST K-prefix segment) instead of `KORD` (canonical station slot).\n// Fix: drop `i` flag — case-sensitive matching pins ICAO to the canonical\n// station slot. Real Wunderground URLs use lowercase paths + uppercase\n// ICAOs (RFC 3986 + Wunderground convention).\nconst WUNDERGROUND_ICAO_RE =\n /https?:\\/\\/(?:www\\.)?wunderground\\.com\\/(?:dashboard\\/)?(?:pws|history\\/daily|history\\/airport|weather-station|cat\\/forecasts)\\/(?:[a-z0-9-]+\\/)*(K[A-Z]{3})(?![A-Za-z0-9_-])/g;\n\n/**\n * Extract the canonical Wunderground PWS / airport ICAO from `text`.\n *\n * Tier 1.5 of the resolver chain — runs between explicit `event.city`\n * and slug-derive. When a Polymarket event embeds a Wunderground PWS\n * URL, the URL IS the source of truth; no catalog lookup needed.\n *\n * Multi-URL disambiguation: when multiple canonical Wunderground URLs\n * appear, ALL extracted ICAOs MUST agree. Disagreement returns null so\n * the resolver falls through to Tier 2 city-derive (prevents an\n * issuer-side citation URL from silently swapping the settlement station).\n *\n * Returns uppercase ICAO (4 chars, leading K) when a canonical URL is\n * found AND any additional canonical URLs agree. Null otherwise —\n * including the disagreement case.\n */\nexport function extractIcaoFromResolutionSource(text: string | null | undefined): string | null {\n if (typeof text !== \"string\" || text.length === 0) return null;\n // Reset lastIndex on the global regex so multiple matchAll calls are safe\n // (the regex literal is reused across calls).\n const matches = [...text.matchAll(WUNDERGROUND_ICAO_RE)];\n if (matches.length === 0) return null;\n const unique = new Set<string>();\n for (const m of matches) {\n if (m[1] !== undefined) unique.add(m[1].toUpperCase());\n }\n if (unique.size !== 1) return null; // 0 or disagreement → abstain\n return [...unique][0] ?? null;\n}\n\n/**\n * Resolve an event to `{icao, stationMeasure}` using the city catalog.\n *\n * Returns null when no city matches (caller drops the event).\n * Raises DeferredMarketError when the resolution would route to a v0.2\n * source (Taipei RCTP, Hong Kong VHHH for the low-extreme market).\n */\nexport function resolveStationForEvent(\n event: PolymarketEventRaw,\n marketMeasure: \"high\" | \"low\" | \"default\",\n): { city: string; icao: string; stationMeasure: \"high\" | \"low\" | \"default\" } | null {\n // Tier 1: explicit city field — useful for tests / synthetic events.\n let cityKey: string | null = null;\n const explicit = (event as { city?: unknown }).city;\n if (typeof explicit === \"string\") {\n const low = explicit.toLowerCase();\n if (Object.prototype.hasOwnProperty.call(POLYMARKET_CITY_STATIONS, low)) {\n cityKey = low;\n }\n }\n\n // Tier 1.5: URL extraction from description / resolutionSource.\n // The Wunderground URL is the issuer's canonical proof — beats catalog\n // lookup for ICAO. Defer gate still applies so a URL injection cannot\n // silently route an RCTP / HK-low market.\n //\n // Iter-1 TS-architect CRITICAL: the `city` field is owned by the slug-\n // derive layer (matching Python's `_derive_city`-before-resolve pattern in\n // `polymarket_discover`). Tier 1.5 ONLY sets `icao`; `city` is whatever\n // the caller / slug-derive resolved to BEFORE the URL was considered.\n // Returning `findCityForIcao(extractedIcao)` here would drift the TS row's\n // `city` column away from the Python row for the same event — silent\n // per-row source-identity drift, the parity-rubric CRITICAL.\n const desc = typeof event.description === \"string\" ? event.description : \"\";\n const resSrc =\n typeof (event as { resolutionSource?: unknown }).resolutionSource === \"string\"\n ? (event as { resolutionSource: string }).resolutionSource\n : \"\";\n const urlText = `${desc} ${resSrc}`;\n const extractedIcao = extractIcaoFromResolutionSource(urlText);\n if (extractedIcao !== null) {\n if (extractedIcao === \"RCTP\") {\n throw new DeferredMarketError(\n `Polymarket market for station ${extractedIcao} is deferred until the v0.2 CWA client lands`,\n );\n }\n if (extractedIcao === \"VHHH\" && marketMeasure === \"low\") {\n throw new DeferredMarketError(\n `Polymarket low-extreme market for station ${extractedIcao} is deferred until the v0.2 HKO client lands`,\n );\n }\n if (DEFERRED_STATIONS.has(extractedIcao) && marketMeasure === \"default\") {\n throw new DeferredMarketError(\n `Polymarket market for deferred station ${extractedIcao} (measure=default) requires v0.2 client`,\n );\n }\n // City: explicit Tier 1 wins; otherwise slug-derived; otherwise empty.\n // This mirrors Python `polymarket_discover`'s ordering — `_derive_city`\n // populates `event.city` BEFORE `resolve_station_for_event` runs, so the\n // explicit-or-derived city is always the `city` column emitted on the row.\n // discover.ts normalizes empty string back to null at the row boundary\n // to mirror Python's `(ev.get(\"city\") or \"\").lower() or None` semantics.\n const cityForRow = cityKey ?? deriveCity(event) ?? \"\";\n // stationMeasure mirrors Python's _detect_measure(text) result (passed\n // in by the caller as marketMeasure via detectMarketMeasure). Hardcoding\n // \"default\" here would drift from Python for URL-sourced low/high\n // markets (codex iter-2 HIGH).\n return { city: cityForRow, icao: extractedIcao, stationMeasure: marketMeasure };\n }\n\n // Tier 2: scan slug + title + tags.\n if (cityKey === null) {\n cityKey = deriveCity(event);\n }\n if (cityKey === null) return null;\n\n const entry = POLYMARKET_CITY_STATIONS[cityKey];\n if (entry === undefined) return null;\n\n // Station-level measure: cities that split (paris high vs low) follow\n // the market measure; cities without a split use \"default\".\n let stationMeasure: \"high\" | \"low\" | \"default\" = \"default\";\n if (marketMeasure === \"high\" && typeof entry.high === \"string\") stationMeasure = \"high\";\n else if (marketMeasure === \"low\" && typeof entry.low === \"string\") stationMeasure = \"low\";\n\n const icao = entry[stationMeasure] ?? entry.default;\n if (typeof icao !== \"string\") return null;\n\n // Tier 0 deferred-station guard. Taipei (RCTP) defers all markets;\n // Hong Kong (VHHH) defers only the low market because HKO is the issuer\n // for the daily low. High markets at HK resolve via standard METAR.\n if (icao === \"RCTP\") {\n throw new DeferredMarketError(\n `Polymarket market for station ${icao} is deferred until the v0.2 CWA client lands`,\n );\n }\n if (icao === \"VHHH\" && marketMeasure === \"low\") {\n throw new DeferredMarketError(\n `Polymarket low-extreme market for station ${icao} is deferred until the v0.2 HKO client lands`,\n );\n }\n if (DEFERRED_STATIONS.has(icao) && marketMeasure === \"default\") {\n // Conservative default fallback for deferred stations.\n throw new DeferredMarketError(\n `Polymarket market for deferred station ${icao} (measure=default) requires v0.2 client`,\n );\n }\n\n return { city: cityKey, icao, stationMeasure };\n}\n\n/**\n * Parse the resolution date from a Polymarket weather slug. The LAST\n * YYYY-MM-DD match wins because slugs may carry both a creation date and\n * a resolution date (`created-2026-01-01-resolves-2026-05-23`) — the\n * resolution date is typically rightmost in Polymarket's convention.\n *\n * Mirrors Python `_settlement_date_from_slug` architect iter-1 HIGH-4.\n */\nexport function settlementDateFromSlug(slug: string): string {\n const matches = slug.matchAll(/(\\d{4})-(\\d{2})-(\\d{2})/g);\n let last: RegExpMatchArray | null = null;\n for (const m of matches) last = m;\n if (last === null) {\n throw new PolymarketSettlementError(\n `no resolution date in slug ${JSON.stringify(slug)} (expected YYYY-MM-DD)`,\n );\n }\n const [_, y, m, d] = last;\n const year = Number(y);\n const month = Number(m);\n const day = Number(d);\n // Validate calendar date roundtrips (e.g. reject 2025-02-30).\n const ts = Date.UTC(year, month - 1, day);\n const back = new Date(ts);\n if (\n back.getUTCFullYear() !== year ||\n back.getUTCMonth() !== month - 1 ||\n back.getUTCDate() !== day\n ) {\n throw new PolymarketSettlementError(\n `slug ${JSON.stringify(slug)} carries malformed date ${y}-${m}-${d}`,\n );\n }\n return `${y}-${m}-${d}`;\n}\n","// AUTO-GENERATED by @mostlyrightmd/codegen from schemas/polymarket-city-stations.json.\n// DO NOT EDIT — regenerate with: pnpm codegen\n// Last manifest SHA recorded in schemas/EXPORT_MANIFEST.json\n\nexport interface PolymarketCityStation {\n default: string;\n high?: string;\n low?: string;\n [measure: string]: string | undefined;\n}\n\nexport const POLYMARKET_CITY_STATIONS: Readonly<Record<string, PolymarketCityStation>> = {\n amsterdam: {\n default: \"EHAM\",\n },\n atlanta: {\n default: \"KATL\",\n },\n auckland: {\n default: \"NZAA\",\n },\n austin: {\n default: \"KAUS\",\n },\n bangkok: {\n default: \"VTBS\",\n },\n barcelona: {\n default: \"LEBL\",\n },\n beijing: {\n default: \"ZBAA\",\n },\n berlin: {\n default: \"EDDB\",\n },\n boston: {\n default: \"KBOS\",\n },\n brisbane: {\n default: \"YBBN\",\n },\n buenos_aires: {\n default: \"SAEZ\",\n },\n chicago: {\n default: \"KORD\",\n high: \"KORD\",\n low: \"KORD\",\n },\n copenhagen: {\n default: \"EKCH\",\n },\n dallas: {\n default: \"KDFW\",\n },\n delhi: {\n default: \"VIDP\",\n },\n denver: {\n default: \"KDEN\",\n },\n detroit: {\n default: \"KDTW\",\n },\n doha: {\n default: \"OTHH\",\n },\n dubai: {\n default: \"OMDB\",\n },\n frankfurt: {\n default: \"EDDF\",\n },\n helsinki: {\n default: \"EFHK\",\n },\n hong_kong: {\n default: \"VHHH\",\n high: \"VHHH\",\n low: \"VHHH\",\n },\n houston: {\n default: \"KIAH\",\n },\n london: {\n default: \"EGLL\",\n },\n london_gatwick: {\n default: \"EGKK\",\n },\n los_angeles: {\n default: \"KLAX\",\n high: \"KLAX\",\n low: \"KLAX\",\n },\n madrid: {\n default: \"LEMD\",\n },\n melbourne: {\n default: \"YMML\",\n },\n miami: {\n default: \"KMIA\",\n },\n milan: {\n default: \"LIMC\",\n },\n minneapolis: {\n default: \"KMSP\",\n },\n moscow: {\n default: \"UUEE\",\n },\n mumbai: {\n default: \"VABB\",\n },\n munich: {\n default: \"EDDM\",\n },\n nyc: {\n default: \"KLGA\",\n high: \"KLGA\",\n low: \"KLGA\",\n },\n paris: {\n default: \"LFPG\",\n high: \"LFPG\",\n low: \"LFPB\",\n },\n paris_orly: {\n default: \"LFPO\",\n },\n philadelphia: {\n default: \"KPHL\",\n },\n phoenix: {\n default: \"KPHX\",\n },\n riyadh: {\n default: \"OERK\",\n },\n rome: {\n default: \"LIRF\",\n },\n san_francisco: {\n default: \"KSFO\",\n },\n sao_paulo: {\n default: \"SBGR\",\n },\n seattle: {\n default: \"KSEA\",\n },\n seoul: {\n default: \"RKSI\",\n },\n shanghai: {\n default: \"ZSPD\",\n },\n singapore: {\n default: \"WSSS\",\n },\n stockholm: {\n default: \"ESSA\",\n },\n sydney: {\n default: \"YSSY\",\n },\n taipei: {\n default: \"RCTP\",\n },\n tokyo: {\n default: \"RJTT\",\n high: \"RJTT\",\n low: \"RJTT\",\n },\n tokyo_narita: {\n default: \"RJAA\",\n },\n vienna: {\n default: \"LOWW\",\n },\n warsaw: {\n default: \"EPWA\",\n },\n washington_dc: {\n default: \"KDCA\",\n },\n wellington: {\n default: \"NZWN\",\n },\n zurich: {\n default: \"LSZH\",\n },\n} as const;\n","// Phase 8 — per-issuer denylist. Hand-paired with Python\n// `mostlyright.markets.polymarket.KNOWN_WRONG_STATIONS` (NOT codegen;\n// see .planning/phases/08-.../PLAN.md §\"TS Parity\" for rationale —\n// the constant is small enough that exporter wiring would cost more\n// than it saves, and the alphabetized JSON exporter side-effect would\n// conflate it with the cities map).\n//\n// Per-city Map (not flat set) because Polymarket's catalog is multi-city\n// and the \"wrong\" station depends on which city the event is for.\n// Symmetric in spirit to Kalshi's KALSHI_KNOWN_WRONG_STATIONS flat set:\n// Polymarket's per-city granularity is required because (e.g.) KLGA is\n// correct for NYC but wrong for Chicago (where Polymarket uses KORD).\n\nexport const POLYMARKET_KNOWN_WRONG_STATIONS: Readonly<Record<string, ReadonlySet<string>>> =\n Object.freeze({\n // NYC: Polymarket uses KLGA. KNYC/KJFK/KEWR are common wrong answers.\n nyc: new Set([\"KNYC\", \"KJFK\", \"KEWR\"]),\n // Chicago: Polymarket uses KORD. KMDW is the common wrong answer.\n chicago: new Set([\"KMDW\"]),\n // Houston: Polymarket uses KIAH. KHOU is the common wrong answer.\n houston: new Set([\"KHOU\"]),\n // Dallas: Polymarket uses KDFW. KDAL is the common wrong answer.\n dallas: new Set([\"KDAL\"]),\n // SF: Polymarket uses KSFO. KOAK is the common wrong answer.\n san_francisco: new Set([\"KOAK\"]),\n // DC: Polymarket uses KDCA. KIAD/KBWI are common wrong answers.\n washington_dc: new Set([\"KIAD\", \"KBWI\"]),\n });\n","// TS-W5 Wave 4 — polymarketSettle().\n//\n// Settlement engine that consumes internationalDailyExtremes() from\n// @mostlyrightmd/core/discovery (TS-W6) as the resolution source, applies\n// the security/validation gates (event-id regex, 16 KB description cap,\n// netloc allowlist), and gates on the per-source publication-delay\n// window via TooEarlyToSettleError.\n//\n// Returns `{ icao, measure, resolvedValue, resolutionSourceType, settlementDate, dataQualityAlert }`.\n//\n// Threshold-bucket parsing (Python computes win/lose buckets from\n// description text) is deferred to v0.2 — for v0.1.0 we return the raw\n// resolved value (the daily extreme) and the caller picks the bucket.\n// This matches the contract the plan documents: \"ports the resolution\n// path, not the bucket-parser\".\n\nimport { STATIONS } from \"@mostlyrightmd/core\";\nimport { type InternationalRow, internationalDailyExtremes } from \"@mostlyrightmd/core/discovery\";\n\nimport { type PolymarketEventRaw, fetchEventById } from \"./client.js\";\nimport { extractResolutionSourceType, validateDescription } from \"./description.js\";\nimport {\n PolymarketEventError,\n PolymarketSettlementError,\n TooEarlyToSettleError,\n} from \"./errors.js\";\nimport { detectMarketMeasure, resolveStationForEvent, settlementDateFromSlug } from \"./resolver.js\";\nimport {\n EVENT_ID_RE,\n type PolymarketResolutionSourceType,\n type PolymarketSettleOptions,\n type PolymarketSettlementResult,\n SETTLE_DELAY_HOURS,\n} from \"./types.js\";\n\n/**\n * Loader contract for the resolution-source observation rows. Defaults to\n * a no-op stub so the security/validation gates can be unit-tested without\n * pulling live cache data; production callers wire the cache reader here.\n *\n * Returning an empty array signals \"no rows available for this date\" and\n * surfaces as PolymarketSettlementError downstream.\n */\nexport type ObservationLoader = (args: {\n icao: string;\n fromDate: string;\n toDate: string;\n}) => Promise<ReadonlyArray<InternationalRow>>;\n\nexport interface PolymarketSettleArgs extends PolymarketSettleOptions {\n /**\n * The raw Gamma event payload. Required because the settle engine reads\n * `slug` (for the resolution date), `description` (for the resolution\n * source), and `title/slug/name` (for the measure). Callers can fetch\n * via `fetchEventById` if they only have an id.\n */\n readonly event: PolymarketEventRaw;\n /**\n * Loader that returns observation rows for `[fromDate, toDate]`. Defaults\n * to an in-memory empty loader so callers MUST wire this for production.\n */\n readonly loader?: ObservationLoader;\n}\n\nfunction tzForStation(icao: string): string | null {\n for (const s of STATIONS) {\n if (s.icao === icao) return s.tz;\n }\n return null;\n}\n\nfunction safeUuidIsh(eventId: string): boolean {\n return typeof eventId === \"string\" && EVENT_ID_RE.test(eventId);\n}\n\n/**\n * Settle a single Polymarket event.\n *\n * Validates the event id, description (16 KB cap, netloc allowlist),\n * resolves the station via the city catalog, parses the resolution date\n * from the slug, enforces the per-source publication-delay window, and\n * pulls the daily extreme via `internationalDailyExtremes`.\n *\n * @throws PolymarketEventError on bad id / bad description / unsupported station.\n * @throws PolymarketSettlementError when no rows resolve for the station/date.\n * @throws TooEarlyToSettleError when the publication delay hasn't elapsed.\n */\nexport async function polymarketSettle(\n args: PolymarketSettleArgs,\n): Promise<PolymarketSettlementResult> {\n const event = args.event;\n const eventId = typeof event.id === \"string\" ? event.id : \"\";\n if (!safeUuidIsh(eventId)) {\n throw new PolymarketEventError(\n `event id ${JSON.stringify(eventId)} does not match ${EVENT_ID_RE.source}`,\n );\n }\n const slug = typeof event.slug === \"string\" ? event.slug : \"\";\n if (slug.length === 0) {\n throw new PolymarketSettlementError(\"event.slug is required for settlement (carries the date)\");\n }\n const description =\n args.description ?? (typeof event.description === \"string\" ? event.description : \"\");\n validateDescription(description);\n const resolutionSourceType: PolymarketResolutionSourceType =\n description.length > 0 ? extractResolutionSourceType(description) : \"other\";\n\n const marketMeasure = detectMarketMeasure(event);\n const resolved = resolveStationForEvent(event, marketMeasure);\n if (resolved === null) {\n throw new PolymarketSettlementError(\n `unable to resolve station for slug=${JSON.stringify(slug)} — no matching city in catalog`,\n );\n }\n\n const settlementDate = settlementDateFromSlug(slug);\n const now = args.now ?? new Date();\n\n // Finalization-delay gate. We compare `now` to the station-local end of\n // day (23:59:59 in the station's tz) so the delay doesn't fire too early\n // for stations east of UTC.\n const tz = tzForStation(resolved.icao) ?? \"UTC\";\n const localEodMs = stationLocalEodUtcMs(settlementDate, tz);\n const delayHours = SETTLE_DELAY_HOURS[resolutionSourceType] ?? SETTLE_DELAY_HOURS.other ?? 24;\n const delayMs = delayHours * 3600 * 1000;\n const earliestSettleMs = localEodMs + delayMs;\n if (now.getTime() < earliestSettleMs) {\n const waitMs = earliestSettleMs - now.getTime();\n throw new TooEarlyToSettleError(\n `settlement for ${resolved.icao} on ${settlementDate} (source=${resolutionSourceType}) requires another ${(\n waitMs / 3600 / 1000\n ).toFixed(2)} h`,\n { waitHours: waitMs / 3600 / 1000, resolutionSourceType },\n );\n }\n\n const loader = args.loader ?? defaultEmptyLoader;\n const rows = await loader({\n icao: resolved.icao,\n fromDate: settlementDate,\n toDate: settlementDate,\n });\n if (rows.length === 0) {\n throw new PolymarketSettlementError(\n `no observation rows for station=${resolved.icao} date=${settlementDate} — warm the cache first`,\n );\n }\n\n const extremes = internationalDailyExtremes(rows, { stationTz: tz });\n const day = extremes.find((r) => r.localDate === settlementDate);\n if (day === undefined) {\n throw new PolymarketSettlementError(\n `no daily extreme for station=${resolved.icao} on local date ${settlementDate}`,\n );\n }\n\n // Pick the value per the market measure. Codex iter-1 P2: ambiguous\n // markets (default measure — title has both/neither high+low keywords)\n // are NOT settled blind; refuse and force the caller to disambiguate.\n // Mirrors Python's stricter behavior on average / non-extreme wordings.\n let resolvedValueC: number | null = null;\n let resolvedValueF: number | null = null;\n if (marketMeasure === \"low\") {\n resolvedValueC = day.tempMinC;\n resolvedValueF = day.tempMinF;\n } else if (marketMeasure === \"high\") {\n resolvedValueC = day.tempMaxC;\n resolvedValueF = day.tempMaxF;\n } else {\n throw new PolymarketSettlementError(\n `event ${JSON.stringify(eventId)} (slug=${JSON.stringify(slug)}) has ambiguous measure (\"default\" — title carries neither high nor low keyword); refusing to settle silently. Disambiguate at the caller.`,\n );\n }\n if (resolvedValueC === null || resolvedValueF === null) {\n throw new PolymarketSettlementError(\n `daily extreme for ${resolved.icao} on ${settlementDate} has null ${marketMeasure} (low coverage)`,\n );\n }\n\n // Codex iter-3 P2: native unit selection. International Polymarket markets\n // publish in whole-°C; US Kalshi markets publish in °F. Default unit follows\n // the station's country (US → F, else C); caller can override with the\n // `unit` option. dataQualityAlert compares in the SAME unit as the\n // resolved/published values.\n const isUsStation = STATIONS.find((s) => s.icao === resolved.icao)?.country === \"US\";\n const unit = args.unit ?? (isUsStation ? \"fahrenheit\" : \"celsius\");\n const resolvedValue = unit === \"celsius\" ? resolvedValueC : resolvedValueF;\n\n let dataQualityAlert: string | null = null;\n if (typeof args.polymarketPublishedValue === \"number\") {\n const diff = Math.abs(resolvedValue - args.polymarketPublishedValue);\n const threshold = unit === \"celsius\" ? 0.6 : 1;\n const unitSym = unit === \"celsius\" ? \"°C\" : \"°F\";\n if (diff > threshold) {\n dataQualityAlert = `mostlyright resolved ${resolvedValue}${unitSym} but Polymarket published ${args.polymarketPublishedValue}${unitSym} (Δ=${diff.toFixed(2)}${unitSym} > ${threshold}${unitSym} threshold)`;\n }\n }\n\n return Object.freeze({\n eventId,\n settlementDate,\n icao: resolved.icao,\n measure: marketMeasure,\n resolvedValue,\n resolvedValueC,\n resolvedValueF,\n unit,\n resolutionSourceType,\n dataQualityAlert,\n });\n}\n\n/**\n * Settle by event id alone. Fetches the event from Gamma first, then\n * delegates to `polymarketSettle`. Useful when a caller only has the id\n * (e.g. from a Kalshi-side cross-reference).\n */\nexport async function polymarketSettleById(\n eventId: string,\n args: Omit<PolymarketSettleArgs, \"event\">,\n): Promise<PolymarketSettlementResult> {\n if (!safeUuidIsh(eventId)) {\n throw new PolymarketEventError(\n `event id ${JSON.stringify(eventId)} does not match ${EVENT_ID_RE.source}`,\n );\n }\n const event = await fetchEventById(eventId);\n if (event === null) {\n throw new PolymarketSettlementError(\n `Gamma returned 404 for event id ${JSON.stringify(eventId)}`,\n );\n }\n return polymarketSettle({ ...args, event });\n}\n\nasync function defaultEmptyLoader(): Promise<ReadonlyArray<InternationalRow>> {\n return [];\n}\n\n/**\n * Compute the UTC ms instant of station-local 23:59:59 for the given date.\n * Used by the publication-delay gate so the delay doesn't fire too early\n * for stations east of UTC (architect iter-1 HIGH-1 in the Python port).\n */\nfunction stationLocalEodUtcMs(localDate: string, tz: string): number {\n // Step 1: pick a UTC instant guaranteed inside the local day (noon UTC\n // gets us inside the local day for every tz on Earth).\n const noon = new Date(`${localDate}T12:00:00Z`);\n // Step 2: extract the local-tz year/month/day for that instant via\n // Intl.DateTimeFormat (matches the discovery/international.ts trick).\n const fmt = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: tz,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n });\n const parts = fmt.formatToParts(noon);\n let y = \"\";\n let m = \"\";\n let d = \"\";\n for (const p of parts) {\n if (p.type === \"year\") y = p.value;\n else if (p.type === \"month\") m = p.value;\n else if (p.type === \"day\") d = p.value;\n }\n // Step 3: find the UTC instant that is the local-midnight of the day\n // AFTER `localDate`. Iterate from the canonical UTC midnight of nextDay\n // outward in 15-minute steps (the finest IANA offset granularity in\n // common use — Nepal Asia/Kathmandu is +5:45). Codex iter-1 P3: a\n // 1-hour step missed Asia/Kolkata (+5:30), Asia/Kathmandu (+5:45) and\n // similar half/quarter-hour zones, returning end-of-day 30 min late.\n const nextDay = new Date(`${localDate}T00:00:00Z`);\n nextDay.setUTCDate(nextDay.getUTCDate() + 1);\n const expectedDate = nextDayDate(localDate);\n const minuteFmt = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: tz,\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: false,\n });\n // Step size: 15 min. Range: ±15 hours of UTC for max IANA offset spread.\n const STEP_MIN = 15;\n const RANGE_MIN = 15 * 60;\n for (let offsetMin = -RANGE_MIN; offsetMin <= RANGE_MIN; offsetMin += STEP_MIN) {\n const candidate = new Date(nextDay.getTime() + offsetMin * 60 * 1000);\n const cParts = fmt.formatToParts(candidate);\n let cy = \"\";\n let cm = \"\";\n let cd = \"\";\n for (const p of cParts) {\n if (p.type === \"year\") cy = p.value;\n else if (p.type === \"month\") cm = p.value;\n else if (p.type === \"day\") cd = p.value;\n }\n if (`${cy}-${cm}-${cd}` !== expectedDate) continue;\n const tParts = minuteFmt.formatToParts(candidate);\n const hourStr = tParts.find((p) => p.type === \"hour\")?.value ?? \"00\";\n const minStr = tParts.find((p) => p.type === \"minute\")?.value ?? \"00\";\n const hour = hourStr === \"24\" ? 0 : Number(hourStr);\n const minute = Number(minStr);\n if (hour === 0 && minute === 0) {\n return candidate.getTime() - 1000;\n }\n }\n // Fallback: assume UTC if we can't resolve.\n return new Date(`${localDate}T23:59:59Z`).getTime();\n}\n\nfunction nextDayDate(localDate: string): string {\n const d = new Date(`${localDate}T00:00:00Z`);\n d.setUTCDate(d.getUTCDate() + 1);\n return d.toISOString().slice(0, 10);\n}\n"],"mappings":";AAOA,SAAS,eAAe,sBAAsB;AAE9C,IAAM,aAAa;AACnB,IAAM,YAAY;AAClB,IAAM,aAAa;AACnB,IAAM,qBACJ;AACF,IAAM,2BAA2B;AACjC,IAAM,iBAAsC,oBAAI,IAAI,CAAC,KAAK,KAAK,KAAK,KAAK,GAAG,CAAC;AAyB7E,eAAe,MAAM,IAAY,QAAqC;AACpE,MAAI,MAAM,EAAG;AACb,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,QAAQ,WAAW,MAAM;AAC7B,cAAQ;AACR,cAAQ;AAAA,IACV,GAAG,EAAE;AACL,UAAM,UAAU,MAAM;AACpB,cAAQ;AACR,aAAO,QAAQ,UAAU,IAAI,aAAa,WAAW,YAAY,CAAC;AAAA,IACpE;AACA,aAAS,UAAU;AACjB,mBAAa,KAAK;AAClB,UAAI,WAAW,OAAW,QAAO,oBAAoB,SAAS,OAAO;AAAA,IACvE;AACA,QAAI,WAAW,QAAW;AACxB,UAAI,OAAO,SAAS;AAClB,gBAAQ;AACR,eAAO,OAAO,UAAU,IAAI,aAAa,WAAW,YAAY,CAAC;AACjE;AAAA,MACF;AACA,aAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;AAAA,IAC1D;AAAA,EACF,CAAC;AACH;AAQA,eAAsB,YAAY,OAA2B,CAAC,GAAkC;AAC9F,QAAM,UAAU,KAAK,kBAAkB;AACvC,QAAM,OAAO,oBAAI,IAAY;AAC7B,QAAM,MAA4B,CAAC;AACnC,WAAS,SAAS,GAAG,SAAS,YAAY,UAAU,WAAW;AAC7D,UAAM,MAAM,GAAG,UAAU,iBAAiB,SAAS,WAAW,MAAM;AACpE,UAAM,YAAkD;AAAA,MACtD,SAAS,EAAE,QAAQ,mBAAmB;AAAA,MACtC,WAAW;AAAA,MACX,eAAe;AAAA,IACjB;AACA,QAAI,KAAK,WAAW,OAAW,WAAU,SAAS,KAAK;AAGvD,UAAM,aAA0B;AAAA,MAC9B,SAAS,EAAE,GAAG,UAAU,SAAS,cAAc,mBAAmB;AAAA,IACpE;AACA,QAAI,KAAK,WAAW,OAAW,YAAW,SAAS,KAAK;AACxD,UAAM,OAAO,OAAO,KAAK,YAAY;AAAA;AAAA,MAEjC,KAAK,QAAQ,KAAK,UAAU;AAAA,QAC5B,eAAe,KAAK,SAAS;AACjC,QAAI,CAAC,KAAK,IAAI;AACZ,YAAM,IAAI,MAAM,sBAAsB,KAAK,MAAM,IAAI,KAAK,UAAU,eAAe,MAAM,EAAE;AAAA,IAC7F;AACA,UAAM,MAAO,MAAM,KAAK,KAAK;AAI7B,QAAI;AACJ,QAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,aAAO;AAAA,IACT,WACE,QAAQ,QACR,OAAO,QAAQ,YACf,MAAM,QAAS,IAA2B,IAAI,GAC9C;AAEA,aAAQ,IAAuC;AAAA,IACjD,OAAO;AACL,YAAM,IAAI;AAAA,QACR,yDAAyD,MAAM,0CAC7D,QAAQ,OAAO,SAAS,OAAO,GACjC;AAAA,MACF;AAAA,IACF;AACA,QAAI,KAAK,WAAW,EAAG;AACvB,eAAW,MAAM,MAAM;AACrB,YAAM,OAAO,OAAO,GAAG,SAAS,WAAW,GAAG,OAAO;AACrD,UAAI,SAAS,QAAQ,KAAK,IAAI,IAAI,EAAG;AACrC,WAAK,IAAI,IAAI;AACb,UAAI,KAAK,EAAE;AAAA,IACb;AACA,QAAI,KAAK,SAAS,UAAW;AAC7B,QAAI,UAAU,KAAK,SAAS,YAAY,YAAY;AAClD,YAAM,MAAM,SAAS,KAAK,MAAM;AAAA,IAClC;AAAA,EACF;AACA,SAAO;AACT;AAGA,eAAsB,eACpB,SACA,OAA2B,CAAC,GACQ;AACpC,QAAM,MAAM,GAAG,UAAU,WAAW,mBAAmB,OAAO,CAAC;AAC/D,QAAM,YAAkD;AAAA,IACtD,SAAS,EAAE,QAAQ,mBAAmB;AAAA,IACtC,WAAW;AAAA,IACX,eAAe;AAAA,EACjB;AACA,MAAI,KAAK,WAAW,OAAW,WAAU,SAAS,KAAK;AAMvD,QAAM,aAA0B;AAAA,IAC9B,SAAS,EAAE,GAAG,UAAU,SAAS,cAAc,mBAAmB;AAAA,EACpE;AACA,MAAI,KAAK,WAAW,OAAW,YAAW,SAAS,KAAK;AACxD,MAAI;AACJ,MAAI;AACF,WACE,KAAK,YAAY,SACb,MAAM,KAAK,QAAQ,KAAK,UAAU,IAClC,MAAM,eAAe,KAAK,SAAS;AAAA,EAC3C,SAAS,KAAK;AACZ,QAAI,eAAe,cAAe,QAAO;AACzC,UAAM;AAAA,EACR;AACA,MAAI,KAAK,WAAW,IAAK,QAAO;AAChC,MAAI,CAAC,KAAK,IAAI;AACZ,UAAM,IAAI,MAAM,sBAAsB,KAAK,MAAM,IAAI,KAAK,UAAU,cAAc,OAAO,EAAE;AAAA,EAC7F;AACA,SAAQ,MAAM,KAAK,KAAK;AAC1B;;;ACtKA,SAAS,uBAAuB;AAGzB,IAAM,uBAAN,cAAmC,gBAAgB;AAAA,EACxD,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AAAA,EACA,OAAgB,mBAAmB;AACrC;AAGO,IAAM,4BAAN,cAAwC,gBAAgB;AAAA,EAC7D,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AAAA,EACA,OAAgB,mBAAmB;AACrC;AAUO,IAAM,wBAAN,cAAoC,gBAAgB;AAAA,EAChD;AAAA,EACA;AAAA,EACT,YAAY,SAAiB,MAA2D;AACtF,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,YAAY,KAAK;AACtB,SAAK,uBAAuB,KAAK;AAAA,EACnC;AAAA,EACA,OAAgB,mBAAmB;AAAA,EAEhB,UAAmC;AACpD,WAAO;AAAA,MACL,GAAG,MAAM,QAAQ;AAAA,MACjB,YAAY,KAAK;AAAA,MACjB,wBAAwB,KAAK;AAAA,IAC/B;AAAA,EACF;AACF;AAOO,IAAM,uBAAN,cAAmC,gBAAgB;AAAA,EACxD,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AAAA,EACA,OAAgB,mBAAmB;AACrC;;;ACnDO,IAAM,8BAAmD,oBAAI,IAAI;AAAA,EACtE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAMM,IAAM,4BAA8D,OAAO,OAAO;AAAA,EACvF,oBAAoB;AAAA,EACpB,wBAAwB;AAAA,EACxB,eAAe;AAAA,EACf,mBAAmB;AACrB,CAAC;AAGM,IAAM,qCAAqC,OAAO,OAAO;AAAA,EAC9D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAU;AAaH,IAAM,cAAc;AAOpB,IAAM,wBAAwB,KAAK;AAUnC,IAAM,qBAAuD,OAAO,OAAO;AAAA,EAChF,cAAc;AAAA,EACd,UAAU;AAAA,EACV,OAAO;AACT,CAAC;AAOM,IAAM,eAAe;AAGrB,IAAM,oBAAyC,oBAAI,IAAI,CAAC,QAAQ,MAAM,CAAC;;;AC/D9E,IAAM,SAAS;AAQR,SAAS,oBAAoB,aAA2B;AAC7D,MAAI,OAAO,gBAAgB,UAAU;AACnC,UAAM,IAAI;AAAA,MACR,qCAAqC,gBAAgB,OAAO,SAAS,OAAO,WAAW;AAAA,IACzF;AAAA,EACF;AACA,QAAM,UAAU,IAAI,YAAY,EAAE,OAAO,WAAW,EAAE;AACtD,MAAI,UAAU,uBAAuB;AACnC,UAAM,IAAI;AAAA,MACR,sCAAsC,OAAO;AAAA,IAC/C;AAAA,EACF;AACA,aAAW,SAAS,YAAY,SAAS,MAAM,GAAG;AAChD,UAAM,MAAM,MAAM,CAAC;AACnB,QAAI;AACJ,QAAI;AACF,eAAS,IAAI,IAAI,GAAG,EAAE,KAAK,YAAY;AAAA,IACzC,QAAQ;AACN,YAAM,IAAI,qBAAqB,qCAAqC,KAAK,UAAU,GAAG,CAAC,EAAE;AAAA,IAC3F;AACA,QAAI,OAAO,SAAS,KAAK,CAAC,4BAA4B,IAAI,MAAM,GAAG;AACjE,YAAM,IAAI;AAAA,QACR,yBAAyB,KAAK,UAAU,GAAG,CAAC,sBAAsB;AAAA,UAChE,GAAG;AAAA,QACL,EACG,KAAK,EACL,KAAK,IAAI,CAAC;AAAA,MACf;AAAA,IACF;AAAA,EACF;AACF;AAOO,SAAS,4BAA4B,aAAqD;AAC/F,aAAW,SAAS,YAAY,SAAS,MAAM,GAAG;AAChD,UAAM,MAAM,MAAM,CAAC;AACnB,QAAI;AACJ,QAAI;AACF,eAAS,IAAI,IAAI,GAAG,EAAE,KAAK,YAAY;AAAA,IACzC,QAAQ;AACN;AAAA,IACF;AACA,UAAM,SAAS,0BAA0B,MAAM;AAC/C,QAAI,WAAW,QAAW;AACxB,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;;;ACtEA,SAAS,uBAAAA,4BAA2B;;;ACSpC,SAAS,2BAA2B;;;ACL7B,IAAM,2BAA4E;AAAA,EACvF,WAAW;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,SAAS;AAAA,IACP,SAAS;AAAA,EACX;AAAA,EACA,UAAU;AAAA,IACR,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA,SAAS;AAAA,IACP,SAAS;AAAA,EACX;AAAA,EACA,WAAW;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,SAAS;AAAA,IACP,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA,UAAU;AAAA,IACR,SAAS;AAAA,EACX;AAAA,EACA,cAAc;AAAA,IACZ,SAAS;AAAA,EACX;AAAA,EACA,SAAS;AAAA,IACP,SAAS;AAAA,IACT,MAAM;AAAA,IACN,KAAK;AAAA,EACP;AAAA,EACA,YAAY;AAAA,IACV,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA,OAAO;AAAA,IACL,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA,SAAS;AAAA,IACP,SAAS;AAAA,EACX;AAAA,EACA,MAAM;AAAA,IACJ,SAAS;AAAA,EACX;AAAA,EACA,OAAO;AAAA,IACL,SAAS;AAAA,EACX;AAAA,EACA,WAAW;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,UAAU;AAAA,IACR,SAAS;AAAA,EACX;AAAA,EACA,WAAW;AAAA,IACT,SAAS;AAAA,IACT,MAAM;AAAA,IACN,KAAK;AAAA,EACP;AAAA,EACA,SAAS;AAAA,IACP,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA,gBAAgB;AAAA,IACd,SAAS;AAAA,EACX;AAAA,EACA,aAAa;AAAA,IACX,SAAS;AAAA,IACT,MAAM;AAAA,IACN,KAAK;AAAA,EACP;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA,WAAW;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,OAAO;AAAA,IACL,SAAS;AAAA,EACX;AAAA,EACA,OAAO;AAAA,IACL,SAAS;AAAA,EACX;AAAA,EACA,aAAa;AAAA,IACX,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA,KAAK;AAAA,IACH,SAAS;AAAA,IACT,MAAM;AAAA,IACN,KAAK;AAAA,EACP;AAAA,EACA,OAAO;AAAA,IACL,SAAS;AAAA,IACT,MAAM;AAAA,IACN,KAAK;AAAA,EACP;AAAA,EACA,YAAY;AAAA,IACV,SAAS;AAAA,EACX;AAAA,EACA,cAAc;AAAA,IACZ,SAAS;AAAA,EACX;AAAA,EACA,SAAS;AAAA,IACP,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA,MAAM;AAAA,IACJ,SAAS;AAAA,EACX;AAAA,EACA,eAAe;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA,WAAW;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,SAAS;AAAA,IACP,SAAS;AAAA,EACX;AAAA,EACA,OAAO;AAAA,IACL,SAAS;AAAA,EACX;AAAA,EACA,UAAU;AAAA,IACR,SAAS;AAAA,EACX;AAAA,EACA,WAAW;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,WAAW;AAAA,IACT,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA,OAAO;AAAA,IACL,SAAS;AAAA,IACT,MAAM;AAAA,IACN,KAAK;AAAA,EACP;AAAA,EACA,cAAc;AAAA,IACZ,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,EACX;AAAA,EACA,eAAe;AAAA,IACb,SAAS;AAAA,EACX;AAAA,EACA,YAAY;AAAA,IACV,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,EACX;AACF;;;ADtKO,SAAS,oBAAoB,OAAuD;AACzF,QAAM,OAAO,CAAC,MAAM,OAAO,MAAM,MAAO,MAA4B,IAAI,EACrE,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ,EAChD,KAAK,GAAG,EACR,YAAY;AACf,QAAM,UAAU,kDAAkD,KAAK,IAAI;AAC3E,QAAM,SAAS,gDAAgD,KAAK,IAAI;AACxE,MAAI,UAAU,CAAC,QAAS,QAAO;AAC/B,MAAI,WAAW,CAAC,OAAQ,QAAO;AAC/B,SAAO;AACT;AAEA,IAAM,mBAA0C,OAAO;AAAA,EACrD,OAAO,KAAK,wBAAwB,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AAC1E;AAOO,SAAS,WAAW,OAA0C;AACnE,QAAM,QAAkB,CAAC;AACzB,QAAM,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,KAAK,YAAY,IAAI;AACzE,QAAM,QAAQ,OAAO,MAAM,UAAU,WAAW,MAAM,MAAM,YAAY,IAAI;AAC5E,QAAM,KAAK,MAAM,KAAK;AACtB,QAAM,OAAO,MAAM;AACnB,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,eAAW,OAAO,MAAM;AACtB,UAAI,OAAO,QAAQ,SAAU,OAAM,KAAK,IAAI,YAAY,CAAC;AAAA,eAChD,QAAQ,QAAQ,OAAO,QAAQ,UAAU;AAChD,cAAM,QAAQ,IAAI,SAAS,IAAI;AAC/B,YAAI,OAAO,UAAU,SAAU,OAAM,KAAK,MAAM,YAAY,CAAC;AAAA,MAC/D;AAAA,IACF;AAAA,EACF;AAOA,QAAM,WAAW,IAAI,MAAM,KAAK,GAAG,CAAC;AACpC,aAAW,OAAO,kBAAkB;AAClC,UAAM,UAAU,CAAC,KAAK,IAAI,QAAQ,MAAM,GAAG,GAAG,IAAI,QAAQ,MAAM,GAAG,CAAC;AACpE,eAAW,KAAK,SAAS;AACvB,UAAI,EAAE,WAAW,EAAG;AAIpB,YAAM,UAAU,EAAE,QAAQ,uBAAuB,MAAM;AACvD,YAAM,KAAK,IAAI,OAAO,mBAAmB,OAAO,oBAAoB;AACpE,UAAI,GAAG,KAAK,QAAQ,EAAG,QAAO;AAAA,IAChC;AAAA,EACF;AACA,SAAO;AACT;AAyBA,IAAM,uBACJ;AAkBK,SAAS,gCAAgC,MAAgD;AAC9F,MAAI,OAAO,SAAS,YAAY,KAAK,WAAW,EAAG,QAAO;AAG1D,QAAM,UAAU,CAAC,GAAG,KAAK,SAAS,oBAAoB,CAAC;AACvD,MAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,QAAM,SAAS,oBAAI,IAAY;AAC/B,aAAW,KAAK,SAAS;AACvB,QAAI,EAAE,CAAC,MAAM,OAAW,QAAO,IAAI,EAAE,CAAC,EAAE,YAAY,CAAC;AAAA,EACvD;AACA,MAAI,OAAO,SAAS,EAAG,QAAO;AAC9B,SAAO,CAAC,GAAG,MAAM,EAAE,CAAC,KAAK;AAC3B;AASO,SAAS,uBACd,OACA,eACmF;AAEnF,MAAI,UAAyB;AAC7B,QAAM,WAAY,MAA6B;AAC/C,MAAI,OAAO,aAAa,UAAU;AAChC,UAAM,MAAM,SAAS,YAAY;AACjC,QAAI,OAAO,UAAU,eAAe,KAAK,0BAA0B,GAAG,GAAG;AACvE,gBAAU;AAAA,IACZ;AAAA,EACF;AAcA,QAAM,OAAO,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc;AACzE,QAAM,SACJ,OAAQ,MAAyC,qBAAqB,WACjE,MAAuC,mBACxC;AACN,QAAM,UAAU,GAAG,IAAI,IAAI,MAAM;AACjC,QAAM,gBAAgB,gCAAgC,OAAO;AAC7D,MAAI,kBAAkB,MAAM;AAC1B,QAAI,kBAAkB,QAAQ;AAC5B,YAAM,IAAI;AAAA,QACR,iCAAiC,aAAa;AAAA,MAChD;AAAA,IACF;AACA,QAAI,kBAAkB,UAAU,kBAAkB,OAAO;AACvD,YAAM,IAAI;AAAA,QACR,6CAA6C,aAAa;AAAA,MAC5D;AAAA,IACF;AACA,QAAI,kBAAkB,IAAI,aAAa,KAAK,kBAAkB,WAAW;AACvE,YAAM,IAAI;AAAA,QACR,0CAA0C,aAAa;AAAA,MACzD;AAAA,IACF;AAOA,UAAM,aAAa,WAAW,WAAW,KAAK,KAAK;AAKnD,WAAO,EAAE,MAAM,YAAY,MAAM,eAAe,gBAAgB,cAAc;AAAA,EAChF;AAGA,MAAI,YAAY,MAAM;AACpB,cAAU,WAAW,KAAK;AAAA,EAC5B;AACA,MAAI,YAAY,KAAM,QAAO;AAE7B,QAAM,QAAQ,yBAAyB,OAAO;AAC9C,MAAI,UAAU,OAAW,QAAO;AAIhC,MAAI,iBAA6C;AACjD,MAAI,kBAAkB,UAAU,OAAO,MAAM,SAAS,SAAU,kBAAiB;AAAA,WACxE,kBAAkB,SAAS,OAAO,MAAM,QAAQ,SAAU,kBAAiB;AAEpF,QAAM,OAAO,MAAM,cAAc,KAAK,MAAM;AAC5C,MAAI,OAAO,SAAS,SAAU,QAAO;AAKrC,MAAI,SAAS,QAAQ;AACnB,UAAM,IAAI;AAAA,MACR,iCAAiC,IAAI;AAAA,IACvC;AAAA,EACF;AACA,MAAI,SAAS,UAAU,kBAAkB,OAAO;AAC9C,UAAM,IAAI;AAAA,MACR,6CAA6C,IAAI;AAAA,IACnD;AAAA,EACF;AACA,MAAI,kBAAkB,IAAI,IAAI,KAAK,kBAAkB,WAAW;AAE9D,UAAM,IAAI;AAAA,MACR,0CAA0C,IAAI;AAAA,IAChD;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,SAAS,MAAM,eAAe;AAC/C;AAUO,SAAS,uBAAuB,MAAsB;AAC3D,QAAM,UAAU,KAAK,SAAS,0BAA0B;AACxD,MAAI,OAAgC;AACpC,aAAWC,MAAK,QAAS,QAAOA;AAChC,MAAI,SAAS,MAAM;AACjB,UAAM,IAAI;AAAA,MACR,8BAA8B,KAAK,UAAU,IAAI,CAAC;AAAA,IACpD;AAAA,EACF;AACA,QAAM,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI;AACrB,QAAM,OAAO,OAAO,CAAC;AACrB,QAAM,QAAQ,OAAO,CAAC;AACtB,QAAM,MAAM,OAAO,CAAC;AAEpB,QAAM,KAAK,KAAK,IAAI,MAAM,QAAQ,GAAG,GAAG;AACxC,QAAM,OAAO,IAAI,KAAK,EAAE;AACxB,MACE,KAAK,eAAe,MAAM,QAC1B,KAAK,YAAY,MAAM,QAAQ,KAC/B,KAAK,WAAW,MAAM,KACtB;AACA,UAAM,IAAI;AAAA,MACR,QAAQ,KAAK,UAAU,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,IAAI,CAAC;AAAA,IACpE;AAAA,EACF;AACA,SAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;AACvB;;;ADlQA,eAAsB,mBACpB,OAAkC,CAAC,GACA;AACnC,QAAM,MAAM,MAAM,YAAY,IAAI;AAClC,QAAM,MAAgC,CAAC;AACvC,aAAW,MAAM,KAAK;AACpB,UAAM,OAAO,OAAO,GAAG,SAAS,WAAW,GAAG,OAAO;AACrD,UAAM,QAAQ,OAAO,GAAG,UAAU,WAAW,GAAG,QAAQ;AACxD,UAAM,UAAU,OAAO,GAAG,YAAY,WAAW,GAAG,UAAU;AAC9D,UAAM,UAAU,OAAO,GAAG,OAAO,WAAW,GAAG,KAAK;AAEpD,UAAM,gBAAgB,oBAAoB,EAAE;AAE5C,QAAI,OAAsB;AAC1B,QAAI,UAAyB;AAC7B,QAAI,aAAgD;AAEpD,QAAI;AACF,YAAM,WAAW,uBAAuB,IAAI,aAAa;AACzD,UAAI,aAAa,MAAM;AACrB,aAAK,SAAS,EAAE,MAAM,QAAQ,2BAA2B,CAAC;AAC1D;AAAA,MACF;AACA,aAAO,SAAS;AAOhB,gBAAU,SAAS,SAAS,KAAK,OAAO,SAAS;AACjD,mBAAa;AAAA,IACf,SAAS,KAAK;AACZ,UAAI,eAAeC,sBAAqB;AAMtC,kBAAU,WAAW,EAAE;AACvB,eAAO;AACP,qBAAa;AAAA,MACf,OAAO;AACL,cAAM;AAAA,MACR;AAAA,IACF;AAEA,UAAM,cAAc,OAAO,GAAG,gBAAgB,WAAW,GAAG,cAAc;AAI1E,QAAI,uBAA8D;AAClE,QAAI,YAAY,SAAS,GAAG;AAC1B,UAAI;AACF,4BAAoB,WAAW;AAC/B,+BAAuB,4BAA4B,WAAW;AAAA,MAChE,SAAS,KAAK;AAKZ,YAAI,eAAe,wBAAwB,eAAe,sBAAsB;AAC9E,eAAK,SAAS,EAAE,MAAM,QAAQ,yBAAyB,IAAI,OAAO,GAAG,CAAC;AACtE,iCAAuB;AAAA,QACzB,OAAO;AACL,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AAEA,QAAI;AAAA,MACF,OAAO,OAAO;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,QACA,MAAM;AAAA,QACN;AAAA,QACA,SAAS;AAAA,QACT;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO;AACT;;;AGrGO,IAAM,kCACX,OAAO,OAAO;AAAA;AAAA,EAEZ,KAAK,oBAAI,IAAI,CAAC,QAAQ,QAAQ,MAAM,CAAC;AAAA;AAAA,EAErC,SAAS,oBAAI,IAAI,CAAC,MAAM,CAAC;AAAA;AAAA,EAEzB,SAAS,oBAAI,IAAI,CAAC,MAAM,CAAC;AAAA;AAAA,EAEzB,QAAQ,oBAAI,IAAI,CAAC,MAAM,CAAC;AAAA;AAAA,EAExB,eAAe,oBAAI,IAAI,CAAC,MAAM,CAAC;AAAA;AAAA,EAE/B,eAAe,oBAAI,IAAI,CAAC,QAAQ,MAAM,CAAC;AACzC,CAAC;;;ACXH,SAAS,gBAAgB;AACzB,SAAgC,kCAAkC;AA+ClE,SAAS,aAAa,MAA6B;AACjD,aAAW,KAAK,UAAU;AACxB,QAAI,EAAE,SAAS,KAAM,QAAO,EAAE;AAAA,EAChC;AACA,SAAO;AACT;AAEA,SAAS,YAAY,SAA0B;AAC7C,SAAO,OAAO,YAAY,YAAY,YAAY,KAAK,OAAO;AAChE;AAcA,eAAsB,iBACpB,MACqC;AACrC,QAAM,QAAQ,KAAK;AACnB,QAAM,UAAU,OAAO,MAAM,OAAO,WAAW,MAAM,KAAK;AAC1D,MAAI,CAAC,YAAY,OAAO,GAAG;AACzB,UAAM,IAAI;AAAA,MACR,YAAY,KAAK,UAAU,OAAO,CAAC,mBAAmB,YAAY,MAAM;AAAA,IAC1E;AAAA,EACF;AACA,QAAM,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO;AAC3D,MAAI,KAAK,WAAW,GAAG;AACrB,UAAM,IAAI,0BAA0B,0DAA0D;AAAA,EAChG;AACA,QAAM,cACJ,KAAK,gBAAgB,OAAO,MAAM,gBAAgB,WAAW,MAAM,cAAc;AACnF,sBAAoB,WAAW;AAC/B,QAAM,uBACJ,YAAY,SAAS,IAAI,4BAA4B,WAAW,IAAI;AAEtE,QAAM,gBAAgB,oBAAoB,KAAK;AAC/C,QAAM,WAAW,uBAAuB,OAAO,aAAa;AAC5D,MAAI,aAAa,MAAM;AACrB,UAAM,IAAI;AAAA,MACR,sCAAsC,KAAK,UAAU,IAAI,CAAC;AAAA,IAC5D;AAAA,EACF;AAEA,QAAM,iBAAiB,uBAAuB,IAAI;AAClD,QAAM,MAAM,KAAK,OAAO,oBAAI,KAAK;AAKjC,QAAM,KAAK,aAAa,SAAS,IAAI,KAAK;AAC1C,QAAM,aAAa,qBAAqB,gBAAgB,EAAE;AAC1D,QAAM,aAAa,mBAAmB,oBAAoB,KAAK,mBAAmB,SAAS;AAC3F,QAAM,UAAU,aAAa,OAAO;AACpC,QAAM,mBAAmB,aAAa;AACtC,MAAI,IAAI,QAAQ,IAAI,kBAAkB;AACpC,UAAM,SAAS,mBAAmB,IAAI,QAAQ;AAC9C,UAAM,IAAI;AAAA,MACR,kBAAkB,SAAS,IAAI,OAAO,cAAc,YAAY,oBAAoB,uBAClF,SAAS,OAAO,KAChB,QAAQ,CAAC,CAAC;AAAA,MACZ,EAAE,WAAW,SAAS,OAAO,KAAM,qBAAqB;AAAA,IAC1D;AAAA,EACF;AAEA,QAAM,SAAS,KAAK,UAAU;AAC9B,QAAM,OAAO,MAAM,OAAO;AAAA,IACxB,MAAM,SAAS;AAAA,IACf,UAAU;AAAA,IACV,QAAQ;AAAA,EACV,CAAC;AACD,MAAI,KAAK,WAAW,GAAG;AACrB,UAAM,IAAI;AAAA,MACR,mCAAmC,SAAS,IAAI,SAAS,cAAc;AAAA,IACzE;AAAA,EACF;AAEA,QAAM,WAAW,2BAA2B,MAAM,EAAE,WAAW,GAAG,CAAC;AACnE,QAAM,MAAM,SAAS,KAAK,CAAC,MAAM,EAAE,cAAc,cAAc;AAC/D,MAAI,QAAQ,QAAW;AACrB,UAAM,IAAI;AAAA,MACR,gCAAgC,SAAS,IAAI,kBAAkB,cAAc;AAAA,IAC/E;AAAA,EACF;AAMA,MAAI,iBAAgC;AACpC,MAAI,iBAAgC;AACpC,MAAI,kBAAkB,OAAO;AAC3B,qBAAiB,IAAI;AACrB,qBAAiB,IAAI;AAAA,EACvB,WAAW,kBAAkB,QAAQ;AACnC,qBAAiB,IAAI;AACrB,qBAAiB,IAAI;AAAA,EACvB,OAAO;AACL,UAAM,IAAI;AAAA,MACR,SAAS,KAAK,UAAU,OAAO,CAAC,UAAU,KAAK,UAAU,IAAI,CAAC;AAAA,IAChE;AAAA,EACF;AACA,MAAI,mBAAmB,QAAQ,mBAAmB,MAAM;AACtD,UAAM,IAAI;AAAA,MACR,qBAAqB,SAAS,IAAI,OAAO,cAAc,aAAa,aAAa;AAAA,IACnF;AAAA,EACF;AAOA,QAAM,cAAc,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,SAAS,IAAI,GAAG,YAAY;AAChF,QAAM,OAAO,KAAK,SAAS,cAAc,eAAe;AACxD,QAAM,gBAAgB,SAAS,YAAY,iBAAiB;AAE5D,MAAI,mBAAkC;AACtC,MAAI,OAAO,KAAK,6BAA6B,UAAU;AACrD,UAAM,OAAO,KAAK,IAAI,gBAAgB,KAAK,wBAAwB;AACnE,UAAM,YAAY,SAAS,YAAY,MAAM;AAC7C,UAAM,UAAU,SAAS,YAAY,UAAO;AAC5C,QAAI,OAAO,WAAW;AACpB,yBAAmB,wBAAwB,aAAa,GAAG,OAAO,6BAA6B,KAAK,wBAAwB,GAAG,OAAO,YAAO,KAAK,QAAQ,CAAC,CAAC,GAAG,OAAO,MAAM,SAAS,GAAG,OAAO;AAAA,IACjM;AAAA,EACF;AAEA,SAAO,OAAO,OAAO;AAAA,IACnB;AAAA,IACA;AAAA,IACA,MAAM,SAAS;AAAA,IACf,SAAS;AAAA,IACT;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AACH;AAOA,eAAsB,qBACpB,SACA,MACqC;AACrC,MAAI,CAAC,YAAY,OAAO,GAAG;AACzB,UAAM,IAAI;AAAA,MACR,YAAY,KAAK,UAAU,OAAO,CAAC,mBAAmB,YAAY,MAAM;AAAA,IAC1E;AAAA,EACF;AACA,QAAM,QAAQ,MAAM,eAAe,OAAO;AAC1C,MAAI,UAAU,MAAM;AAClB,UAAM,IAAI;AAAA,MACR,mCAAmC,KAAK,UAAU,OAAO,CAAC;AAAA,IAC5D;AAAA,EACF;AACA,SAAO,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC;AAC5C;AAEA,eAAe,qBAA+D;AAC5E,SAAO,CAAC;AACV;AAOA,SAAS,qBAAqB,WAAmB,IAAoB;AAGnE,QAAM,OAAO,oBAAI,KAAK,GAAG,SAAS,YAAY;AAG9C,QAAM,MAAM,IAAI,KAAK,eAAe,SAAS;AAAA,IAC3C,UAAU;AAAA,IACV,MAAM;AAAA,IACN,OAAO;AAAA,IACP,KAAK;AAAA,EACP,CAAC;AACD,QAAM,QAAQ,IAAI,cAAc,IAAI;AACpC,MAAI,IAAI;AACR,MAAI,IAAI;AACR,MAAI,IAAI;AACR,aAAW,KAAK,OAAO;AACrB,QAAI,EAAE,SAAS,OAAQ,KAAI,EAAE;AAAA,aACpB,EAAE,SAAS,QAAS,KAAI,EAAE;AAAA,aAC1B,EAAE,SAAS,MAAO,KAAI,EAAE;AAAA,EACnC;AAOA,QAAM,UAAU,oBAAI,KAAK,GAAG,SAAS,YAAY;AACjD,UAAQ,WAAW,QAAQ,WAAW,IAAI,CAAC;AAC3C,QAAM,eAAe,YAAY,SAAS;AAC1C,QAAM,YAAY,IAAI,KAAK,eAAe,SAAS;AAAA,IACjD,UAAU;AAAA,IACV,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV,CAAC;AAED,QAAM,WAAW;AACjB,QAAM,YAAY,KAAK;AACvB,WAAS,YAAY,CAAC,WAAW,aAAa,WAAW,aAAa,UAAU;AAC9E,UAAM,YAAY,IAAI,KAAK,QAAQ,QAAQ,IAAI,YAAY,KAAK,GAAI;AACpE,UAAM,SAAS,IAAI,cAAc,SAAS;AAC1C,QAAI,KAAK;AACT,QAAI,KAAK;AACT,QAAI,KAAK;AACT,eAAW,KAAK,QAAQ;AACtB,UAAI,EAAE,SAAS,OAAQ,MAAK,EAAE;AAAA,eACrB,EAAE,SAAS,QAAS,MAAK,EAAE;AAAA,eAC3B,EAAE,SAAS,MAAO,MAAK,EAAE;AAAA,IACpC;AACA,QAAI,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,aAAc;AAC1C,UAAM,SAAS,UAAU,cAAc,SAAS;AAChD,UAAM,UAAU,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM,GAAG,SAAS;AAChE,UAAM,SAAS,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ,GAAG,SAAS;AACjE,UAAM,OAAO,YAAY,OAAO,IAAI,OAAO,OAAO;AAClD,UAAM,SAAS,OAAO,MAAM;AAC5B,QAAI,SAAS,KAAK,WAAW,GAAG;AAC9B,aAAO,UAAU,QAAQ,IAAI;AAAA,IAC/B;AAAA,EACF;AAEA,UAAO,oBAAI,KAAK,GAAG,SAAS,YAAY,GAAE,QAAQ;AACpD;AAEA,SAAS,YAAY,WAA2B;AAC9C,QAAM,IAAI,oBAAI,KAAK,GAAG,SAAS,YAAY;AAC3C,IAAE,WAAW,EAAE,WAAW,IAAI,CAAC;AAC/B,SAAO,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AACpC;","names":["DeferredMarketError","m","DeferredMarketError"]}
|
|
1
|
+
{"version":3,"sources":["../../src/polymarket/client.ts","../../src/polymarket/errors.ts","../../src/polymarket/types.ts","../../src/polymarket/description.ts","../../src/polymarket/discover.ts","../../src/polymarket/resolver.ts","../../src/data/generated/polymarket-city-stations.ts","../../src/polymarket/known-wrong-stations.ts","../../src/polymarket/settle.ts"],"sourcesContent":["// TS-W5 Wave 1 — Polymarket Gamma API client.\n//\n// Port of `packages/markets/src/mostlyright/markets/_polymarket_client.py`.\n// HTTP fetch + 0.2s politeness sleep + retry on 429/5xx + offset-paginated\n// discovery up to 10000 events. Gamma's Cloudfront edge 403s on blank\n// User-Agent, so we always set a mostlyright UA.\n\nimport { NotFoundError, fetchWithRetry } from \"@mostlyrightmd/core\";\n\nconst GAMMA_BASE = \"https://gamma-api.polymarket.com\";\nconst PAGE_SIZE = 100;\nconst MAX_EVENTS = 10_000;\nconst DEFAULT_USER_AGENT =\n \"mostlyright-ts/0.1.0 (+https://github.com/mostlyrightmd/mostlyright-sdk)\";\nconst DEFAULT_SLEEP_BETWEEN_MS = 200; // 0.2 s\nconst RETRY_STATUSES: ReadonlySet<number> = new Set([429, 500, 502, 503, 504]);\n\n/** Raw Gamma event payload — narrow shape we depend on. */\nexport interface PolymarketEventRaw {\n id?: string;\n slug?: string;\n title?: string;\n description?: string;\n endDate?: string;\n active?: boolean;\n closed?: boolean;\n archived?: boolean;\n tags?: Array<string | { label?: string; slug?: string }>;\n [key: string]: unknown;\n}\n\nexport interface FetchEventsOptions {\n /** Politeness sleep between requests, in ms. Default 200 (0.2 s). Pass 0 to skip. */\n readonly sleepBetweenMs?: number;\n /** AbortSignal for the whole paginator. */\n readonly signal?: AbortSignal;\n /** Override fetch (for tests). Defaults to global fetch. */\n readonly fetchFn?: typeof fetch;\n}\n\nasync function sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (ms <= 0) return;\n return new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n cleanup();\n resolve();\n }, ms);\n const onAbort = () => {\n cleanup();\n reject(signal?.reason ?? new DOMException(\"Aborted\", \"AbortError\"));\n };\n function cleanup() {\n clearTimeout(timer);\n if (signal !== undefined) signal.removeEventListener(\"abort\", onAbort);\n }\n if (signal !== undefined) {\n if (signal.aborted) {\n cleanup();\n reject(signal.reason ?? new DOMException(\"Aborted\", \"AbortError\"));\n return;\n }\n signal.addEventListener(\"abort\", onAbort, { once: true });\n }\n });\n}\n\n/**\n * Fetch every active weather event from Gamma, paginated by `offset` in\n * `PAGE_SIZE` increments until either an empty page is returned or\n * `MAX_EVENTS` is reached. Dedup by slug to defend against the rare case\n * where pagination overlaps under concurrent edits on Gamma's side.\n */\nexport async function fetchEvents(opts: FetchEventsOptions = {}): Promise<PolymarketEventRaw[]> {\n const sleepMs = opts.sleepBetweenMs ?? DEFAULT_SLEEP_BETWEEN_MS;\n const seen = new Set<string>();\n const out: PolymarketEventRaw[] = [];\n for (let offset = 0; offset < MAX_EVENTS; offset += PAGE_SIZE) {\n const url = `${GAMMA_BASE}/events?limit=${PAGE_SIZE}&offset=${offset}&active=true&closed=false`;\n const fetchOpts: Parameters<typeof fetchWithRetry>[1] = {\n headers: { Accept: \"application/json\" },\n userAgent: DEFAULT_USER_AGENT,\n retryStatuses: RETRY_STATUSES,\n };\n if (opts.signal !== undefined) fetchOpts.signal = opts.signal;\n // Codex iter-5 P3: forward `signal` to the custom fetchFn override too\n // so callers can abort in-flight requests, not just inter-page sleeps.\n const customInit: RequestInit = {\n headers: { ...fetchOpts.headers, \"User-Agent\": DEFAULT_USER_AGENT },\n };\n if (opts.signal !== undefined) customInit.signal = opts.signal;\n const resp = await (opts.fetchFn !== undefined\n ? // Custom fetch override (tests). Bypass retry — caller mock-controls statuses.\n opts.fetchFn(url, customInit)\n : fetchWithRetry(url, fetchOpts));\n if (!resp.ok) {\n throw new Error(`Gamma API returned ${resp.status} ${resp.statusText} for offset=${offset}`);\n }\n const raw = (await resp.json()) as unknown;\n // Codex iter-2 P2: distinguish \"Gamma changed shape\" from \"empty page\".\n // Empty list → natural pagination terminator. Non-list → upstream\n // contract changed; surface loudly instead of returning {} as nothing.\n let page: PolymarketEventRaw[];\n if (Array.isArray(raw)) {\n page = raw as PolymarketEventRaw[];\n } else if (\n raw !== null &&\n typeof raw === \"object\" &&\n Array.isArray((raw as { data?: unknown }).data)\n ) {\n // Tolerate the documented `{data: [...]}` envelope shape.\n page = (raw as { data: PolymarketEventRaw[] }).data;\n } else {\n throw new Error(\n `Gamma API returned an unexpected page shape at offset=${offset} (expected array or {data: array}, got ${\n raw === null ? \"null\" : typeof raw\n }). The upstream contract may have changed; check https://docs.polymarket.com/.`,\n );\n }\n if (page.length === 0) break;\n for (const ev of page) {\n const slug = typeof ev.slug === \"string\" ? ev.slug : null;\n if (slug === null || seen.has(slug)) continue;\n seen.add(slug);\n out.push(ev);\n }\n if (page.length < PAGE_SIZE) break;\n if (sleepMs > 0 && offset + PAGE_SIZE < MAX_EVENTS) {\n await sleep(sleepMs, opts.signal);\n }\n }\n return out;\n}\n\n/** Fetch a single event by id. Useful for the settle() flow when only an id is known. */\nexport async function fetchEventById(\n eventId: string,\n opts: FetchEventsOptions = {},\n): Promise<PolymarketEventRaw | null> {\n const url = `${GAMMA_BASE}/events/${encodeURIComponent(eventId)}`;\n const fetchOpts: Parameters<typeof fetchWithRetry>[1] = {\n headers: { Accept: \"application/json\" },\n userAgent: DEFAULT_USER_AGENT,\n retryStatuses: RETRY_STATUSES,\n };\n if (opts.signal !== undefined) fetchOpts.signal = opts.signal;\n // Codex iter-2 P2: fetchWithRetry THROWS NotFoundError on 404 (it does\n // not return a Response); the resp.status check below is unreachable\n // through the default path. Catch + convert to the documented null\n // return so polymarketSettleById can surface PolymarketSettlementError.\n // Codex iter-5 P3: forward `signal` to custom fetchFn override too.\n const customInit: RequestInit = {\n headers: { ...fetchOpts.headers, \"User-Agent\": DEFAULT_USER_AGENT },\n };\n if (opts.signal !== undefined) customInit.signal = opts.signal;\n let resp: Response;\n try {\n resp =\n opts.fetchFn !== undefined\n ? await opts.fetchFn(url, customInit)\n : await fetchWithRetry(url, fetchOpts);\n } catch (err) {\n if (err instanceof NotFoundError) return null;\n throw err;\n }\n if (resp.status === 404) return null;\n if (!resp.ok) {\n throw new Error(`Gamma API returned ${resp.status} ${resp.statusText} for event=${eventId}`);\n }\n return (await resp.json()) as PolymarketEventRaw;\n}\n","// TS-W5 — Polymarket-specific errors. All subclass MostlyRightError so they\n// gain toDict() and the standard request-id/error-code payload shape.\n\nimport { MostlyRightError } from \"@mostlyrightmd/core\";\n\n/** Event payload is malformed (bad event id, oversized description, bad URL). */\nexport class PolymarketEventError extends MostlyRightError {\n constructor(message: string) {\n super(message);\n this.name = \"PolymarketEventError\";\n }\n static readonly defaultErrorCode = \"POLYMARKET_EVENT_INVALID\";\n}\n\n/** Settlement engine couldn't resolve an event to a value. */\nexport class PolymarketSettlementError extends MostlyRightError {\n constructor(message: string) {\n super(message);\n this.name = \"PolymarketSettlementError\";\n }\n static readonly defaultErrorCode = \"POLYMARKET_SETTLEMENT_FAILED\";\n}\n\n/**\n * Settlement attempted before the resolution source's publication delay\n * has elapsed. Carries `waitHours` so the caller can schedule a retry.\n *\n * Codex iter-1 P2: overrides `payload()` so `toDict()` (and any MCP\n * serializer downstream) includes the structured retry metadata. The\n * fields are otherwise only readable via the live JS error object.\n */\nexport class TooEarlyToSettleError extends MostlyRightError {\n readonly waitHours: number;\n readonly resolutionSourceType: string;\n constructor(message: string, opts: { waitHours: number; resolutionSourceType: string }) {\n super(message);\n this.name = \"TooEarlyToSettleError\";\n this.waitHours = opts.waitHours;\n this.resolutionSourceType = opts.resolutionSourceType;\n }\n static readonly defaultErrorCode = \"POLYMARKET_TOO_EARLY\";\n\n protected override payload(): Record<string, unknown> {\n return {\n ...super.payload(),\n wait_hours: this.waitHours,\n resolution_source_type: this.resolutionSourceType,\n };\n }\n}\n\n/**\n * Description exceeded the 16 KB cap. Direct subclass of MostlyRightError\n * (rather than PolymarketEventError) because TS prevents narrowing a\n * `static readonly` literal type in a subclass.\n */\nexport class PayloadTooLargeError extends MostlyRightError {\n constructor(message: string) {\n super(message);\n this.name = \"PayloadTooLargeError\";\n }\n static readonly defaultErrorCode = \"POLYMARKET_PAYLOAD_TOO_LARGE\";\n}\n","// TS-W5 — Polymarket types + security constants.\n//\n// Ports the v0.14.1 + Phase 3.3 Python contract verbatim. Anything that\n// crosses the trust boundary (event description, resolution URL) is\n// validated against the constants here before reaching the HTTP fetch\n// or settlement engine.\n\n/**\n * Resolution-source netlocs we trust. Anything else throws\n * PolymarketEventError. Mirrors Python `RESOLUTION_SOURCE_ALLOWLIST`.\n */\nexport const RESOLUTION_SOURCE_ALLOWLIST: ReadonlySet<string> = new Set([\n \"wunderground.com\",\n \"www.wunderground.com\",\n \"weather.gov\",\n \"www.weather.gov\",\n]);\n\n/**\n * Per-netloc → enum value for the `resolutionSourceType` field on settlement\n * records. `hko` / `cwa` are predeclared for v0.2 (HKO/CWA clients).\n */\nexport const NETLOC_TO_RESOLUTION_TYPE: Readonly<Record<string, string>> = Object.freeze({\n \"wunderground.com\": \"wunderground\",\n \"www.wunderground.com\": \"wunderground\",\n \"weather.gov\": \"noaa_wrh\",\n \"www.weather.gov\": \"noaa_wrh\",\n});\n\n/** Enum values for the `resolutionSourceType` column. */\nexport const POLYMARKET_RESOLUTION_SOURCE_TYPES = Object.freeze([\n \"wunderground\",\n \"noaa_wrh\",\n \"hko\",\n \"cwa\",\n \"other\",\n] as const);\nexport type PolymarketResolutionSourceType = (typeof POLYMARKET_RESOLUTION_SOURCE_TYPES)[number];\n\n/**\n * Event id pattern. Python widened this in codex iter-2 P1: real Gamma IDs\n * are numeric strings (`\"12345\"`), but condition-tag UUIDs + slugs also\n * appear in the wild. Wide enough to accept real Gamma payloads but narrow\n * enough to defend against URL-path injection.\n *\n * The plan called this \"UUID4 regex\" but follows Python's actual behavior:\n * the strict UUID4 form rejected every real Gamma event, breaking the\n * discover → settle round-trip.\n */\nexport const EVENT_ID_RE = /^[A-Za-z0-9_-]{1,128}$/;\n\n/**\n * Max bytes of a Polymarket event description we'll parse. Polymarket\n * descriptions are concise; oversized payloads indicate hostile input\n * (ReDoS defense).\n */\nexport const MAX_DESCRIPTION_BYTES = 16 * 1024;\n\n/**\n * Per-resolution-source publication delay. Settlement refuses to settle\n * until `now - settlementDate >= delay` to avoid settling on values the\n * issuer hasn't published yet.\n *\n * Wunderground typically posts daily extremes ~6h after local midnight;\n * NOAA WRH ~4h. \"other\" gets a conservative 24h fallback.\n */\nexport const SETTLE_DELAY_HOURS: Readonly<Record<string, number>> = Object.freeze({\n wunderground: 6,\n noaa_wrh: 4,\n other: 24,\n});\n\n/**\n * Slug date extractor. Polymarket weather slugs embed the resolution date\n * (e.g. `will-nyc-be-above-80f-on-2026-05-23`). Used by `polymarketSettle`\n * to derive the resolution date from the slug instead of `event.endDate`.\n */\nexport const SLUG_DATE_RE = /(\\d{4})-(\\d{2})-(\\d{2})/g;\n\n/** Markets routed to v0.2 sources (CWA/HKO clients). */\nexport const DEFERRED_STATIONS: ReadonlySet<string> = new Set([\"VHHH\", \"RCTP\"]);\n\n/** Discovery row shape — one per active weather event. */\nexport interface PolymarketDiscoveryRow {\n readonly eventId: string | null;\n readonly slug: string | null;\n readonly title: string | null;\n readonly city: string | null;\n readonly icao: string | null;\n readonly measure: \"high\" | \"low\" | \"default\" | null;\n readonly endTime: string | null;\n readonly resolutionSourceType: PolymarketResolutionSourceType | null;\n}\n\n/**\n * Native unit of the market's published settlement value. Codex iter-3 P2:\n * international Polymarket markets publish in whole-°C, US in °F. The\n * settle engine returns the resolved value in BOTH units so the caller's\n * comparison against Polymarket's published value uses the matching unit.\n */\nexport type SettlementUnit = \"fahrenheit\" | \"celsius\";\n\n/** Settlement result shape. */\nexport interface PolymarketSettlementResult {\n readonly eventId: string;\n readonly settlementDate: string; // YYYY-MM-DD\n readonly icao: string;\n readonly measure: \"high\" | \"low\" | \"default\";\n /**\n * Resolved temperature in the unit the caller asked for (the `unit`\n * option; defaults to the station's native unit — F for US-registry\n * stations, C for international). Convenience pointer to `resolvedValueF`\n * or `resolvedValueC`.\n */\n readonly resolvedValue: number;\n readonly resolvedValueC: number;\n readonly resolvedValueF: number;\n /** Which unit `resolvedValue` carries. */\n readonly unit: SettlementUnit;\n readonly resolutionSourceType: PolymarketResolutionSourceType;\n readonly dataQualityAlert: string | null;\n}\n\n/** Settlement options. */\nexport interface PolymarketSettleOptions {\n /** Optional description override (live discovery normally supplies this). */\n readonly description?: string;\n /** Reference \"now\" for the finalization-delay check. Defaults to `new Date()`. */\n readonly now?: Date;\n /**\n * Polymarket's published settlement value, if known. The comparison\n * uses whichever unit `unit` is set to. ±1°F (or ±0.6°C) diff emits an\n * alert; values outside that band don't throw.\n */\n readonly polymarketPublishedValue?: number;\n /**\n * Resolved-value unit. Defaults to the station's native unit:\n * °F for the 20 US Kalshi cities; °C for international stations\n * (matches Polymarket's published-bucket convention per\n * .planning/research/INGEST-PLANNER-RESEARCH.md). Codex iter-3 P2.\n */\n readonly unit?: SettlementUnit;\n}\n","// TS-W5 — Description-validation primitives.\n//\n// Ports Python `_validate_description` + `_extract_resolution_source_type`.\n// All three security defenses (16 KB cap, netloc allowlist, ReDoS-safe\n// URL extraction) live here so they can be unit-tested independently of\n// the higher-level settle() flow.\n\nimport { PayloadTooLargeError, PolymarketEventError } from \"./errors.js\";\nimport {\n MAX_DESCRIPTION_BYTES,\n NETLOC_TO_RESOLUTION_TYPE,\n type PolymarketResolutionSourceType,\n RESOLUTION_SOURCE_ALLOWLIST,\n} from \"./types.js\";\n\n// Bounded URL regex (linear-time match, no nested quantifiers → ReDoS-safe).\n// Stops on whitespace, `<`, `>`, `\"`, `'`, `)`. Capped at 2 KB per URL.\nconst URL_RE = /https?:\\/\\/[^\\s<>\"')]{1,2048}/g;\n\n/**\n * Apply the 16 KB cap + netloc allowlist to a description string.\n *\n * @throws PayloadTooLargeError when the UTF-8 byte length exceeds 16 KB.\n * @throws PolymarketEventError when any URL has a netloc outside the allowlist.\n */\nexport function validateDescription(description: string): void {\n if (typeof description !== \"string\") {\n throw new PolymarketEventError(\n `description must be a string; got ${description === null ? \"null\" : typeof description}`,\n );\n }\n const byteLen = new TextEncoder().encode(description).length;\n if (byteLen > MAX_DESCRIPTION_BYTES) {\n throw new PayloadTooLargeError(\n `description exceeds 16 KB cap (got ${byteLen} bytes; oversized payloads indicate hostile input)`,\n );\n }\n for (const match of description.matchAll(URL_RE)) {\n const url = match[0];\n let netloc: string;\n try {\n netloc = new URL(url).host.toLowerCase();\n } catch {\n throw new PolymarketEventError(`unparseable resolution-source URL ${JSON.stringify(url)}`);\n }\n if (netloc.length > 0 && !RESOLUTION_SOURCE_ALLOWLIST.has(netloc)) {\n throw new PolymarketEventError(\n `resolution-source URL ${JSON.stringify(url)} not in allowlist [${[\n ...RESOLUTION_SOURCE_ALLOWLIST,\n ]\n .sort()\n .join(\", \")}]`,\n );\n }\n }\n}\n\n/**\n * Classify a description's resolution source by the first allowlisted netloc\n * found. Returns `\"other\"` when no allowlisted URL appears (the settlement\n * engine falls back to the 24-hour delay for \"other\").\n */\nexport function extractResolutionSourceType(description: string): PolymarketResolutionSourceType {\n for (const match of description.matchAll(URL_RE)) {\n const url = match[0];\n let netloc: string;\n try {\n netloc = new URL(url).host.toLowerCase();\n } catch {\n continue;\n }\n const mapped = NETLOC_TO_RESOLUTION_TYPE[netloc];\n if (mapped !== undefined) {\n return mapped as PolymarketResolutionSourceType;\n }\n }\n return \"other\";\n}\n","// TS-W5 Wave 3 — polymarketDiscover().\n//\n// Calls Gamma `/events`, enriches each event with city + ICAO + market\n// measure + resolution-source classification. Drops events that don't\n// resolve to a known city (logged for the caller). Surfaces deferred\n// markets (Taipei, HK-low) with `icao: null` so callers see they exist.\n\nimport { DeferredMarketError } from \"@mostlyrightmd/core\";\nimport { type FetchEventsOptions, type PolymarketEventRaw, fetchEvents } from \"./client.js\";\nimport { extractResolutionSourceType, validateDescription } from \"./description.js\";\nimport { PayloadTooLargeError, PolymarketEventError } from \"./errors.js\";\nimport { deriveCity, detectMarketMeasure, resolveStationForEvent } from \"./resolver.js\";\nimport type { PolymarketDiscoveryRow, PolymarketResolutionSourceType } from \"./types.js\";\n\nexport interface PolymarketDiscoverOptions extends FetchEventsOptions {\n /**\n * Sink for dropped events. Tests pass a recorder; production can pass\n * console.info or omit. Receives `{slug, reason}` per skipped event.\n */\n onSkip?: (info: { slug: string | null; reason: string }) => void;\n}\n\n/**\n * Discover active Polymarket weather events.\n *\n * Returns one row per resolvable event. Events the resolver can't match\n * are dropped silently (with optional `onSkip` callback). Events that\n * route to a deferred station (Taipei, HK-low) appear in the result with\n * `icao: null` and `measure: null` so callers can SEE them.\n */\nexport async function polymarketDiscover(\n opts: PolymarketDiscoverOptions = {},\n): Promise<PolymarketDiscoveryRow[]> {\n const raw = await fetchEvents(opts);\n const out: PolymarketDiscoveryRow[] = [];\n for (const ev of raw) {\n const slug = typeof ev.slug === \"string\" ? ev.slug : null;\n const title = typeof ev.title === \"string\" ? ev.title : null;\n const endTime = typeof ev.endDate === \"string\" ? ev.endDate : null;\n const eventId = typeof ev.id === \"string\" ? ev.id : null;\n\n const marketMeasure = detectMarketMeasure(ev);\n\n let icao: string | null = null;\n let cityKey: string | null = null;\n let measureOut: \"high\" | \"low\" | \"default\" | null = null;\n\n try {\n const resolved = resolveStationForEvent(ev, marketMeasure);\n if (resolved === null) {\n opts.onSkip?.({ slug, reason: \"no city match in catalog\" });\n continue;\n }\n icao = resolved.icao;\n // Phase 8 ts-architect iter-2 HIGH: normalize empty string → null at\n // the row boundary to mirror Python's\n // `(ev_enriched.get(\"city\") or \"\").lower() or None` semantics in\n // `polymarket_discover`. Tier 1.5 returns `\"\"` when no explicit nor\n // slug-derived city accompanies a URL-only resolution; emitting\n // `city: \"\"` on the row would drift from Python's `city: None`.\n cityKey = resolved.city === \"\" ? null : resolved.city;\n measureOut = marketMeasure;\n } catch (err) {\n if (err instanceof DeferredMarketError) {\n // Codex iter-4 P2: surface the matched city even when the market is\n // deferred. The catch path used to null out `city` along with `icao`\n // and `measure`, making deferred markets indistinguishable from\n // unresolved-city rows for downstream consumers. Recover the city\n // via deriveCity (cheap; the resolver had already done the same).\n cityKey = deriveCity(ev);\n icao = null;\n measureOut = null;\n } else {\n throw err;\n }\n }\n\n const description = typeof ev.description === \"string\" ? ev.description : \"\";\n // Codex iter-4 P2: an empty/missing description means \"no allowlisted\n // URL found\" — that's the `other` classification (24h fallback delay),\n // NOT `null` (unknown). Mirrors extractResolutionSourceType's contract.\n let resolutionSourceType: PolymarketResolutionSourceType | null = \"other\";\n if (description.length > 0) {\n try {\n validateDescription(description);\n resolutionSourceType = extractResolutionSourceType(description);\n } catch (err) {\n // Bad description on a single event shouldn't poison the whole\n // discovery batch. Codex iter-1 P2: catch both validation paths\n // (PolymarketEventError AND PayloadTooLargeError, which is a\n // sibling MostlyRightError after the static-field flatten).\n if (err instanceof PolymarketEventError || err instanceof PayloadTooLargeError) {\n opts.onSkip?.({ slug, reason: `description rejected: ${err.message}` });\n resolutionSourceType = null;\n } else {\n throw err;\n }\n }\n }\n\n out.push(\n Object.freeze({\n eventId,\n slug,\n title,\n city: cityKey,\n icao,\n measure: measureOut,\n endTime,\n resolutionSourceType,\n }),\n );\n }\n return out;\n}\n\n/** Re-export for callers who want the raw shape. */\nexport type { PolymarketEventRaw } from \"./client.js\";\n","// TS-W5 Wave 2 — Tier 0/1/2/3 resolver chain + city catalog.\n//\n// Mirrors Python `_per_event_station.resolve_station_for_event` + the\n// `_derive_city` helper. The resolver chain:\n//\n// - Tier 0 (deferred check): if the resolved ICAO is in DEFERRED_STATIONS\n// (Taipei RCTP, Hong Kong VHHH) AND the market is low-extreme, raise\n// DeferredMarketError. The Python contract defers only HK-LOW + Taipei\n// because v0.2 will land CWA + HKO clients.\n// - Tier 1: explicit `event.city` field if a known city.\n// - Tier 2: derive city from slug + title + tags (lowercase substring\n// match against the catalog, longest-key-first so multi-token cities\n// like \"london_gatwick\" resolve before \"london\").\n// - Tier 3: bail with KeyError — discover() drops the row, settle()\n// surfaces PolymarketSettlementError.\n\nimport { DeferredMarketError } from \"@mostlyrightmd/core\";\n\nimport { POLYMARKET_CITY_STATIONS } from \"../data/generated/polymarket-city-stations.js\";\nimport type { PolymarketEventRaw } from \"./client.js\";\nimport { PolymarketSettlementError } from \"./errors.js\";\nimport { DEFERRED_STATIONS } from \"./types.js\";\n\n/**\n * Detect whether the market resolves on the daily HIGH or LOW from\n * keywords in the event title/slug/name. Distinct from the station-level\n * measure: many cities have one airport for both, but the market still\n * resolves on tmax XOR tmin.\n */\nexport function detectMarketMeasure(event: PolymarketEventRaw): \"high\" | \"low\" | \"default\" {\n const text = [event.title, event.slug, (event as { name?: string }).name]\n .filter((v): v is string => typeof v === \"string\")\n .join(\" \")\n .toLowerCase();\n const hasHigh = /\\b(highest|high|hottest|warmest|max(?:imum)?)\\b/.test(text);\n const hasLow = /\\b(lowest|low|coldest|coolest|min(?:imum)?)\\b/.test(text);\n if (hasLow && !hasHigh) return \"low\";\n if (hasHigh && !hasLow) return \"high\";\n return \"default\";\n}\n\nconst CITY_KEYS_SORTED: ReadonlyArray<string> = Object.freeze(\n Object.keys(POLYMARKET_CITY_STATIONS).sort((a, b) => b.length - a.length),\n);\n\n/**\n * Derive a city key from slug + title + tags. Lowercase substring match\n * against the catalog; longest-first so multi-token cities outrank prefixes.\n * Returns null when no match — caller decides whether to drop or surface.\n */\nexport function deriveCity(event: PolymarketEventRaw): string | null {\n const parts: string[] = [];\n const slug = typeof event.slug === \"string\" ? event.slug.toLowerCase() : \"\";\n const title = typeof event.title === \"string\" ? event.title.toLowerCase() : \"\";\n parts.push(slug, title);\n const tags = event.tags;\n if (Array.isArray(tags)) {\n for (const tag of tags) {\n if (typeof tag === \"string\") parts.push(tag.toLowerCase());\n else if (tag !== null && typeof tag === \"object\") {\n const label = tag.label ?? tag.slug;\n if (typeof label === \"string\") parts.push(label.toLowerCase());\n }\n }\n }\n // Codex iter-5 P2: require word-boundary matches so cities don't false-\n // positive inside ordinary words (e.g. \"comparison\" → \"paris\"). Build a\n // regex per needle with non-word-character boundaries on both sides.\n // Word characters are ASCII letters/digits + underscore; we treat \"-\",\n // \" \", \"/\", \"(\", \")\" etc. as boundaries (covers the slug/title/tag forms\n // we ingest).\n const haystack = ` ${parts.join(\" \")} `;\n for (const key of CITY_KEYS_SORTED) {\n const needles = [key, key.replace(/_/g, \"-\"), key.replace(/_/g, \" \")];\n for (const n of needles) {\n if (n.length === 0) continue;\n // Escape any regex metacharacters in `n` (city keys are alphanum +\n // underscore + hyphen + space; the latter two need no escaping but\n // be defensive).\n const escaped = n.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n const re = new RegExp(`(^|[^A-Za-z0-9])${escaped}(?=[^A-Za-z0-9]|$)`);\n if (re.test(haystack)) return key;\n }\n }\n return null;\n}\n\n// Phase 8 — Tier 1.5 URL extraction (POLY-US-03).\n// Wunderground PWS / airport / history URL pattern; captures K-prefix ICAO\n// from CANONICAL settlement paths only — anchor allowlist: /pws/,\n// /dashboard/pws/, /history/daily/, /history/airport/, /weather-station/,\n// /cat/forecasts/. Real Polymarket settlement URLs carry country / state /\n// city slugs between the anchor and the ICAO (e.g.\n// /history/daily/us/ny/new-york-city/KLGA); the `(?:[a-z0-9-]+/)*` segment\n// captures zero or more such intermediate slugs (codex iter-2 +\n// python-architect iter-2 CRITICAL — prior tighter version that required\n// the ICAO to abut the anchor missed every real Polymarket URL).\n//\n// The trailing negative-lookahead `(?![A-Za-z0-9_-])` rejects any\n// alphanumeric / underscore / hyphen follower so we accept common URL\n// terminators (`/`, `?`, `#`, `)`, `.`, `,`, whitespace, EOF) but reject\n// extensions like `KIDS-summer` where `-` would otherwise pass `\\b`\n// (codex iter-2 CRITICAL — original `(?=[/?#\\s]|$)` lookahead missed\n// Markdown-embedded URLs that end with `)`, `.`, etc.).\n// Iter-3 codex CRITICAL: case-insensitive flag let `[a-z0-9-]+/` consume\n// uppercase segments, so `/history/daily/KORD/date/KLAX` extracted `KLAX`\n// (the LAST K-prefix segment) instead of `KORD` (canonical station slot).\n// Fix: drop `i` flag — case-sensitive matching pins ICAO to the canonical\n// station slot. Real Wunderground URLs use lowercase paths + uppercase\n// ICAOs (RFC 3986 + Wunderground convention).\nconst WUNDERGROUND_ICAO_RE =\n /https?:\\/\\/(?:www\\.)?wunderground\\.com\\/(?:dashboard\\/)?(?:pws|history\\/daily|history\\/airport|weather-station|cat\\/forecasts)\\/(?:[a-z0-9-]+\\/)*(K[A-Z]{3})(?![A-Za-z0-9_-])/g;\n\n/**\n * Extract the canonical Wunderground PWS / airport ICAO from `text`.\n *\n * Tier 1.5 of the resolver chain — runs between explicit `event.city`\n * and slug-derive. When a Polymarket event embeds a Wunderground PWS\n * URL, the URL IS the source of truth; no catalog lookup needed.\n *\n * Multi-URL disambiguation: when multiple canonical Wunderground URLs\n * appear, ALL extracted ICAOs MUST agree. Disagreement returns null so\n * the resolver falls through to Tier 2 city-derive (prevents an\n * issuer-side citation URL from silently swapping the settlement station).\n *\n * Returns uppercase ICAO (4 chars, leading K) when a canonical URL is\n * found AND any additional canonical URLs agree. Null otherwise —\n * including the disagreement case.\n */\nexport function extractIcaoFromResolutionSource(text: string | null | undefined): string | null {\n if (typeof text !== \"string\" || text.length === 0) return null;\n // Reset lastIndex on the global regex so multiple matchAll calls are safe\n // (the regex literal is reused across calls).\n const matches = [...text.matchAll(WUNDERGROUND_ICAO_RE)];\n if (matches.length === 0) return null;\n const unique = new Set<string>();\n for (const m of matches) {\n if (m[1] !== undefined) unique.add(m[1].toUpperCase());\n }\n if (unique.size !== 1) return null; // 0 or disagreement → abstain\n return [...unique][0] ?? null;\n}\n\n/**\n * Resolve an event to `{icao, stationMeasure}` using the city catalog.\n *\n * Returns null when no city matches (caller drops the event).\n * Raises DeferredMarketError when the resolution would route to a v0.2\n * source (Taipei RCTP, Hong Kong VHHH for the low-extreme market).\n */\nexport function resolveStationForEvent(\n event: PolymarketEventRaw,\n marketMeasure: \"high\" | \"low\" | \"default\",\n): { city: string; icao: string; stationMeasure: \"high\" | \"low\" | \"default\" } | null {\n // Tier 1: explicit city field — useful for tests / synthetic events.\n let cityKey: string | null = null;\n const explicit = (event as { city?: unknown }).city;\n if (typeof explicit === \"string\") {\n const low = explicit.toLowerCase();\n if (Object.prototype.hasOwnProperty.call(POLYMARKET_CITY_STATIONS, low)) {\n cityKey = low;\n }\n }\n\n // Tier 1.5: URL extraction from description / resolutionSource.\n // The Wunderground URL is the issuer's canonical proof — beats catalog\n // lookup for ICAO. Defer gate still applies so a URL injection cannot\n // silently route an RCTP / HK-low market.\n //\n // Iter-1 TS-architect CRITICAL: the `city` field is owned by the slug-\n // derive layer (matching Python's `_derive_city`-before-resolve pattern in\n // `polymarket_discover`). Tier 1.5 ONLY sets `icao`; `city` is whatever\n // the caller / slug-derive resolved to BEFORE the URL was considered.\n // Returning `findCityForIcao(extractedIcao)` here would drift the TS row's\n // `city` column away from the Python row for the same event — silent\n // per-row source-identity drift, the parity-rubric CRITICAL.\n const desc = typeof event.description === \"string\" ? event.description : \"\";\n const resSrc =\n typeof (event as { resolutionSource?: unknown }).resolutionSource === \"string\"\n ? (event as { resolutionSource: string }).resolutionSource\n : \"\";\n const urlText = `${desc} ${resSrc}`;\n const extractedIcao = extractIcaoFromResolutionSource(urlText);\n if (extractedIcao !== null) {\n if (extractedIcao === \"RCTP\") {\n throw new DeferredMarketError(\n `Polymarket market for station ${extractedIcao} is deferred until the v0.2 CWA client lands`,\n );\n }\n if (extractedIcao === \"VHHH\" && marketMeasure === \"low\") {\n throw new DeferredMarketError(\n `Polymarket low-extreme market for station ${extractedIcao} is deferred until the v0.2 HKO client lands`,\n );\n }\n if (DEFERRED_STATIONS.has(extractedIcao) && marketMeasure === \"default\") {\n throw new DeferredMarketError(\n `Polymarket market for deferred station ${extractedIcao} (measure=default) requires v0.2 client`,\n );\n }\n // City: explicit Tier 1 wins; otherwise slug-derived; otherwise empty.\n // This mirrors Python `polymarket_discover`'s ordering — `_derive_city`\n // populates `event.city` BEFORE `resolve_station_for_event` runs, so the\n // explicit-or-derived city is always the `city` column emitted on the row.\n // discover.ts normalizes empty string back to null at the row boundary\n // to mirror Python's `(ev.get(\"city\") or \"\").lower() or None` semantics.\n const cityForRow = cityKey ?? deriveCity(event) ?? \"\";\n // stationMeasure mirrors Python's _detect_measure(text) result (passed\n // in by the caller as marketMeasure via detectMarketMeasure). Hardcoding\n // \"default\" here would drift from Python for URL-sourced low/high\n // markets (codex iter-2 HIGH).\n return { city: cityForRow, icao: extractedIcao, stationMeasure: marketMeasure };\n }\n\n // Tier 2: scan slug + title + tags.\n if (cityKey === null) {\n cityKey = deriveCity(event);\n }\n if (cityKey === null) return null;\n\n const entry = POLYMARKET_CITY_STATIONS[cityKey];\n if (entry === undefined) return null;\n\n // Station-level measure: cities that split (paris high vs low) follow\n // the market measure; cities without a split use \"default\".\n let stationMeasure: \"high\" | \"low\" | \"default\" = \"default\";\n if (marketMeasure === \"high\" && typeof entry.high === \"string\") stationMeasure = \"high\";\n else if (marketMeasure === \"low\" && typeof entry.low === \"string\") stationMeasure = \"low\";\n\n const icao = entry[stationMeasure] ?? entry.default;\n if (typeof icao !== \"string\") return null;\n\n // Tier 0 deferred-station guard. Taipei (RCTP) defers all markets;\n // Hong Kong (VHHH) defers only the low market because HKO is the issuer\n // for the daily low. High markets at HK resolve via standard METAR.\n if (icao === \"RCTP\") {\n throw new DeferredMarketError(\n `Polymarket market for station ${icao} is deferred until the v0.2 CWA client lands`,\n );\n }\n if (icao === \"VHHH\" && marketMeasure === \"low\") {\n throw new DeferredMarketError(\n `Polymarket low-extreme market for station ${icao} is deferred until the v0.2 HKO client lands`,\n );\n }\n if (DEFERRED_STATIONS.has(icao) && marketMeasure === \"default\") {\n // Conservative default fallback for deferred stations.\n throw new DeferredMarketError(\n `Polymarket market for deferred station ${icao} (measure=default) requires v0.2 client`,\n );\n }\n\n return { city: cityKey, icao, stationMeasure };\n}\n\n/**\n * Parse the resolution date from a Polymarket weather slug. The LAST\n * YYYY-MM-DD match wins because slugs may carry both a creation date and\n * a resolution date (`created-2026-01-01-resolves-2026-05-23`) — the\n * resolution date is typically rightmost in Polymarket's convention.\n *\n * Mirrors Python `_settlement_date_from_slug` architect iter-1 HIGH-4.\n */\nexport function settlementDateFromSlug(slug: string): string {\n const matches = slug.matchAll(/(\\d{4})-(\\d{2})-(\\d{2})/g);\n let last: RegExpMatchArray | null = null;\n for (const m of matches) last = m;\n if (last === null) {\n throw new PolymarketSettlementError(\n `no resolution date in slug ${JSON.stringify(slug)} (expected YYYY-MM-DD)`,\n );\n }\n const [_, y, m, d] = last;\n const year = Number(y);\n const month = Number(m);\n const day = Number(d);\n // Validate calendar date roundtrips (e.g. reject 2025-02-30).\n const ts = Date.UTC(year, month - 1, day);\n const back = new Date(ts);\n if (\n back.getUTCFullYear() !== year ||\n back.getUTCMonth() !== month - 1 ||\n back.getUTCDate() !== day\n ) {\n throw new PolymarketSettlementError(\n `slug ${JSON.stringify(slug)} carries malformed date ${y}-${m}-${d}`,\n );\n }\n return `${y}-${m}-${d}`;\n}\n","// AUTO-GENERATED by @mostlyrightmd/codegen from schemas/polymarket-city-stations.json.\n// DO NOT EDIT — regenerate with: pnpm codegen\n// Last manifest SHA recorded in schemas/EXPORT_MANIFEST.json\n\nexport interface PolymarketCityStation {\n default: string;\n high?: string;\n low?: string;\n [measure: string]: string | undefined;\n}\n\nexport const POLYMARKET_CITY_STATIONS: Readonly<Record<string, PolymarketCityStation>> = {\n amsterdam: {\n default: \"EHAM\",\n },\n atlanta: {\n default: \"KATL\",\n },\n auckland: {\n default: \"NZAA\",\n },\n austin: {\n default: \"KAUS\",\n },\n bangkok: {\n default: \"VTBS\",\n },\n barcelona: {\n default: \"LEBL\",\n },\n beijing: {\n default: \"ZBAA\",\n },\n berlin: {\n default: \"EDDB\",\n },\n boston: {\n default: \"KBOS\",\n },\n brisbane: {\n default: \"YBBN\",\n },\n buenos_aires: {\n default: \"SAEZ\",\n },\n chicago: {\n default: \"KORD\",\n high: \"KORD\",\n low: \"KORD\",\n },\n copenhagen: {\n default: \"EKCH\",\n },\n dallas: {\n default: \"KDFW\",\n },\n delhi: {\n default: \"VIDP\",\n },\n denver: {\n default: \"KDEN\",\n },\n detroit: {\n default: \"KDTW\",\n },\n doha: {\n default: \"OTHH\",\n },\n dubai: {\n default: \"OMDB\",\n },\n frankfurt: {\n default: \"EDDF\",\n },\n helsinki: {\n default: \"EFHK\",\n },\n hong_kong: {\n default: \"VHHH\",\n high: \"VHHH\",\n low: \"VHHH\",\n },\n houston: {\n default: \"KIAH\",\n },\n london: {\n default: \"EGLL\",\n },\n london_gatwick: {\n default: \"EGKK\",\n },\n los_angeles: {\n default: \"KLAX\",\n high: \"KLAX\",\n low: \"KLAX\",\n },\n madrid: {\n default: \"LEMD\",\n },\n melbourne: {\n default: \"YMML\",\n },\n miami: {\n default: \"KMIA\",\n },\n milan: {\n default: \"LIMC\",\n },\n minneapolis: {\n default: \"KMSP\",\n },\n moscow: {\n default: \"UUEE\",\n },\n mumbai: {\n default: \"VABB\",\n },\n munich: {\n default: \"EDDM\",\n },\n nyc: {\n default: \"KLGA\",\n high: \"KLGA\",\n low: \"KLGA\",\n },\n paris: {\n default: \"LFPG\",\n high: \"LFPG\",\n low: \"LFPB\",\n },\n paris_orly: {\n default: \"LFPO\",\n },\n philadelphia: {\n default: \"KPHL\",\n },\n phoenix: {\n default: \"KPHX\",\n },\n riyadh: {\n default: \"OERK\",\n },\n rome: {\n default: \"LIRF\",\n },\n san_francisco: {\n default: \"KSFO\",\n },\n sao_paulo: {\n default: \"SBGR\",\n },\n seattle: {\n default: \"KSEA\",\n },\n seoul: {\n default: \"RKSI\",\n },\n shanghai: {\n default: \"ZSPD\",\n },\n singapore: {\n default: \"WSSS\",\n },\n stockholm: {\n default: \"ESSA\",\n },\n sydney: {\n default: \"YSSY\",\n },\n taipei: {\n default: \"RCTP\",\n },\n tokyo: {\n default: \"RJTT\",\n high: \"RJTT\",\n low: \"RJTT\",\n },\n tokyo_narita: {\n default: \"RJAA\",\n },\n vienna: {\n default: \"LOWW\",\n },\n warsaw: {\n default: \"EPWA\",\n },\n washington_dc: {\n default: \"KDCA\",\n },\n wellington: {\n default: \"NZWN\",\n },\n zurich: {\n default: \"LSZH\",\n },\n} as const;\n","// Phase 8 — per-issuer denylist. Hand-paired with Python\n// `mostlyright.markets.polymarket.KNOWN_WRONG_STATIONS` (NOT codegen;\n// see .planning/phases/08-.../PLAN.md §\"TS Parity\" for rationale —\n// the constant is small enough that exporter wiring would cost more\n// than it saves, and the alphabetized JSON exporter side-effect would\n// conflate it with the cities map).\n//\n// Per-city Map (not flat set) because Polymarket's catalog is multi-city\n// and the \"wrong\" station depends on which city the event is for.\n// Symmetric in spirit to Kalshi's KALSHI_KNOWN_WRONG_STATIONS flat set:\n// Polymarket's per-city granularity is required because (e.g.) KLGA is\n// correct for NYC but wrong for Chicago (where Polymarket uses KORD).\n\nexport const POLYMARKET_KNOWN_WRONG_STATIONS: Readonly<Record<string, ReadonlySet<string>>> =\n Object.freeze({\n // NYC: Polymarket uses KLGA. KNYC/KJFK/KEWR are common wrong answers.\n nyc: new Set([\"KNYC\", \"KJFK\", \"KEWR\"]),\n // Chicago: Polymarket uses KORD. KMDW is the common wrong answer.\n chicago: new Set([\"KMDW\"]),\n // Houston: Polymarket uses KIAH. KHOU is the common wrong answer.\n houston: new Set([\"KHOU\"]),\n // Dallas: Polymarket uses KDFW. KDAL is the common wrong answer.\n dallas: new Set([\"KDAL\"]),\n // SF: Polymarket uses KSFO. KOAK is the common wrong answer.\n san_francisco: new Set([\"KOAK\"]),\n // DC: Polymarket uses KDCA. KIAD/KBWI are common wrong answers.\n washington_dc: new Set([\"KIAD\", \"KBWI\"]),\n });\n","// TS-W5 Wave 4 — polymarketSettle().\n//\n// Settlement engine that consumes internationalDailyExtremes() from\n// @mostlyrightmd/core/discovery (TS-W6) as the resolution source, applies\n// the security/validation gates (event-id regex, 16 KB description cap,\n// netloc allowlist), and gates on the per-source publication-delay\n// window via TooEarlyToSettleError.\n//\n// Returns `{ icao, measure, resolvedValue, resolutionSourceType, settlementDate, dataQualityAlert }`.\n//\n// Threshold-bucket parsing (Python computes win/lose buckets from\n// description text) is deferred to v0.2 — for v0.1.0 we return the raw\n// resolved value (the daily extreme) and the caller picks the bucket.\n// This matches the contract the plan documents: \"ports the resolution\n// path, not the bucket-parser\".\n\nimport { STATIONS } from \"@mostlyrightmd/core\";\nimport { type InternationalRow, internationalDailyExtremes } from \"@mostlyrightmd/core/discovery\";\n\nimport { type PolymarketEventRaw, fetchEventById } from \"./client.js\";\nimport { extractResolutionSourceType, validateDescription } from \"./description.js\";\nimport {\n PolymarketEventError,\n PolymarketSettlementError,\n TooEarlyToSettleError,\n} from \"./errors.js\";\nimport { detectMarketMeasure, resolveStationForEvent, settlementDateFromSlug } from \"./resolver.js\";\nimport {\n EVENT_ID_RE,\n type PolymarketResolutionSourceType,\n type PolymarketSettleOptions,\n type PolymarketSettlementResult,\n SETTLE_DELAY_HOURS,\n} from \"./types.js\";\n\n/**\n * Loader contract for the resolution-source observation rows. Defaults to\n * a no-op stub so the security/validation gates can be unit-tested without\n * pulling live cache data; production callers wire the cache reader here.\n *\n * Returning an empty array signals \"no rows available for this date\" and\n * surfaces as PolymarketSettlementError downstream.\n */\nexport type ObservationLoader = (args: {\n icao: string;\n fromDate: string;\n toDate: string;\n}) => Promise<ReadonlyArray<InternationalRow>>;\n\nexport interface PolymarketSettleArgs extends PolymarketSettleOptions {\n /**\n * The raw Gamma event payload. Required because the settle engine reads\n * `slug` (for the resolution date), `description` (for the resolution\n * source), and `title/slug/name` (for the measure). Callers can fetch\n * via `fetchEventById` if they only have an id.\n */\n readonly event: PolymarketEventRaw;\n /**\n * Loader that returns observation rows for `[fromDate, toDate]`. Defaults\n * to an in-memory empty loader so callers MUST wire this for production.\n */\n readonly loader?: ObservationLoader;\n}\n\nfunction tzForStation(icao: string): string | null {\n for (const s of STATIONS) {\n if (s.icao === icao) return s.tz;\n }\n return null;\n}\n\nfunction safeUuidIsh(eventId: string): boolean {\n return typeof eventId === \"string\" && EVENT_ID_RE.test(eventId);\n}\n\n/**\n * Settle a single Polymarket event.\n *\n * Validates the event id, description (16 KB cap, netloc allowlist),\n * resolves the station via the city catalog, parses the resolution date\n * from the slug, enforces the per-source publication-delay window, and\n * pulls the daily extreme via `internationalDailyExtremes`.\n *\n * @throws PolymarketEventError on bad id / bad description / unsupported station.\n * @throws PolymarketSettlementError when no rows resolve for the station/date.\n * @throws TooEarlyToSettleError when the publication delay hasn't elapsed.\n */\nexport async function polymarketSettle(\n args: PolymarketSettleArgs,\n): Promise<PolymarketSettlementResult> {\n const event = args.event;\n const eventId = typeof event.id === \"string\" ? event.id : \"\";\n if (!safeUuidIsh(eventId)) {\n throw new PolymarketEventError(\n `event id ${JSON.stringify(eventId)} does not match ${EVENT_ID_RE.source}`,\n );\n }\n const slug = typeof event.slug === \"string\" ? event.slug : \"\";\n if (slug.length === 0) {\n throw new PolymarketSettlementError(\"event.slug is required for settlement (carries the date)\");\n }\n const description =\n args.description ?? (typeof event.description === \"string\" ? event.description : \"\");\n validateDescription(description);\n const resolutionSourceType: PolymarketResolutionSourceType =\n description.length > 0 ? extractResolutionSourceType(description) : \"other\";\n\n const marketMeasure = detectMarketMeasure(event);\n const resolved = resolveStationForEvent(event, marketMeasure);\n if (resolved === null) {\n throw new PolymarketSettlementError(\n `unable to resolve station for slug=${JSON.stringify(slug)} — no matching city in catalog`,\n );\n }\n\n const settlementDate = settlementDateFromSlug(slug);\n const now = args.now ?? new Date();\n\n // Finalization-delay gate. We compare `now` to the station-local end of\n // day (23:59:59 in the station's tz) so the delay doesn't fire too early\n // for stations east of UTC.\n const tz = tzForStation(resolved.icao) ?? \"UTC\";\n const localEodMs = stationLocalEodUtcMs(settlementDate, tz);\n const delayHours = SETTLE_DELAY_HOURS[resolutionSourceType] ?? SETTLE_DELAY_HOURS.other ?? 24;\n const delayMs = delayHours * 3600 * 1000;\n const earliestSettleMs = localEodMs + delayMs;\n if (now.getTime() < earliestSettleMs) {\n const waitMs = earliestSettleMs - now.getTime();\n throw new TooEarlyToSettleError(\n `settlement for ${resolved.icao} on ${settlementDate} (source=${resolutionSourceType}) requires another ${(\n waitMs / 3600 / 1000\n ).toFixed(2)} h`,\n { waitHours: waitMs / 3600 / 1000, resolutionSourceType },\n );\n }\n\n const loader = args.loader ?? defaultEmptyLoader;\n const rows = await loader({\n icao: resolved.icao,\n fromDate: settlementDate,\n toDate: settlementDate,\n });\n if (rows.length === 0) {\n throw new PolymarketSettlementError(\n `no observation rows for station=${resolved.icao} date=${settlementDate} — warm the cache first`,\n );\n }\n\n const extremes = internationalDailyExtremes(rows, { stationTz: tz });\n const day = extremes.find((r) => r.localDate === settlementDate);\n if (day === undefined) {\n throw new PolymarketSettlementError(\n `no daily extreme for station=${resolved.icao} on local date ${settlementDate}`,\n );\n }\n\n // Pick the value per the market measure. Codex iter-1 P2: ambiguous\n // markets (default measure — title has both/neither high+low keywords)\n // are NOT settled blind; refuse and force the caller to disambiguate.\n // Mirrors Python's stricter behavior on average / non-extreme wordings.\n let resolvedValueC: number | null = null;\n let resolvedValueF: number | null = null;\n if (marketMeasure === \"low\") {\n resolvedValueC = day.tempMinC;\n resolvedValueF = day.tempMinF;\n } else if (marketMeasure === \"high\") {\n resolvedValueC = day.tempMaxC;\n resolvedValueF = day.tempMaxF;\n } else {\n throw new PolymarketSettlementError(\n `event ${JSON.stringify(eventId)} (slug=${JSON.stringify(slug)}) has ambiguous measure (\"default\" — title carries neither high nor low keyword); refusing to settle silently. Disambiguate at the caller.`,\n );\n }\n if (resolvedValueC === null || resolvedValueF === null) {\n throw new PolymarketSettlementError(\n `daily extreme for ${resolved.icao} on ${settlementDate} has null ${marketMeasure} (low coverage)`,\n );\n }\n\n // Codex iter-3 P2: native unit selection. International Polymarket markets\n // publish in whole-°C; US Kalshi markets publish in °F. Default unit follows\n // the station's country (US → F, else C); caller can override with the\n // `unit` option. dataQualityAlert compares in the SAME unit as the\n // resolved/published values.\n const isUsStation = STATIONS.find((s) => s.icao === resolved.icao)?.country === \"US\";\n const unit = args.unit ?? (isUsStation ? \"fahrenheit\" : \"celsius\");\n const resolvedValue = unit === \"celsius\" ? resolvedValueC : resolvedValueF;\n\n let dataQualityAlert: string | null = null;\n if (typeof args.polymarketPublishedValue === \"number\") {\n const diff = Math.abs(resolvedValue - args.polymarketPublishedValue);\n const threshold = unit === \"celsius\" ? 0.6 : 1;\n const unitSym = unit === \"celsius\" ? \"°C\" : \"°F\";\n if (diff > threshold) {\n dataQualityAlert = `mostlyright resolved ${resolvedValue}${unitSym} but Polymarket published ${args.polymarketPublishedValue}${unitSym} (Δ=${diff.toFixed(2)}${unitSym} > ${threshold}${unitSym} threshold)`;\n }\n }\n\n return Object.freeze({\n eventId,\n settlementDate,\n icao: resolved.icao,\n measure: marketMeasure,\n resolvedValue,\n resolvedValueC,\n resolvedValueF,\n unit,\n resolutionSourceType,\n dataQualityAlert,\n });\n}\n\n/**\n * Settle by event id alone. Fetches the event from Gamma first, then\n * delegates to `polymarketSettle`. Useful when a caller only has the id\n * (e.g. from a Kalshi-side cross-reference).\n */\nexport async function polymarketSettleById(\n eventId: string,\n args: Omit<PolymarketSettleArgs, \"event\">,\n): Promise<PolymarketSettlementResult> {\n if (!safeUuidIsh(eventId)) {\n throw new PolymarketEventError(\n `event id ${JSON.stringify(eventId)} does not match ${EVENT_ID_RE.source}`,\n );\n }\n const event = await fetchEventById(eventId);\n if (event === null) {\n throw new PolymarketSettlementError(\n `Gamma returned 404 for event id ${JSON.stringify(eventId)}`,\n );\n }\n return polymarketSettle({ ...args, event });\n}\n\nasync function defaultEmptyLoader(): Promise<ReadonlyArray<InternationalRow>> {\n return [];\n}\n\n/**\n * Compute the UTC ms instant of station-local 23:59:59 for the given date.\n * Used by the publication-delay gate so the delay doesn't fire too early\n * for stations east of UTC (architect iter-1 HIGH-1 in the Python port).\n */\nfunction stationLocalEodUtcMs(localDate: string, tz: string): number {\n // Step 1: pick a UTC instant guaranteed inside the local day (noon UTC\n // gets us inside the local day for every tz on Earth).\n const noon = new Date(`${localDate}T12:00:00Z`);\n // Step 2: extract the local-tz year/month/day for that instant via\n // Intl.DateTimeFormat (matches the discovery/international.ts trick).\n const fmt = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: tz,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n });\n const parts = fmt.formatToParts(noon);\n let y = \"\";\n let m = \"\";\n let d = \"\";\n for (const p of parts) {\n if (p.type === \"year\") y = p.value;\n else if (p.type === \"month\") m = p.value;\n else if (p.type === \"day\") d = p.value;\n }\n // Step 3: find the UTC instant that is the local-midnight of the day\n // AFTER `localDate`. Iterate from the canonical UTC midnight of nextDay\n // outward in 15-minute steps (the finest IANA offset granularity in\n // common use — Nepal Asia/Kathmandu is +5:45). Codex iter-1 P3: a\n // 1-hour step missed Asia/Kolkata (+5:30), Asia/Kathmandu (+5:45) and\n // similar half/quarter-hour zones, returning end-of-day 30 min late.\n const nextDay = new Date(`${localDate}T00:00:00Z`);\n nextDay.setUTCDate(nextDay.getUTCDate() + 1);\n const expectedDate = nextDayDate(localDate);\n const minuteFmt = new Intl.DateTimeFormat(\"en-US\", {\n timeZone: tz,\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: false,\n });\n // Step size: 15 min. Range: ±15 hours of UTC for max IANA offset spread.\n const STEP_MIN = 15;\n const RANGE_MIN = 15 * 60;\n for (let offsetMin = -RANGE_MIN; offsetMin <= RANGE_MIN; offsetMin += STEP_MIN) {\n const candidate = new Date(nextDay.getTime() + offsetMin * 60 * 1000);\n const cParts = fmt.formatToParts(candidate);\n let cy = \"\";\n let cm = \"\";\n let cd = \"\";\n for (const p of cParts) {\n if (p.type === \"year\") cy = p.value;\n else if (p.type === \"month\") cm = p.value;\n else if (p.type === \"day\") cd = p.value;\n }\n if (`${cy}-${cm}-${cd}` !== expectedDate) continue;\n const tParts = minuteFmt.formatToParts(candidate);\n const hourStr = tParts.find((p) => p.type === \"hour\")?.value ?? \"00\";\n const minStr = tParts.find((p) => p.type === \"minute\")?.value ?? \"00\";\n const hour = hourStr === \"24\" ? 0 : Number(hourStr);\n const minute = Number(minStr);\n if (hour === 0 && minute === 0) {\n return candidate.getTime() - 1000;\n }\n }\n // Fallback: assume UTC if we can't resolve.\n return new Date(`${localDate}T23:59:59Z`).getTime();\n}\n\nfunction nextDayDate(localDate: string): string {\n const d = new Date(`${localDate}T00:00:00Z`);\n d.setUTCDate(d.getUTCDate() + 1);\n return d.toISOString().slice(0, 10);\n}\n"],"mappings":"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","names":["DeferredMarketError","m","DeferredMarketError"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mostlyrightmd/markets",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Prediction-market data for TypeScript / Node — Kalshi NHIGH/NLOW weather-contract resolvers, Polymarket discovery + settlement, and Kalshi + Polymarket trade history. For quants, backtesting, and ML training pipelines.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"kalshi",
|
|
@@ -55,13 +55,13 @@
|
|
|
55
55
|
"dist"
|
|
56
56
|
],
|
|
57
57
|
"peerDependencies": {
|
|
58
|
-
"@mostlyrightmd/core": "^1.
|
|
58
|
+
"@mostlyrightmd/core": "^1.4.0"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
61
|
"tsup": "8.3.5",
|
|
62
62
|
"typescript": "5.6.3",
|
|
63
63
|
"vitest": "2.1.9",
|
|
64
|
-
"@mostlyrightmd/core": "1.
|
|
64
|
+
"@mostlyrightmd/core": "1.4.0"
|
|
65
65
|
},
|
|
66
66
|
"publishConfig": {
|
|
67
67
|
"access": "public"
|