RareIndex foundation: monorepo, shared schemas, database (55 tables), taxonomy, connector framework, web shell
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
101 changed files +19,307 −0
added
.env.example
+35 −0
@@ -0,0 +1,35 @@ | ||
| 1 | +# Copy to .env (never commit .env). All secrets are read server-side only. | |
| 2 | + | |
| 3 | +# PostgreSQL 17 (extensions used: pg_trgm, unaccent, vector when available) | |
| 4 | +DATABASE_URL=postgres://localhost:5432/rareindex | |
| 5 | + | |
| 6 | +# Extraction engines (server-side only — never shipped to the browser) | |
| 7 | +FIRECRAWL_API_KEY= | |
| 8 | +SCRAPFLY_API_KEY= | |
| 9 | + | |
| 10 | +# AI providers (any subset; the model router picks what is configured) | |
| 11 | +ANTHROPIC_API_KEY= | |
| 12 | +OPENAI_API_KEY= | |
| 13 | +# OpenAI-compatible local gateway (optional) | |
| 14 | +LOCAL_LLM_BASE_URL= | |
| 15 | +LOCAL_LLM_API_KEY= | |
| 16 | + | |
| 17 | +# Optional source API keys | |
| 18 | +POKEMONTCG_API_KEY= | |
| 19 | + | |
| 20 | +# Web | |
| 21 | +NEXT_PUBLIC_SITE_URL=http://localhost:3000 | |
| 22 | +SESSION_SECRET=change-me-32-bytes-minimum | |
| 23 | +ADMIN_TOKEN=change-me | |
| 24 | + | |
| 25 | +# Public API | |
| 26 | +API_PORT=8211 | |
| 27 | +WEB_PORT=8210 | |
| 28 | + | |
| 29 | +# Worker | |
| 30 | +WORKER_CONCURRENCY=4 | |
| 31 | +LOG_LEVEL=info | |
| 32 | + | |
| 33 | +# Transactional email (verification codes, MFA codes, alerts, digests) | |
| 34 | +RESEND_API_KEY= | |
| 35 | +EMAIL_FROM=RareIndex <no-reply@rareindex.io> | |
added
.gitignore
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +node_modules/ | |
| 2 | +dist/ | |
| 3 | +.next/ | |
| 4 | +out/ | |
| 5 | +*.tsbuildinfo | |
| 6 | +.env | |
| 7 | +.env.* | |
| 8 | +!.env.example | |
| 9 | +logs/ | |
| 10 | +*.log | |
| 11 | +.DS_Store | |
| 12 | +coverage/ | |
| 13 | +.turbo/ | |
| 14 | +data/cache/ | |
| 15 | +data/raw/ | |
| 16 | +tmp/ | |
added
CLAUDE.md
+189 −0
@@ -0,0 +1,189 @@ | ||
| 1 | +# CLAUDE.md | |
| 2 | + | |
| 3 | +## RareIndex.io | |
| 4 | + | |
| 5 | +Global Collectibles Market Intelligence, Search, Pricing & Index Platform | |
| 6 | + | |
| 7 | +RareIndex.io must become the global reference platform for discovering, tracking, pricing, comparing, analyzing, and researching collectible assets. | |
| 8 | + | |
| 9 | +The ambition is significantly larger than a marketplace aggregator. | |
| 10 | + | |
| 11 | +RareIndex should become: **the Bloomberg Terminal, Google, CoinMarketCap, Zillow, and StockX of the global collectibles economy.** | |
| 12 | + | |
| 13 | +The platform must continuously collect public market data from marketplaces, auction houses, dealers, specialized websites, historical databases, grading companies, collector communities, manufacturer catalogs, archives, and other relevant sources. | |
| 14 | + | |
| 15 | +RareIndex should cover as many collectible categories as technically possible. | |
| 16 | + | |
| 17 | +The architecture must be built around: Firecrawl · Scrapfly · direct APIs when available · structured feeds · official datasets · auction databases · marketplace connectors · AI extraction · multimodal image analysis · entity resolution · historical sale normalization · deduplication · valuation models · global collectible indices · category indices · individual asset price histories · collection tracking · alerts · comparable-sales analysis · rarity analysis · grading normalization · liquidity analysis · AI-assisted identification. | |
| 18 | + | |
| 19 | +The platform language must be English-first. | |
| 20 | + | |
| 21 | +The application must be: extremely fast · visually exceptional · mobile-first · responsive · data dense without feeling cluttered · professional · credible · research-grade · scalable to hundreds of millions of records. | |
| 22 | + | |
| 23 | +> Repository companion docs: `docs/ARCHITECTURE.md` (what exists and how it fits), `docs/adr/` (decisions), `connectors/README.md` (how to add a source). Read them before changing structure. | |
| 24 | + | |
| 25 | +--- | |
| 26 | + | |
| 27 | +## 1. CORE PRODUCT VISION | |
| 28 | + | |
| 29 | +RareIndex should answer questions such as: What is this collectible worth? How rare is it? Has its value increased? What are the latest comparable sales? Where is it currently for sale? Which marketplace has the cheapest listing? What is the global market price? What is the price trend? What is the liquidity? How often does it sell? Is the market accelerating or declining? What grade commands the highest premium? Is this listing unusually cheap or expensive? Is the collectible likely misidentified? How many examples exist? What are similar collectibles? What are the most valuable objects in this category? What collectibles are trending globally? Which categories are outperforming? Where are collectors moving capital? How has Pokémon performed versus watches? How has LEGO performed versus the S&P 500? What are the best performing collectibles over 1Y / 5Y / 10Y? What is the most liquid collectible market? What items are becoming scarce? What discontinued products are appreciating rapidly? | |
| 30 | + | |
| 31 | +RareIndex must transform fragmented collectible markets into structured financial-style data. | |
| 32 | + | |
| 33 | +## 2. PRIMARY PLATFORM MODULES | |
| 34 | + | |
| 35 | +Main navigation: 1 Home · 2 Explore · 3 Markets · 4 Categories · 5 RareIndex · 6 Trending · 7 Sales · 8 Listings · 9 Auctions · 10 Price History · 11 Collections · 12 Watchlist · 13 Compare · 14 Scanner · 15 AI Research · 16 Market Map · 17 Grading · 18 Auction Calendar · 19 News · 20 Data · 21 API · 22 About | |
| 36 | + | |
| 37 | +## 3. RAREINDEX GLOBAL INDEX | |
| 38 | + | |
| 39 | +Flagship index: **RareIndex Global Collectibles Index**, ticker **RARE**. Subindices: RARE-TCG, RARE-SPORT, RARE-WATCH, RARE-SNEAKER, RARE-LEGO, RARE-COMIC, RARE-GAME, RARE-ART, RARE-LUXURY, RARE-WINE, RARE-COIN, RARE-TOY, RARE-MUSIC, RARE-AUTO, RARE-TECH, RARE-BOOK, RARE-MILITARIA, RARE-SPACE, RARE-FOSSIL, RARE-DESIGN. | |
| 40 | + | |
| 41 | +Each index should support: current value · daily change · weekly change · monthly change · YTD · 1 year · 3 years · 5 years · 10 years · all time · volatility · drawdown · liquidity score · transaction count · median sale price · average sale price · market capitalization estimate · number of tracked assets · category breadth · momentum. | |
| 42 | + | |
| 43 | +## 4. COLLECTIBLE CATEGORY UNIVERSE | |
| 44 | + | |
| 45 | +The architecture MUST NOT hardcode a small number of collectible categories. Use an extensible taxonomy (`data/taxonomy/categories.json`, `categories` table, `taxonomy_proposals`). | |
| 46 | + | |
| 47 | +Every category should support: category · subcategory · franchise · brand · series · model · release · variant · year · edition · condition · grade · grading company · certification number · provenance · country · material · size · color · serial number · production quantity · rarity · population · original MSRP · estimated value · latest sale · listing price · currency · marketplace · images · description · source URLs. | |
| 48 | + | |
| 49 | +## 5–100. CATEGORY MASTER LIST | |
| 50 | + | |
| 51 | +RareIndex should attempt to cover all of the following (each is a taxonomy family; details of sets, brands, tracked attributes and graders are captured in the taxonomy files and the connectors): | |
| 52 | + | |
| 53 | +5 Trading Cards (Pokémon — all eras, languages, promos, error/shadowless/1st edition, graded PSA/BGS/CGC/SGC/TAG/raw; Magic: The Gathering — Alpha→current, reserved list, promos, foils, serialized; Yu-Gi-Oh!; One Piece; Disney Lorcana; other TCGs) · 6 Sports Cards (all sports, Topps/Panini/Upper Deck/Bowman/Fleer/Donruss/Score/Leaf/Futera; rookies, numbered, parallels, autos, patches, 1/1, plates) · 7 Comics (Marvel, DC, Image, Dark Horse, IDW, Boom, Archie, Valiant, Dynamite, EC; keys, variants, pedigrees; CGC/CBCS/raw) · 8 Manga · 9 Video Games (all platforms; sealed/graded/CIB/loose/prototypes) · 10 Gaming Hardware · 11 Arcade & Pinball · 12 Sneakers · 13 Watches · 14 Luxury Handbags · 15 Fashion & Streetwear · 16 LEGO · 17 Funko · 18 Designer Toys · 19 Action Figures · 20 Vintage Toys · 21 Dolls · 22 Plush · 23 Model Cars · 24 Model Trains · 25 Automobiles · 26 Motorcycles · 27 Automotive Memorabilia · 28 Formula 1 · 29 Sports Memorabilia · 30 Coins (PCGS/NGC/ANACS/ICCS) · 31 Banknotes · 32 Stamps · 33 Books · 34 Historical Documents · 35 Autographs · 36 Music · 37 Music Memorabilia · 38 Musical Instruments · 39 Movie Memorabilia · 40 Movie Posters · 41 Animation Art · 42 Art · 43 Contemporary Art (do not hardcode value assumptions) · 44 Photography · 45 Cameras · 46 Apple Collectibles · 47 Vintage Computers · 48 Computer Hardware · 49 Mobile Phones · 50 Keyboards · 51 Audio Equipment · 52 Wine · 53 Whisky · 54 Rum · 55 Cognac · 56 Perfume · 57 Jewelry · 58 Gemstones (certification + provenance) · 59 Minerals · 60 Meteorites (weight + classification) · 61 Fossils (legally traded; provenance and jurisdiction flags) · 62 Antiques · 63 Porcelain · 64 Glass & Crystal · 65 Silver · 66 Clocks · 67 Pens · 68 Lighters · 69 Advertising Collectibles · 70 Disney · 71 Sanrio · 72 Star Wars · 73 Marvel · 74 DC · 75 Harry Potter · 76 Lord of the Rings · 77 Warhammer · 78 Gundam · 79 Travel · 80 Airline · 81 Aviation · 82 Space · 83 Militaria (legal; compliance restrictions implemented) · 84 Medals · 85 Olympic · 86 Maps · 87 Postcards · 88 License Plates · 89 Pins · 90 Board Games · 91 Chess · 92 Playing Cards · 93 Casino Memorabilia (where legal) · 94 Political Memorabilia (neutral presentation only) · 95 Royal Memorabilia · 96 Scientific Instruments · 97 Typewriters · 98 Vending Machines · 99 Historic Corporate Memorabilia · 100 Digital Collectibles (separate valuation model). | |
| 54 | + | |
| 55 | +## 101. FUTURE CATEGORY DISCOVERY | |
| 56 | + | |
| 57 | +RareIndex must automatically discover new collectible categories: crawl marketplaces → identify recurring product clusters → detect categories missing from the taxonomy → measure transaction volume → propose taxonomy nodes → admin queue → approval → auto-generate source connectors and schemas. The taxonomy must evolve continuously. | |
| 58 | + | |
| 59 | +## 102. CONNECTOR ARCHITECTURE | |
| 60 | + | |
| 61 | +Every source uses the standardized interface (`packages/connectors/src/types.ts`): | |
| 62 | + | |
| 63 | +```ts | |
| 64 | +interface RareIndexConnector { | |
| 65 | + meta: ConnectorMeta // id, name, categories, countries, languages… | |
| 66 | + crawl(ctx): AsyncIterable<RawRecordInput> | |
| 67 | + normalize(raw): Promise<NormalizedRecord[]> | |
| 68 | + healthCheck(ctx): Promise<ConnectorHealth> | |
| 69 | +} | |
| 70 | +``` | |
| 71 | + | |
| 72 | +## 103. FIRECRAWL | |
| 73 | + | |
| 74 | +Preferred engine for websites reliably parsed with HTML / markdown / structured extraction / sitemap discovery / crawling / search / dynamic rendering: category pages, search results, public catalogs, auction archives, sold-item databases, dealer inventory, pricing guides, manufacturer archives, grading info, encyclopedias, editorial market data. Output is converted into canonical JSON. | |
| 75 | + | |
| 76 | +## 104. SCRAPFLY | |
| 77 | + | |
| 78 | +Secondary extraction engine, difficult-site connector, dynamic rendering layer, proxy/geo routing layer, anti-bot-compatible access layer where legally permitted, fallback when ordinary extraction fails. | |
| 79 | + | |
| 80 | +Routing: **Direct API → Structured Feed → Firecrawl → Scrapfly → Browser Extraction → Manual Review.** | |
| 81 | + | |
| 82 | +Do NOT attempt to circumvent authentication, paywalls, CAPTCHAs, access controls, or other security protections unlawfully. Respect applicable laws, source terms, robots policies where applicable, copyright, privacy, rate limits, authentication boundaries. | |
| 83 | + | |
| 84 | +## 105. CONNECTOR FALLBACK ENGINE | |
| 85 | + | |
| 86 | +Every connector produces health metrics (`ConnectorHealth`: status, success_rate_24h, pages_attempted/success, firecrawl_success_rate, scrapfly_fallback_rate, parse_failure_rate, last_success, schema_version). Automatically detect page redesigns, selector failures, missing fields, duplicate explosion, abnormal price distributions, blocked requests, empty pages, unexpected redirects, currency parsing problems. | |
| 87 | + | |
| 88 | +## 106. CONNECTOR REGISTRY | |
| 89 | + | |
| 90 | +`/connectors/registry.json` (generated from per-connector `meta.json`): id, displayName, sourceType, enginePriority, categories, regions, languages, currency, supportsListings/Sold/Auctions/Images, refreshFrequencyMinutes. | |
| 91 | + | |
| 92 | +## 107. SOURCE TYPES | |
| 93 | + | |
| 94 | +marketplace · auction_house · dealer · pricing_guide · grading_company · manufacturer · museum · archive · catalog · collector_database · community · forum · news · analytics_provider · registry · official_source | |
| 95 | + | |
| 96 | +## 108. RAW INGESTION LAYER | |
| 97 | + | |
| 98 | +Never directly write scraped records into final product tables. Source → Raw payload → Extraction → Raw JSON → Normalization → Entity Resolution → Deduplication → Price Validation → Canonical Asset Match → Sale/Listing Database → Indices & Analytics. Raw records are immutable. | |
| 99 | + | |
| 100 | +## 109–111. CANONICAL MODELS | |
| 101 | + | |
| 102 | +Canonical asset (`assets` + `asset_variants`), sale (`sales`: source, url, type, date, price, currency, price_usd, buyer premium, condition, grade, location, images, raw title, confidence) and listing (`listings`: asking price, seller, source, location, shipping, condition, grade, dates, availability, quantity, seller reputation, images, description). **Listing price MUST NOT automatically equal market value.** | |
| 103 | + | |
| 104 | +## 112. ENTITY RESOLUTION | |
| 105 | + | |
| 106 | +Different sources describe the same collectible differently; they must resolve to the same canonical asset variant using deterministic identifiers, model numbers, card numbers, sets, year, UPC/ISBN/SKU, certification, serial, visual similarity, text and multimodal embeddings, LLM verification. | |
| 107 | + | |
| 108 | +## 113–114. IMAGE INTELLIGENCE & SCANNER | |
| 109 | + | |
| 110 | +Image pipelines for duplicate detection, identification, edition recognition, condition estimation, box/seal recognition; multimodal embeddings stored in pgvector. The Scanner accepts photos or a marketplace URL and estimates category, item, edition, year, variation, condition, grade range, rarity, value range, sales, comps and listings — always with confidence, never claiming professional authentication. | |
| 111 | + | |
| 112 | +## 115–124. PRICE ENGINE & SCORES | |
| 113 | + | |
| 114 | +Never use only the average. Compute latest sale, median 5/10/20, volume-weighted, trimmed mean, exponentially weighted, comparable-, grade- and condition-adjusted prices → **RIV (RareIndex Valuation)** with low/high estimate and confidence. Flag (never silently delete) outliers, fake/cancelled/bundle sales, misidentified items; keep audit logs. Category-specific condition scales; grading companies tracked separately with empirical premiums (PSA 10 ≠ BGS 10 ≠ CGC 10). Population reports → gem rate, scarcity, Population Momentum. Rarity Score 0–100 (unknown when data missing). Liquidity Score 0–100. Momentum 7d/30d/90d/1y. Value Opportunity Score (analytical data, not investment advice). Market capitalization only with methodology and confidence. | |
| 115 | + | |
| 116 | +## 125–136. PAGES, SEARCH, PORTFOLIO, ALERTS, AUCTIONS, COMPS, CURRENCY | |
| 117 | + | |
| 118 | +Category market pages (`/markets/<slug>`), world-class asset pages (header, metrics, charts, tabs Overview/Sales/Listings/Grades/Population/Images/History/Comparables/AI Analysis/Sources), natural-language global search, conversational AI research over structured internal data (no hallucination), collection portfolios with analytics, watchlists, alerts, auction calendar, comparable sales with similarity scores, price distribution (min/p25/median/p75/max/trimmed mean). Store native currency + historical FX + USD/CAD/EUR/GBP/JPY; never convert historical sales at today's rate. | |
| 119 | + | |
| 120 | +## 137–159. PLATFORM | |
| 121 | + | |
| 122 | +Internationalization later (canonical data language neutral). Hybrid search (PostgreSQL FTS + vectors, OpenSearch later). PostgreSQL + object storage + Redis/queues + vector storage. Event-driven pipeline (page_discovered, page_crawled, listing_created, listing_updated, sale_detected, entity_matched, valuation_updated, index_updated). Dynamic crawl scheduling by source importance. Full data provenance. Source trust score. `/admin/connectors` control center. AI connector repair with fixture validation. Connector test suite with fixtures. Marketplace and image deduplication (`cross_listing_group_id`, perceptual hashes). Fraud signals (analytical, never definitive). Data Quality 0–100. Market heatmap, trending algorithm, RareIndex 100, record sales, Rare Radar, market news, public API `/v1/...` with tiers, exports (CSV/JSON/Excel/PDF). | |
| 123 | + | |
| 124 | +## 160–166. DESIGN | |
| 125 | + | |
| 126 | +Institutional financial platform × modern luxury marketplace (Bloomberg, Sotheby's, Christie's, StockX, Linear, Stripe, Apple). Neutral base; accents only for gains, losses, index identity, rarity, alerts; dark mode. Homepage: "The Global Market for Collectibles" — search — live tape — stats — discovery grid (Trending Now, Biggest Movers, Record Sales, Rare Finds, Auctions Ending Soon, Most Watched, Newly Added, Market Insights). Mobile is not an afterthought. Performance: homepage interactive < 2 s, cached search < 300 ms, optimized images, SSR, CDN caching. | |
| 127 | + | |
| 128 | +## 167–171. TECH, AI ROUTER, COST, BUDGET, CHANGE DETECTION | |
| 129 | + | |
| 130 | +Next.js/TypeScript/React/Tailwind/TanStack; Node/TypeScript services; PostgreSQL; Redis/queues; object storage; Firecrawl + Scrapfly; AI provider abstraction (`ModelProvider { complete, extract, embed, vision }`) never locked to one vendor; cost tracking per connector/category/source/record/user/endpoint (`/admin/costs`); scraping budget engine (ETag, Last-Modified, content hashing, change-frequency estimates); listing change detection (New, Price Changed, Sold, Removed, Relisted, Auction Ended) with event history. | |
| 131 | + | |
| 132 | +## 172–179. BACKFILL, SEO, AUTH, PRIVACY, COMPLIANCE | |
| 133 | + | |
| 134 | +Aggressive but legitimate historical backfills with real source timestamps. Indexable SEO pages with Schema.org (Product, Offer, AggregateOffer, CollectionPage, Article, BreadcrumbList). Auth: email, Google, Apple, passkeys. Private collections private by default. Disclaimers: valuations are estimates; listing prices are not confirmed transactions; past performance does not guarantee future results; RareIndex does not authenticate items. Source attribution. **Prohibited automation**: no bypassing logins/paywalls/CAPTCHAs/authentication controls, no private data scraping, no unlawful circumvention. | |
| 135 | + | |
| 136 | +## 180–183. PHASES | |
| 137 | + | |
| 138 | +Phase 1 foundation: Pokémon, Sports Cards, Magic, Yu-Gi-Oh!, Watches, Sneakers, LEGO, Comics, Video Games, Funko/Designer Toys — canonical models, connectors, sale ingestion, listings, search, price engine, asset pages, category pages. Phase 2: coins, handbags, wine, whisky, cars, music, toys, books, art + portfolio, alerts, scanner, indices. Phase 3: all categories, AI category discovery, international sources, API, institutional analytics, backfills, research terminal. Phase 4: RareIndex Terminal (screener, correlation matrix, liquidity scanner, volatility ranking, historical returns, factor analysis, anomaly scanner). | |
| 139 | + | |
| 140 | +## 184–191. TERMINAL, FACTORS, CORRELATION, BENCHMARKS, DATA SCIENCE, CONFIDENCE | |
| 141 | + | |
| 142 | +Screener filters; collectible factors (research relationships without asserting causality); category correlation matrix; benchmarking vs S&P 500, NASDAQ, gold, Bitcoin, inflation, real estate (explain liquidity/methodology differences); research models (hedonic, nearest-neighbor comps, gradient boosting, Bayesian, time-series smoothing, repeat-sales, hierarchical, multimodal embeddings). Every statistic shows sample size, confidence, last update. | |
| 143 | + | |
| 144 | +## 192. DO NOT INVENT DATA | |
| 145 | + | |
| 146 | +Absolute rule. Never fabricate sale prices, production counts, grading populations, market caps, auctions, listing availability. When data is missing, "Data unavailable" is better than hallucination. | |
| 147 | + | |
| 148 | +## 193–194. OBSERVABILITY & SECURITY | |
| 149 | + | |
| 150 | +Structured logs, traces, metrics, error reporting (crawl latency, parsing errors, DB latency, AI cost, connector health, queue lag, valuation failures). Strict secrets management, server-side credentials only, encryption, rate limits, abuse prevention, input validation. Never expose Firecrawl, Scrapfly, AI keys or database credentials. | |
| 151 | + | |
| 152 | +## 195. REPOSITORY STRUCTURE | |
| 153 | + | |
| 154 | +``` | |
| 155 | +rareindex/ | |
| 156 | +├── apps/ (web, api, admin→ inside web /admin for Phase 1) | |
| 157 | +├── packages/ (database, taxonomy, valuation, search, indices, ai, connectors, shared) | |
| 158 | +├── workers/ (crawler, normalizer, entity-resolution, valuation, image-processing, indices) | |
| 159 | +├── connectors/ (firecrawl, scrapfly, api, feeds, registry.json) | |
| 160 | +├── data/ (taxonomy, fixtures) | |
| 161 | +├── docs/ · scripts/ · CLAUDE.md | |
| 162 | +``` | |
| 163 | + | |
| 164 | +## 196. ENGINEERING RULES FOR CLAUDE CODE | |
| 165 | + | |
| 166 | +1 Inspect the existing repository first. 2 Never overwrite working functionality unnecessarily. 3 Prefer reusable abstractions. 4 Avoid monolithic files. 5 Keep connector logic isolated. 6 Keep source-specific logic outside the canonical domain model. 7 Add tests for every connector. 8 Add migrations for DB changes. 9 Keep TypeScript strict. 10 Validate external payloads. 11 Use Zod. 12 Log extraction failures. 13 Never swallow exceptions silently. 14 Build responsive UI from the beginning. 15 Optimize database indexes. 16 Avoid premature microservices. 17 Document major architectural decisions. 18 Never hardcode credentials. 19 Never invent fake production data. 20 Preserve traceability from every normalized datapoint to its source. | |
| 167 | + | |
| 168 | +## 197. CONNECTOR IMPLEMENTATION RULE | |
| 169 | + | |
| 170 | +A new marketplace requires only: connector metadata · extraction schema · normalization adapter · test fixtures. The rest of the ingestion pipeline works automatically. | |
| 171 | + | |
| 172 | +## 198–199. ROUTER & EXTRACTION QUALITY | |
| 173 | + | |
| 174 | +`fetchCollectiblePage`: official API → Firecrawl (quality ≥ MIN) → Scrapfly (quality ≥ MIN) → requiresReview. Quality weights: Title 20% · Price 20% · Status 15% · Date 10% · Images 10% · Description 5% · Identifiers 10% · Category 5% · Currency 5%. | |
| 175 | + | |
| 176 | +## 200–202. ULTIMATE GOAL, PRINCIPLE, MANDATE | |
| 177 | + | |
| 178 | +One canonical asset graph containing every collectible, every important variation, every observable listing, every verified historical sale, and every meaningful market signal that can legally and reliably be obtained. Always prioritize data quality over superficial features; admit insufficient evidence rather than display a number; build the intelligence platform, not a generic marketplace. Build incrementally but architect from day one for millions of models, hundreds of millions of observations, thousands of sources, global currencies, multilingual descriptions and billions of image references. RareIndex is the global data layer for collectible assets. | |
| 179 | + | |
| 180 | +--- | |
| 181 | + | |
| 182 | +## Repository conventions (added by the implementation) | |
| 183 | + | |
| 184 | +- Package manager `pnpm`; `pnpm typecheck`, `pnpm test`, `pnpm build`. Workers run with `tsx`. | |
| 185 | +- Secrets only in `.env` (git-ignored) or the `mld` manifest on the cluster. Never in code or fixtures. | |
| 186 | +- Add a connector: `connectors/<engine>/<id>/{meta.json,index.ts,index.test.ts}` + `data/fixtures/<id>/*.json`, then `pnpm tsx scripts/build-registry.ts` and `pnpm db:seed`. | |
| 187 | +- DB changes: edit `packages/database/src/schema/*`, run `pnpm db:generate`, commit the SQL migration. | |
| 188 | +- UI: dense, neutral, tabular numbers (`num` utility), `<Unavailable/>` for missing evidence, every number with its sample size / confidence / freshness when it is an estimate. | |
| 189 | +- Member accounts: email + password, email verification code and multi-factor code delivered through Resend (`RESEND_API_KEY`, `EMAIL_FROM`). | |
added
apps/api/package.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"name":"@rareindex/api","version":"0.1.0","private":true,"type":"module","scripts":{"typecheck":"tsc -p tsconfig.json --noEmit","test":"vitest run --passWithNoTests","build":"tsc -p tsconfig.json --noEmit"},"dependencies":{"@rareindex/shared":"workspace:*"},"devDependencies":{"@types/node":"^24.0.0","typescript":"^5.9.3","vitest":"^3.2.0"}} | |
added
apps/web/.gitignore
+41 −0
@@ -0,0 +1,41 @@ | ||
| 1 | +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | |
| 2 | + | |
| 3 | +# dependencies | |
| 4 | +/node_modules | |
| 5 | +/.pnp | |
| 6 | +.pnp.* | |
| 7 | +.yarn/* | |
| 8 | +!.yarn/patches | |
| 9 | +!.yarn/plugins | |
| 10 | +!.yarn/releases | |
| 11 | +!.yarn/versions | |
| 12 | + | |
| 13 | +# testing | |
| 14 | +/coverage | |
| 15 | + | |
| 16 | +# next.js | |
| 17 | +/.next/ | |
| 18 | +/out/ | |
| 19 | + | |
| 20 | +# production | |
| 21 | +/build | |
| 22 | + | |
| 23 | +# misc | |
| 24 | +.DS_Store | |
| 25 | +*.pem | |
| 26 | + | |
| 27 | +# debug | |
| 28 | +npm-debug.log* | |
| 29 | +yarn-debug.log* | |
| 30 | +yarn-error.log* | |
| 31 | +.pnpm-debug.log* | |
| 32 | + | |
| 33 | +# env files (can opt-in for committing if needed) | |
| 34 | +.env* | |
| 35 | + | |
| 36 | +# vercel | |
| 37 | +.vercel | |
| 38 | + | |
| 39 | +# typescript | |
| 40 | +*.tsbuildinfo | |
| 41 | +next-env.d.ts | |
added
apps/web/eslint.config.mjs
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +import { defineConfig, globalIgnores } from "eslint/config"; | |
| 2 | +import nextVitals from "eslint-config-next/core-web-vitals"; | |
| 3 | +import nextTs from "eslint-config-next/typescript"; | |
| 4 | + | |
| 5 | +const eslintConfig = defineConfig([ | |
| 6 | + ...nextVitals, | |
| 7 | + ...nextTs, | |
| 8 | + // Override default ignores of eslint-config-next. | |
| 9 | + globalIgnores([ | |
| 10 | + // Default ignores of eslint-config-next: | |
| 11 | + ".next/**", | |
| 12 | + "out/**", | |
| 13 | + "build/**", | |
| 14 | + "next-env.d.ts", | |
| 15 | + ]), | |
| 16 | +]); | |
| 17 | + | |
| 18 | +export default eslintConfig; | |
added
apps/web/next.config.ts
+31 −0
@@ -0,0 +1,31 @@ | ||
| 1 | +import type { NextConfig } from 'next'; | |
| 2 | + | |
| 3 | +const nextConfig: NextConfig = { | |
| 4 | + reactStrictMode: true, | |
| 5 | + poweredByHeader: false, | |
| 6 | + // Workspace packages are consumed as TypeScript sources. | |
| 7 | + transpilePackages: ['@rareindex/shared', '@rareindex/database', '@rareindex/taxonomy', '@rareindex/connectors'], | |
| 8 | + serverExternalPackages: ['postgres', 'pino', 'cheerio'], | |
| 9 | + images: { | |
| 10 | + remotePatterns: [{ protocol: 'https', hostname: '**' }], | |
| 11 | + formats: ['image/avif', 'image/webp'], | |
| 12 | + }, | |
| 13 | + experimental: { | |
| 14 | + optimizePackageImports: ['lucide-react'], | |
| 15 | + }, | |
| 16 | + async headers() { | |
| 17 | + return [ | |
| 18 | + { | |
| 19 | + source: '/(.*)', | |
| 20 | + headers: [ | |
| 21 | + { key: 'X-Content-Type-Options', value: 'nosniff' }, | |
| 22 | + { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' }, | |
| 23 | + { key: 'X-Frame-Options', value: 'SAMEORIGIN' }, | |
| 24 | + { key: 'Permissions-Policy', value: 'camera=(self), microphone=(), geolocation=()' }, | |
| 25 | + ], | |
| 26 | + }, | |
| 27 | + ]; | |
| 28 | + }, | |
| 29 | +}; | |
| 30 | + | |
| 31 | +export default nextConfig; | |
added
apps/web/package.json
+37 −0
@@ -0,0 +1,37 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@rareindex/web", | |
| 3 | + "version": "0.1.0", | |
| 4 | + "private": true, | |
| 5 | + "scripts": { | |
| 6 | + "dev": "next dev -p 3000", | |
| 7 | + "build": "next build", | |
| 8 | + "start": "next start", | |
| 9 | + "lint": "eslint", | |
| 10 | + "typecheck": "tsc -p tsconfig.json --noEmit", | |
| 11 | + "test": "vitest run --passWithNoTests" | |
| 12 | + }, | |
| 13 | + "dependencies": { | |
| 14 | + "@rareindex/connectors": "workspace:*", | |
| 15 | + "@rareindex/database": "workspace:*", | |
| 16 | + "@rareindex/shared": "workspace:*", | |
| 17 | + "@rareindex/taxonomy": "workspace:*", | |
| 18 | + "@tanstack/react-query": "^5.90.0", | |
| 19 | + "lucide-react": "^1.0.0", | |
| 20 | + "next": "16.3.4", | |
| 21 | + "react": "19.2.8", | |
| 22 | + "react-dom": "19.2.8", | |
| 23 | + "server-only": "^0.0.1", | |
| 24 | + "zod": "^4.0.0" | |
| 25 | + }, | |
| 26 | + "devDependencies": { | |
| 27 | + "@tailwindcss/postcss": "^4", | |
| 28 | + "@types/node": "^24.0.0", | |
| 29 | + "@types/react": "^19", | |
| 30 | + "@types/react-dom": "^19", | |
| 31 | + "eslint": "^9", | |
| 32 | + "eslint-config-next": "16.3.4", | |
| 33 | + "tailwindcss": "^4", | |
| 34 | + "typescript": "^5.9.3", | |
| 35 | + "vitest": "^3.2.0" | |
| 36 | + } | |
| 37 | +} | |
added
apps/web/postcss.config.mjs
+7 −0
@@ -0,0 +1,7 @@ | ||
| 1 | +const config = { | |
| 2 | + plugins: { | |
| 3 | + "@tailwindcss/postcss": {}, | |
| 4 | + }, | |
| 5 | +}; | |
| 6 | + | |
| 7 | +export default config; | |
added
apps/web/src/app/error.tsx
+17 −0
@@ -0,0 +1,17 @@ | ||
| 1 | +'use client'; | |
| 2 | + | |
| 3 | +import { EmptyState } from '@/components/ui/primitives'; | |
| 4 | + | |
| 5 | +export default function ErrorPage({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) { | |
| 6 | + return ( | |
| 7 | + <EmptyState | |
| 8 | + title="Something went wrong" | |
| 9 | + description={error.digest ? `Reference ${error.digest}` : 'An unexpected error occurred while rendering this page.'} | |
| 10 | + action={ | |
| 11 | + <button type="button" onClick={reset} className="rounded-md border border-border px-3 py-1.5 text-xs font-medium hover:bg-inset"> | |
| 12 | + Try again | |
| 13 | + </button> | |
| 14 | + } | |
| 15 | + /> | |
| 16 | + ); | |
| 17 | +} | |
added
apps/web/src/app/favicon.ico
+0 −0
Binary file not shown.
added
apps/web/src/app/globals.css
+211 −0
@@ -0,0 +1,211 @@ | ||
| 1 | +@import "tailwindcss"; | |
| 2 | + | |
| 3 | +/* | |
| 4 | + RareIndex design language (§160–§161): institutional market terminal × modern luxury house. | |
| 5 | + Neutral base, accents reserved for gains / losses / index identity / rarity / alerts. | |
| 6 | + Light and dark are first-class; `data-theme` on <html> overrides system preference. | |
| 7 | +*/ | |
| 8 | + | |
| 9 | +:root { | |
| 10 | + --ri-bg: #fafaf9; | |
| 11 | + --ri-bg-elevated: #ffffff; | |
| 12 | + --ri-bg-sunken: #f4f4f3; | |
| 13 | + --ri-bg-inset: #ececea; | |
| 14 | + --ri-fg: #0b0b0c; | |
| 15 | + --ri-fg-muted: #55555b; | |
| 16 | + --ri-fg-subtle: #8a8a91; | |
| 17 | + --ri-border: #e4e4e2; | |
| 18 | + --ri-border-strong: #c9c9c5; | |
| 19 | + --ri-accent: #0b0b0c; | |
| 20 | + --ri-accent-fg: #ffffff; | |
| 21 | + --ri-gain: #0f8a4a; | |
| 22 | + --ri-gain-bg: #e6f5ec; | |
| 23 | + --ri-loss: #c8262c; | |
| 24 | + --ri-loss-bg: #fbe9ea; | |
| 25 | + --ri-flat: #6b6b72; | |
| 26 | + --ri-index: #1f3a8a; | |
| 27 | + --ri-index-bg: #e8edfa; | |
| 28 | + --ri-rarity: #7c3aed; | |
| 29 | + --ri-rarity-bg: #f0e9fe; | |
| 30 | + --ri-alert: #b45309; | |
| 31 | + --ri-alert-bg: #fdf1e3; | |
| 32 | + --ri-gold: #a16207; | |
| 33 | + --ri-ring: rgba(11, 11, 12, 0.18); | |
| 34 | + --ri-shadow: 0 1px 2px rgba(0, 0, 0, 0.05), 0 1px 1px rgba(0, 0, 0, 0.03); | |
| 35 | + --ri-shadow-lg: 0 10px 30px -12px rgba(0, 0, 0, 0.18); | |
| 36 | + --ri-radius: 6px; | |
| 37 | + --ri-radius-sm: 4px; | |
| 38 | + --ri-radius-lg: 10px; | |
| 39 | + color-scheme: light; | |
| 40 | +} | |
| 41 | + | |
| 42 | +html[data-theme="dark"] { | |
| 43 | + --ri-bg: #0b0c0e; | |
| 44 | + --ri-bg-elevated: #121316; | |
| 45 | + --ri-bg-sunken: #08090a; | |
| 46 | + --ri-bg-inset: #1a1b1f; | |
| 47 | + --ri-fg: #f2f2f0; | |
| 48 | + --ri-fg-muted: #a8a8ad; | |
| 49 | + --ri-fg-subtle: #6f6f76; | |
| 50 | + --ri-border: #24252a; | |
| 51 | + --ri-border-strong: #3a3b42; | |
| 52 | + --ri-accent: #f2f2f0; | |
| 53 | + --ri-accent-fg: #0b0c0e; | |
| 54 | + --ri-gain: #34c47c; | |
| 55 | + --ri-gain-bg: rgba(52, 196, 124, 0.12); | |
| 56 | + --ri-loss: #ef5a5f; | |
| 57 | + --ri-loss-bg: rgba(239, 90, 95, 0.12); | |
| 58 | + --ri-flat: #8b8b93; | |
| 59 | + --ri-index: #7c9cf5; | |
| 60 | + --ri-index-bg: rgba(124, 156, 245, 0.12); | |
| 61 | + --ri-rarity: #a78bfa; | |
| 62 | + --ri-rarity-bg: rgba(167, 139, 250, 0.12); | |
| 63 | + --ri-alert: #f0a34c; | |
| 64 | + --ri-alert-bg: rgba(240, 163, 76, 0.12); | |
| 65 | + --ri-gold: #d4a53a; | |
| 66 | + --ri-ring: rgba(242, 242, 240, 0.22); | |
| 67 | + --ri-shadow: 0 1px 2px rgba(0, 0, 0, 0.4); | |
| 68 | + --ri-shadow-lg: 0 14px 40px -14px rgba(0, 0, 0, 0.7); | |
| 69 | + color-scheme: dark; | |
| 70 | +} | |
| 71 | + | |
| 72 | +@media (prefers-color-scheme: dark) { | |
| 73 | + html:not([data-theme="light"]) { | |
| 74 | + --ri-bg: #0b0c0e; | |
| 75 | + --ri-bg-elevated: #121316; | |
| 76 | + --ri-bg-sunken: #08090a; | |
| 77 | + --ri-bg-inset: #1a1b1f; | |
| 78 | + --ri-fg: #f2f2f0; | |
| 79 | + --ri-fg-muted: #a8a8ad; | |
| 80 | + --ri-fg-subtle: #6f6f76; | |
| 81 | + --ri-border: #24252a; | |
| 82 | + --ri-border-strong: #3a3b42; | |
| 83 | + --ri-accent: #f2f2f0; | |
| 84 | + --ri-accent-fg: #0b0c0e; | |
| 85 | + --ri-gain: #34c47c; | |
| 86 | + --ri-gain-bg: rgba(52, 196, 124, 0.12); | |
| 87 | + --ri-loss: #ef5a5f; | |
| 88 | + --ri-loss-bg: rgba(239, 90, 95, 0.12); | |
| 89 | + --ri-flat: #8b8b93; | |
| 90 | + --ri-index: #7c9cf5; | |
| 91 | + --ri-index-bg: rgba(124, 156, 245, 0.12); | |
| 92 | + --ri-rarity: #a78bfa; | |
| 93 | + --ri-rarity-bg: rgba(167, 139, 250, 0.12); | |
| 94 | + --ri-alert: #f0a34c; | |
| 95 | + --ri-alert-bg: rgba(240, 163, 76, 0.12); | |
| 96 | + --ri-gold: #d4a53a; | |
| 97 | + --ri-ring: rgba(242, 242, 240, 0.22); | |
| 98 | + --ri-shadow: 0 1px 2px rgba(0, 0, 0, 0.4); | |
| 99 | + --ri-shadow-lg: 0 14px 40px -14px rgba(0, 0, 0, 0.7); | |
| 100 | + color-scheme: dark; | |
| 101 | + } | |
| 102 | +} | |
| 103 | + | |
| 104 | +@theme inline { | |
| 105 | + --color-bg: var(--ri-bg); | |
| 106 | + --color-elevated: var(--ri-bg-elevated); | |
| 107 | + --color-sunken: var(--ri-bg-sunken); | |
| 108 | + --color-inset: var(--ri-bg-inset); | |
| 109 | + --color-fg: var(--ri-fg); | |
| 110 | + --color-muted: var(--ri-fg-muted); | |
| 111 | + --color-subtle: var(--ri-fg-subtle); | |
| 112 | + --color-border: var(--ri-border); | |
| 113 | + --color-border-strong: var(--ri-border-strong); | |
| 114 | + --color-accent: var(--ri-accent); | |
| 115 | + --color-accent-fg: var(--ri-accent-fg); | |
| 116 | + --color-gain: var(--ri-gain); | |
| 117 | + --color-gain-bg: var(--ri-gain-bg); | |
| 118 | + --color-loss: var(--ri-loss); | |
| 119 | + --color-loss-bg: var(--ri-loss-bg); | |
| 120 | + --color-flat: var(--ri-flat); | |
| 121 | + --color-index: var(--ri-index); | |
| 122 | + --color-index-bg: var(--ri-index-bg); | |
| 123 | + --color-rarity: var(--ri-rarity); | |
| 124 | + --color-rarity-bg: var(--ri-rarity-bg); | |
| 125 | + --color-alert: var(--ri-alert); | |
| 126 | + --color-alert-bg: var(--ri-alert-bg); | |
| 127 | + --color-gold: var(--ri-gold); | |
| 128 | + --font-sans: var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif; | |
| 129 | + --font-mono: var(--font-geist-mono), ui-monospace, "SF Mono", Menlo, monospace; | |
| 130 | + --radius-sm: var(--ri-radius-sm); | |
| 131 | + --radius-md: var(--ri-radius); | |
| 132 | + --radius-lg: var(--ri-radius-lg); | |
| 133 | + --shadow-card: var(--ri-shadow); | |
| 134 | + --shadow-pop: var(--ri-shadow-lg); | |
| 135 | +} | |
| 136 | + | |
| 137 | +@layer base { | |
| 138 | + html { | |
| 139 | + height: 100%; | |
| 140 | + -webkit-text-size-adjust: 100%; | |
| 141 | + scroll-behavior: smooth; | |
| 142 | + } | |
| 143 | + body { | |
| 144 | + min-height: 100%; | |
| 145 | + background: var(--ri-bg); | |
| 146 | + color: var(--ri-fg); | |
| 147 | + font-family: var(--font-sans); | |
| 148 | + font-feature-settings: "cv11", "ss01", "tnum"; | |
| 149 | + text-rendering: optimizeLegibility; | |
| 150 | + -webkit-font-smoothing: antialiased; | |
| 151 | + } | |
| 152 | + ::selection { | |
| 153 | + background: var(--ri-index-bg); | |
| 154 | + } | |
| 155 | + :focus-visible { | |
| 156 | + outline: 2px solid var(--ri-ring); | |
| 157 | + outline-offset: 2px; | |
| 158 | + } | |
| 159 | + input, | |
| 160 | + select, | |
| 161 | + textarea { | |
| 162 | + font-size: 16px; /* prevents iOS zoom */ | |
| 163 | + } | |
| 164 | + @media (min-width: 768px) { | |
| 165 | + input, | |
| 166 | + select, | |
| 167 | + textarea { | |
| 168 | + font-size: 14px; | |
| 169 | + } | |
| 170 | + } | |
| 171 | + h1, h2, h3, h4 { | |
| 172 | + letter-spacing: -0.015em; | |
| 173 | + } | |
| 174 | +} | |
| 175 | + | |
| 176 | +@utility num { | |
| 177 | + font-variant-numeric: tabular-nums lining-nums; | |
| 178 | + font-feature-settings: "tnum", "lnum"; | |
| 179 | +} | |
| 180 | +@utility mono-num { | |
| 181 | + font-family: var(--font-mono); | |
| 182 | + font-variant-numeric: tabular-nums; | |
| 183 | +} | |
| 184 | +@utility hairline { | |
| 185 | + border-color: var(--ri-border); | |
| 186 | +} | |
| 187 | +@utility card { | |
| 188 | + background: var(--ri-bg-elevated); | |
| 189 | + border: 1px solid var(--ri-border); | |
| 190 | + border-radius: var(--ri-radius); | |
| 191 | + box-shadow: var(--ri-shadow); | |
| 192 | +} | |
| 193 | +@utility scrollbar-none { | |
| 194 | + scrollbar-width: none; | |
| 195 | + &::-webkit-scrollbar { display: none; } | |
| 196 | +} | |
| 197 | +@utility safe-bottom { | |
| 198 | + padding-bottom: max(env(safe-area-inset-bottom), 0.75rem); | |
| 199 | +} | |
| 200 | + | |
| 201 | +@keyframes ri-tape { | |
| 202 | + from { transform: translateX(0); } | |
| 203 | + to { transform: translateX(-50%); } | |
| 204 | +} | |
| 205 | +.tape-track { | |
| 206 | + animation: ri-tape 60s linear infinite; | |
| 207 | +} | |
| 208 | +.tape-track:hover { animation-play-state: paused; } | |
| 209 | +@media (prefers-reduced-motion: reduce) { | |
| 210 | + .tape-track { animation: none; } | |
| 211 | +} | |
added
apps/web/src/app/healthz/route.ts
+14 −0
@@ -0,0 +1,14 @@ | ||
| 1 | +import { NextResponse } from 'next/server'; | |
| 2 | +import { getSql } from '@rareindex/database'; | |
| 3 | + | |
| 4 | +export const dynamic = 'force-dynamic'; | |
| 5 | + | |
| 6 | +export async function GET() { | |
| 7 | + try { | |
| 8 | + const sql = getSql(); | |
| 9 | + const [row] = await sql`select now() as now`; | |
| 10 | + return NextResponse.json({ ok: true, service: 'rareindex-web', db: Boolean(row), time: new Date().toISOString() }); | |
| 11 | + } catch (err) { | |
| 12 | + return NextResponse.json({ ok: false, service: 'rareindex-web', error: err instanceof Error ? err.message : String(err) }, { status: 503 }); | |
| 13 | + } | |
| 14 | +} | |
added
apps/web/src/app/layout.tsx
+46 −0
@@ -0,0 +1,46 @@ | ||
| 1 | +import type { Metadata, Viewport } from 'next'; | |
| 2 | +import { Geist, Geist_Mono } from 'next/font/google'; | |
| 3 | +import './globals.css'; | |
| 4 | +import { SiteHeader } from '@/components/layout/site-header'; | |
| 5 | +import { SiteFooter } from '@/components/layout/site-footer'; | |
| 6 | +import { THEME_SCRIPT } from '@/components/layout/theme-toggle'; | |
| 7 | + | |
| 8 | +const geistSans = Geist({ variable: '--font-geist-sans', subsets: ['latin'] }); | |
| 9 | +const geistMono = Geist_Mono({ variable: '--font-geist-mono', subsets: ['latin'] }); | |
| 10 | + | |
| 11 | +const SITE_URL = process.env.NEXT_PUBLIC_SITE_URL ?? 'https://www.rareindex.io'; | |
| 12 | + | |
| 13 | +export const metadata: Metadata = { | |
| 14 | + metadataBase: new URL(SITE_URL), | |
| 15 | + title: { default: 'RareIndex — The Global Market for Collectibles', template: '%s · RareIndex' }, | |
| 16 | + description: 'Discover, price, track and analyze collectible assets across the world’s marketplaces and auction houses.', | |
| 17 | + applicationName: 'RareIndex', | |
| 18 | + openGraph: { type: 'website', siteName: 'RareIndex', url: SITE_URL, title: 'RareIndex — The Global Market for Collectibles', description: 'Prices, sales, listings, rarity, liquidity and indices for collectible assets.' }, | |
| 19 | + twitter: { card: 'summary_large_image', title: 'RareIndex', description: 'The global market for collectibles.' }, | |
| 20 | + robots: { index: true, follow: true }, | |
| 21 | +}; | |
| 22 | + | |
| 23 | +export const viewport: Viewport = { | |
| 24 | + width: 'device-width', | |
| 25 | + initialScale: 1, | |
| 26 | + viewportFit: 'cover', | |
| 27 | + themeColor: [ | |
| 28 | + { media: '(prefers-color-scheme: light)', color: '#fafaf9' }, | |
| 29 | + { media: '(prefers-color-scheme: dark)', color: '#0b0c0e' }, | |
| 30 | + ], | |
| 31 | +}; | |
| 32 | + | |
| 33 | +export default function RootLayout({ children }: { children: React.ReactNode }) { | |
| 34 | + return ( | |
| 35 | + <html lang="en" className={`${geistSans.variable} ${geistMono.variable} h-full antialiased`} suppressHydrationWarning> | |
| 36 | + <head> | |
| 37 | + <script dangerouslySetInnerHTML={{ __html: THEME_SCRIPT }} /> | |
| 38 | + </head> | |
| 39 | + <body className="flex min-h-full flex-col"> | |
| 40 | + <SiteHeader /> | |
| 41 | + <main className="mx-auto w-full max-w-[1440px] flex-1 px-4 pb-16 pt-4 sm:px-6">{children}</main> | |
| 42 | + <SiteFooter /> | |
| 43 | + </body> | |
| 44 | + </html> | |
| 45 | + ); | |
| 46 | +} | |
added
apps/web/src/app/not-found.tsx
+16 −0
@@ -0,0 +1,16 @@ | ||
| 1 | +import Link from 'next/link'; | |
| 2 | +import { EmptyState } from '@/components/ui/primitives'; | |
| 3 | + | |
| 4 | +export default function NotFound() { | |
| 5 | + return ( | |
| 6 | + <EmptyState | |
| 7 | + title="Page not found" | |
| 8 | + description="The asset, market or page you requested does not exist or has been merged into another record." | |
| 9 | + action={ | |
| 10 | + <Link href="/" className="rounded-md border border-border px-3 py-1.5 text-xs font-medium hover:bg-inset"> | |
| 11 | + Back to RareIndex | |
| 12 | + </Link> | |
| 13 | + } | |
| 14 | + /> | |
| 15 | + ); | |
| 16 | +} | |
added
apps/web/src/app/page.tsx
+6 −0
@@ -0,0 +1,6 @@ | ||
| 1 | +import { EmptyState } from '@/components/ui/primitives'; | |
| 2 | + | |
| 3 | +// Placeholder — replaced by the homepage module (hero, live tape, discovery grid). | |
| 4 | +export default function HomePage() { | |
| 5 | + return <EmptyState title="RareIndex is initialising" description="The global market for collectibles. Data pipelines are being connected." />; | |
| 6 | +} | |
added
apps/web/src/components/layout/header-search.tsx
+32 −0
@@ -0,0 +1,32 @@ | ||
| 1 | +'use client'; | |
| 2 | + | |
| 3 | +import { useRouter } from 'next/navigation'; | |
| 4 | +import { Search } from 'lucide-react'; | |
| 5 | +import { useState } from 'react'; | |
| 6 | + | |
| 7 | +/** Compact header search; the full search experience lives at /search (owned by the search module). */ | |
| 8 | +export function HeaderSearch() { | |
| 9 | + const router = useRouter(); | |
| 10 | + const [q, setQ] = useState(''); | |
| 11 | + return ( | |
| 12 | + <form | |
| 13 | + role="search" | |
| 14 | + className="relative hidden items-center md:flex" | |
| 15 | + onSubmit={(e) => { | |
| 16 | + e.preventDefault(); | |
| 17 | + const query = q.trim(); | |
| 18 | + if (query) router.push(`/search?q=${encodeURIComponent(query)}`); | |
| 19 | + }} | |
| 20 | + > | |
| 21 | + <Search className="pointer-events-none absolute left-2.5 h-3.5 w-3.5 text-subtle" /> | |
| 22 | + <input | |
| 23 | + type="search" | |
| 24 | + value={q} | |
| 25 | + onChange={(e) => setQ(e.target.value)} | |
| 26 | + placeholder="Search cards, watches, games, sneakers, LEGO…" | |
| 27 | + className="h-8 w-64 rounded-md border border-border bg-sunken pl-8 pr-2 text-[13px] text-fg placeholder:text-subtle focus:w-80 focus:border-border-strong focus:outline-none transition-[width] xl:w-80 xl:focus:w-96" | |
| 28 | + aria-label="Search collectibles" | |
| 29 | + /> | |
| 30 | + </form> | |
| 31 | + ); | |
| 32 | +} | |
added
apps/web/src/components/layout/mobile-nav.tsx
+56 −0
@@ -0,0 +1,56 @@ | ||
| 1 | +'use client'; | |
| 2 | + | |
| 3 | +import Link from 'next/link'; | |
| 4 | +import { useEffect, useState } from 'react'; | |
| 5 | +import { usePathname } from 'next/navigation'; | |
| 6 | +import { Menu, X } from 'lucide-react'; | |
| 7 | +import type { NavItem } from '@/config/nav'; | |
| 8 | + | |
| 9 | +export function MobileNav({ items, groups }: { items: NavItem[]; groups: Array<{ id: NavItem['group']; label: string }> }) { | |
| 10 | + const [open, setOpen] = useState(false); | |
| 11 | + const pathname = usePathname(); | |
| 12 | + useEffect(() => setOpen(false), [pathname]); | |
| 13 | + useEffect(() => { | |
| 14 | + document.body.style.overflow = open ? 'hidden' : ''; | |
| 15 | + return () => { | |
| 16 | + document.body.style.overflow = ''; | |
| 17 | + }; | |
| 18 | + }, [open]); | |
| 19 | + return ( | |
| 20 | + <div className="lg:hidden"> | |
| 21 | + <button type="button" aria-label="Open menu" aria-expanded={open} className="inline-flex h-8 w-8 items-center justify-center rounded-md text-muted hover:bg-inset hover:text-fg" onClick={() => setOpen(true)}> | |
| 22 | + <Menu className="h-5 w-5" /> | |
| 23 | + </button> | |
| 24 | + {open ? ( | |
| 25 | + <div className="fixed inset-0 z-50 flex" role="dialog" aria-modal="true"> | |
| 26 | + <div className="absolute inset-0 bg-black/40" onClick={() => setOpen(false)} /> | |
| 27 | + <div className="relative flex h-[100dvh] w-[86vw] max-w-sm flex-col overflow-y-auto bg-elevated shadow-pop safe-bottom"> | |
| 28 | + <div className="flex h-14 items-center justify-between border-b border-border px-4"> | |
| 29 | + <span className="text-sm font-semibold">Menu</span> | |
| 30 | + <button type="button" aria-label="Close menu" className="inline-flex h-8 w-8 items-center justify-center rounded-md text-muted hover:bg-inset" onClick={() => setOpen(false)}> | |
| 31 | + <X className="h-5 w-5" /> | |
| 32 | + </button> | |
| 33 | + </div> | |
| 34 | + <nav className="flex-1 px-2 py-3"> | |
| 35 | + {groups.map((g) => ( | |
| 36 | + <div key={g.id} className="mb-3"> | |
| 37 | + <p className="px-2 pb-1 text-[10px] font-semibold uppercase tracking-wider text-subtle">{g.label}</p> | |
| 38 | + {items | |
| 39 | + .filter((n) => n.group === g.id) | |
| 40 | + .map((n) => ( | |
| 41 | + <Link key={n.href} href={n.href} className={`block rounded-md px-2 py-2 text-[15px] ${pathname === n.href ? 'bg-inset font-medium text-fg' : 'text-muted'}`}> | |
| 42 | + {n.label} | |
| 43 | + </Link> | |
| 44 | + ))} | |
| 45 | + </div> | |
| 46 | + ))} | |
| 47 | + <Link href="/account" className="mt-2 block rounded-md border border-border px-3 py-2 text-center text-sm font-medium"> | |
| 48 | + Sign in | |
| 49 | + </Link> | |
| 50 | + </nav> | |
| 51 | + </div> | |
| 52 | + </div> | |
| 53 | + ) : null} | |
| 54 | + </div> | |
| 55 | + ); | |
| 56 | +} | |
added
apps/web/src/components/layout/site-footer.tsx
+42 −0
@@ -0,0 +1,42 @@ | ||
| 1 | +import Link from 'next/link'; | |
| 2 | +import { NAV, NAV_GROUPS } from '@/config/nav'; | |
| 3 | +import { Logo } from './site-header'; | |
| 4 | + | |
| 5 | +export function SiteFooter() { | |
| 6 | + return ( | |
| 7 | + <footer className="mt-16 border-t border-border bg-sunken"> | |
| 8 | + <div className="mx-auto max-w-[1440px] px-4 py-10 sm:px-6"> | |
| 9 | + <div className="grid grid-cols-2 gap-8 md:grid-cols-6"> | |
| 10 | + <div className="col-span-2 md:col-span-2"> | |
| 11 | + <Logo /> | |
| 12 | + <p className="mt-3 max-w-xs text-xs leading-relaxed text-muted">The global data layer for collectible assets: prices, sales, listings, rarity, liquidity and indices across marketplaces and auction houses.</p> | |
| 13 | + </div> | |
| 14 | + {NAV_GROUPS.filter((g) => g.id !== 'discover').map((g) => ( | |
| 15 | + <div key={g.id}> | |
| 16 | + <p className="mb-2 text-[10px] font-semibold uppercase tracking-wider text-subtle">{g.label}</p> | |
| 17 | + <ul className="space-y-1"> | |
| 18 | + {NAV.filter((n) => n.group === g.id).map((n) => ( | |
| 19 | + <li key={n.href}> | |
| 20 | + <Link href={n.href} className="text-xs text-muted hover:text-fg"> | |
| 21 | + {n.label} | |
| 22 | + </Link> | |
| 23 | + </li> | |
| 24 | + ))} | |
| 25 | + </ul> | |
| 26 | + </div> | |
| 27 | + ))} | |
| 28 | + </div> | |
| 29 | + <div className="mt-8 border-t border-border pt-5 text-[11px] leading-relaxed text-subtle"> | |
| 30 | + <p> | |
| 31 | + RareIndex is an information platform. Valuations are estimates derived from observed public data and carry a confidence level; listing prices are not confirmed transactions; past performance does not guarantee future results. RareIndex does not authenticate items. Third-party names and marks belong to their owners; data is attributed to its source.{' '} | |
| 32 | + <Link href="/about#disclaimers" className="underline hover:text-fg"> | |
| 33 | + Read the full disclaimers | |
| 34 | + </Link> | |
| 35 | + . | |
| 36 | + </p> | |
| 37 | + <p className="mt-2">© {new Date().getFullYear()} RareIndex.io</p> | |
| 38 | + </div> | |
| 39 | + </div> | |
| 40 | + </footer> | |
| 41 | + ); | |
| 42 | +} | |
added
apps/web/src/components/layout/site-header.tsx
+60 −0
@@ -0,0 +1,60 @@ | ||
| 1 | +import Link from 'next/link'; | |
| 2 | +import { NAV, NAV_GROUPS, PRIMARY_NAV } from '@/config/nav'; | |
| 3 | +import { ThemeToggle } from './theme-toggle'; | |
| 4 | +import { MobileNav } from './mobile-nav'; | |
| 5 | +import { HeaderSearch } from './header-search'; | |
| 6 | + | |
| 7 | +export function Logo({ className }: { className?: string }) { | |
| 8 | + return ( | |
| 9 | + <Link href="/" className={`flex items-center gap-2 ${className ?? ''}`} aria-label="RareIndex home"> | |
| 10 | + <span className="inline-flex h-6 w-6 items-center justify-center rounded-sm bg-accent text-[11px] font-bold text-accent-fg">R</span> | |
| 11 | + <span className="text-[15px] font-semibold tracking-tight text-fg"> | |
| 12 | + Rare<span className="text-muted">Index</span> | |
| 13 | + </span> | |
| 14 | + </Link> | |
| 15 | + ); | |
| 16 | +} | |
| 17 | + | |
| 18 | +export function SiteHeader() { | |
| 19 | + return ( | |
| 20 | + <header className="sticky top-0 z-40 border-b border-border bg-bg/85 backdrop-blur supports-[backdrop-filter]:bg-bg/70"> | |
| 21 | + <div className="mx-auto flex h-14 max-w-[1440px] items-center gap-3 px-4 sm:px-6"> | |
| 22 | + <MobileNav items={NAV} groups={NAV_GROUPS} /> | |
| 23 | + <Logo /> | |
| 24 | + <nav className="ml-4 hidden items-center gap-1 lg:flex" aria-label="Primary"> | |
| 25 | + {PRIMARY_NAV.map((n) => ( | |
| 26 | + <Link key={n.href} href={n.href} className="rounded-md px-2.5 py-1.5 text-[13px] font-medium text-muted hover:bg-inset hover:text-fg"> | |
| 27 | + {n.label} | |
| 28 | + </Link> | |
| 29 | + ))} | |
| 30 | + <details className="group relative"> | |
| 31 | + <summary className="cursor-pointer list-none rounded-md px-2.5 py-1.5 text-[13px] font-medium text-muted hover:bg-inset hover:text-fg [&::-webkit-details-marker]:hidden">More</summary> | |
| 32 | + <div className="absolute left-0 top-full z-50 mt-1 grid w-[640px] grid-cols-3 gap-4 rounded-lg border border-border bg-elevated p-4 shadow-pop"> | |
| 33 | + {NAV_GROUPS.map((g) => ( | |
| 34 | + <div key={g.id}> | |
| 35 | + <p className="mb-1.5 text-[10px] font-semibold uppercase tracking-wider text-subtle">{g.label}</p> | |
| 36 | + <ul className="space-y-0.5"> | |
| 37 | + {NAV.filter((n) => n.group === g.id).map((n) => ( | |
| 38 | + <li key={n.href}> | |
| 39 | + <Link href={n.href} className="block rounded-sm px-1.5 py-1 text-[13px] text-muted hover:bg-inset hover:text-fg"> | |
| 40 | + {n.label} | |
| 41 | + </Link> | |
| 42 | + </li> | |
| 43 | + ))} | |
| 44 | + </ul> | |
| 45 | + </div> | |
| 46 | + ))} | |
| 47 | + </div> | |
| 48 | + </details> | |
| 49 | + </nav> | |
| 50 | + <div className="ml-auto flex items-center gap-1.5"> | |
| 51 | + <HeaderSearch /> | |
| 52 | + <ThemeToggle /> | |
| 53 | + <Link href="/account" className="hidden rounded-md border border-border px-2.5 py-1.5 text-[13px] font-medium text-fg hover:bg-inset sm:inline-flex"> | |
| 54 | + Sign in | |
| 55 | + </Link> | |
| 56 | + </div> | |
| 57 | + </div> | |
| 58 | + </header> | |
| 59 | + ); | |
| 60 | +} | |
added
apps/web/src/components/layout/theme-toggle.tsx
+41 −0
@@ -0,0 +1,41 @@ | ||
| 1 | +'use client'; | |
| 2 | + | |
| 3 | +import { useEffect, useState } from 'react'; | |
| 4 | +import { Moon, Sun } from 'lucide-react'; | |
| 5 | + | |
| 6 | +type Theme = 'light' | 'dark'; | |
| 7 | + | |
| 8 | +function applyTheme(t: Theme) { | |
| 9 | + document.documentElement.setAttribute('data-theme', t); | |
| 10 | + try { | |
| 11 | + localStorage.setItem('ri-theme', t); | |
| 12 | + } catch { | |
| 13 | + /* ignore */ | |
| 14 | + } | |
| 15 | +} | |
| 16 | + | |
| 17 | +export function ThemeToggle({ className }: { className?: string }) { | |
| 18 | + const [theme, setTheme] = useState<Theme>('light'); | |
| 19 | + useEffect(() => { | |
| 20 | + const attr = document.documentElement.getAttribute('data-theme') as Theme | null; | |
| 21 | + if (attr) setTheme(attr); | |
| 22 | + else setTheme(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'); | |
| 23 | + }, []); | |
| 24 | + return ( | |
| 25 | + <button | |
| 26 | + type="button" | |
| 27 | + aria-label={theme === 'dark' ? 'Switch to light mode' : 'Switch to dark mode'} | |
| 28 | + className={className ?? 'inline-flex h-8 w-8 items-center justify-center rounded-md text-muted hover:bg-inset hover:text-fg'} | |
| 29 | + onClick={() => { | |
| 30 | + const next: Theme = theme === 'dark' ? 'light' : 'dark'; | |
| 31 | + setTheme(next); | |
| 32 | + applyTheme(next); | |
| 33 | + }} | |
| 34 | + > | |
| 35 | + {theme === 'dark' ? <Sun className="h-4 w-4" /> : <Moon className="h-4 w-4" />} | |
| 36 | + </button> | |
| 37 | + ); | |
| 38 | +} | |
| 39 | + | |
| 40 | +/** Inline script: apply the stored theme before paint to avoid flashes. */ | |
| 41 | +export const THEME_SCRIPT = `(function(){try{var t=localStorage.getItem('ri-theme');if(t==='dark'||t==='light'){document.documentElement.setAttribute('data-theme',t);}}catch(e){}})();`; | |
added
apps/web/src/components/ui/primitives.tsx
+91 −0
@@ -0,0 +1,91 @@ | ||
| 1 | +import Link from 'next/link'; | |
| 2 | +import type { ReactNode } from 'react'; | |
| 3 | +import { cn, deltaClass, fmtPct } from '@/lib/format'; | |
| 4 | + | |
| 5 | +/** Minimal, dense UI primitives. Keep them boring; the data is the design. */ | |
| 6 | + | |
| 7 | +export function Card({ children, className, as: Tag = 'section' }: { children: ReactNode; className?: string; as?: 'section' | 'div' | 'article' }) { | |
| 8 | + return <Tag className={cn('card', className)}>{children}</Tag>; | |
| 9 | +} | |
| 10 | + | |
| 11 | +export function CardHeader({ title, subtitle, action, className }: { title: ReactNode; subtitle?: ReactNode; action?: ReactNode; className?: string }) { | |
| 12 | + return ( | |
| 13 | + <header className={cn('flex items-start justify-between gap-3 border-b border-border px-4 py-3', className)}> | |
| 14 | + <div className="min-w-0"> | |
| 15 | + <h2 className="text-sm font-semibold tracking-tight text-fg">{title}</h2> | |
| 16 | + {subtitle ? <p className="mt-0.5 text-xs text-muted">{subtitle}</p> : null} | |
| 17 | + </div> | |
| 18 | + {action ? <div className="shrink-0 text-xs">{action}</div> : null} | |
| 19 | + </header> | |
| 20 | + ); | |
| 21 | +} | |
| 22 | + | |
| 23 | +export function Delta({ value, digits = 2, className }: { value: number | null | undefined; digits?: number; className?: string }) { | |
| 24 | + return <span className={cn('num font-medium', deltaClass(value), className)}>{fmtPct(value, digits)}</span>; | |
| 25 | +} | |
| 26 | + | |
| 27 | +export function Badge({ children, tone = 'neutral', className }: { children: ReactNode; tone?: 'neutral' | 'gain' | 'loss' | 'index' | 'rarity' | 'alert' | 'gold'; className?: string }) { | |
| 28 | + const tones: Record<string, string> = { | |
| 29 | + neutral: 'bg-inset text-muted', | |
| 30 | + gain: 'bg-gain-bg text-gain', | |
| 31 | + loss: 'bg-loss-bg text-loss', | |
| 32 | + index: 'bg-index-bg text-index', | |
| 33 | + rarity: 'bg-rarity-bg text-rarity', | |
| 34 | + alert: 'bg-alert-bg text-alert', | |
| 35 | + gold: 'bg-alert-bg text-gold', | |
| 36 | + }; | |
| 37 | + return <span className={cn('inline-flex items-center rounded-sm px-1.5 py-0.5 text-[11px] font-medium leading-4 tracking-wide', tones[tone], className)}>{children}</span>; | |
| 38 | +} | |
| 39 | + | |
| 40 | +export function Stat({ label, value, sub, className }: { label: ReactNode; value: ReactNode; sub?: ReactNode; className?: string }) { | |
| 41 | + return ( | |
| 42 | + <div className={cn('flex flex-col gap-0.5', className)}> | |
| 43 | + <span className="text-[11px] font-medium uppercase tracking-wider text-subtle">{label}</span> | |
| 44 | + <span className="num text-lg font-semibold leading-tight text-fg">{value}</span> | |
| 45 | + {sub ? <span className="text-xs text-muted">{sub}</span> : null} | |
| 46 | + </div> | |
| 47 | + ); | |
| 48 | +} | |
| 49 | + | |
| 50 | +export function EmptyState({ title, description, action, className }: { title: ReactNode; description?: ReactNode; action?: ReactNode; className?: string }) { | |
| 51 | + return ( | |
| 52 | + <div className={cn('flex flex-col items-center justify-center gap-2 px-6 py-12 text-center', className)}> | |
| 53 | + <p className="text-sm font-medium text-fg">{title}</p> | |
| 54 | + {description ? <p className="max-w-md text-xs leading-relaxed text-muted">{description}</p> : null} | |
| 55 | + {action ? <div className="mt-2">{action}</div> : null} | |
| 56 | + </div> | |
| 57 | + ); | |
| 58 | +} | |
| 59 | + | |
| 60 | +/** Honest placeholder for metrics without enough evidence (§191–§192). */ | |
| 61 | +export function Unavailable({ reason = 'Data unavailable', className }: { reason?: string; className?: string }) { | |
| 62 | + return <span className={cn('text-subtle', className)} title={reason}>—</span>; | |
| 63 | +} | |
| 64 | + | |
| 65 | +export function SectionTitle({ children, href, hrefLabel = 'View all', className }: { children: ReactNode; href?: string; hrefLabel?: string; className?: string }) { | |
| 66 | + return ( | |
| 67 | + <div className={cn('mb-3 flex items-baseline justify-between gap-3', className)}> | |
| 68 | + <h2 className="text-base font-semibold tracking-tight text-fg">{children}</h2> | |
| 69 | + {href ? ( | |
| 70 | + <Link href={href} className="text-xs font-medium text-muted hover:text-fg"> | |
| 71 | + {hrefLabel} → | |
| 72 | + </Link> | |
| 73 | + ) : null} | |
| 74 | + </div> | |
| 75 | + ); | |
| 76 | +} | |
| 77 | + | |
| 78 | +export function Skeleton({ className }: { className?: string }) { | |
| 79 | + return <div className={cn('animate-pulse rounded-sm bg-inset', className)} aria-hidden />; | |
| 80 | +} | |
| 81 | + | |
| 82 | +export function Table({ children, className, dense = true }: { children: ReactNode; className?: string; dense?: boolean }) { | |
| 83 | + return ( | |
| 84 | + <div className={cn('w-full overflow-x-auto scrollbar-none', className)}> | |
| 85 | + <table className={cn('w-full border-collapse text-left', dense ? 'text-[13px]' : 'text-sm')}>{children}</table> | |
| 86 | + </div> | |
| 87 | + ); | |
| 88 | +} | |
| 89 | +export const th = 'sticky top-0 z-[1] whitespace-nowrap border-b border-border bg-elevated px-3 py-2 text-[11px] font-medium uppercase tracking-wider text-subtle'; | |
| 90 | +export const td = 'whitespace-nowrap border-b border-border px-3 py-2 align-middle'; | |
| 91 | +export const tdNum = `${td} num text-right`; | |
added
apps/web/src/config/nav.ts
+47 −0
@@ -0,0 +1,47 @@ | ||
| 1 | +/** | |
| 2 | + * Main navigation (CLAUDE.md §2). Single source of truth for header, mobile menu, footer and sitemap. | |
| 3 | + * Routes are grouped so the header stays legible; every module remains reachable. | |
| 4 | + */ | |
| 5 | +export interface NavItem { | |
| 6 | + label: string; | |
| 7 | + href: string; | |
| 8 | + description: string; | |
| 9 | + group: 'discover' | 'markets' | 'portfolio' | 'tools' | 'company'; | |
| 10 | + /** show in the primary header bar on desktop */ | |
| 11 | + primary?: boolean; | |
| 12 | +} | |
| 13 | + | |
| 14 | +export const NAV: NavItem[] = [ | |
| 15 | + { label: 'Home', href: '/', description: 'The global market for collectibles', group: 'discover' }, | |
| 16 | + { label: 'Explore', href: '/explore', description: 'Browse tracked assets across every category', group: 'discover', primary: true }, | |
| 17 | + { label: 'Markets', href: '/markets', description: 'Category markets, movers and volume', group: 'markets', primary: true }, | |
| 18 | + { label: 'Categories', href: '/categories', description: 'The RareIndex taxonomy', group: 'discover' }, | |
| 19 | + { label: 'RareIndex', href: '/rareindex', description: 'RARE and its subindices', group: 'markets', primary: true }, | |
| 20 | + { label: 'Trending', href: '/trending', description: 'What collectors are moving into', group: 'markets' }, | |
| 21 | + { label: 'Sales', href: '/sales', description: 'Latest observed transactions', group: 'markets', primary: true }, | |
| 22 | + { label: 'Listings', href: '/listings', description: 'Live asks across marketplaces', group: 'markets' }, | |
| 23 | + { label: 'Auctions', href: '/auctions', description: 'Lots, results and auction houses', group: 'markets' }, | |
| 24 | + { label: 'Price History', href: '/price-history', description: 'Historical series for any asset', group: 'tools' }, | |
| 25 | + { label: 'Collections', href: '/collections', description: 'Track your portfolio', group: 'portfolio', primary: true }, | |
| 26 | + { label: 'Watchlist', href: '/watchlist', description: 'Assets, sets and markets you follow', group: 'portfolio' }, | |
| 27 | + { label: 'Compare', href: '/compare', description: 'Compare assets and categories side by side', group: 'tools' }, | |
| 28 | + { label: 'Scanner', href: '/scanner', description: 'Identify and price from a photo or URL', group: 'tools', primary: true }, | |
| 29 | + { label: 'AI Research', href: '/research', description: 'Ask questions over structured market data', group: 'tools' }, | |
| 30 | + { label: 'Market Map', href: '/market-map', description: 'Heatmap of category performance', group: 'markets' }, | |
| 31 | + { label: 'Grading', href: '/grading', description: 'Graders, populations and premiums', group: 'tools' }, | |
| 32 | + { label: 'Auction Calendar', href: '/auctions/calendar', description: 'Upcoming auctions worldwide', group: 'markets' }, | |
| 33 | + { label: 'News', href: '/news', description: 'Market news and record sales', group: 'discover' }, | |
| 34 | + { label: 'Data', href: '/data', description: 'Methodology, coverage and exports', group: 'company' }, | |
| 35 | + { label: 'API', href: '/api-docs', description: 'Programmatic access to RareIndex data', group: 'company' }, | |
| 36 | + { label: 'About', href: '/about', description: 'Mission, disclaimers and contact', group: 'company' }, | |
| 37 | +]; | |
| 38 | + | |
| 39 | +export const NAV_GROUPS: Array<{ id: NavItem['group']; label: string }> = [ | |
| 40 | + { id: 'discover', label: 'Discover' }, | |
| 41 | + { id: 'markets', label: 'Markets' }, | |
| 42 | + { id: 'portfolio', label: 'Portfolio' }, | |
| 43 | + { id: 'tools', label: 'Tools' }, | |
| 44 | + { id: 'company', label: 'Company' }, | |
| 45 | +]; | |
| 46 | + | |
| 47 | +export const PRIMARY_NAV = NAV.filter((n) => n.primary); | |
added
apps/web/src/lib/db.ts
+6 −0
@@ -0,0 +1,6 @@ | ||
| 1 | +import 'server-only'; | |
| 2 | +import { getDb } from '@rareindex/database'; | |
| 3 | + | |
| 4 | +/** Server-side database handle for server components, route handlers and server actions. */ | |
| 5 | +export const db = () => getDb(); | |
| 6 | +export * from '@rareindex/database'; | |
added
apps/web/src/lib/format.ts
+81 −0
@@ -0,0 +1,81 @@ | ||
| 1 | +import type { CurrencyCode } from '@rareindex/shared'; | |
| 2 | + | |
| 3 | +/** Display formatting shared by server and client components (no Node-only imports). */ | |
| 4 | + | |
| 5 | +export function fmtMoney(amount: number | null | undefined, currency: CurrencyCode | string = 'USD', opts: { compact?: boolean; digits?: number } = {}): string { | |
| 6 | + if (amount === null || amount === undefined || !Number.isFinite(amount)) return '—'; | |
| 7 | + const zero = currency === 'JPY' || currency === 'KRW'; | |
| 8 | + const digits = opts.digits ?? (zero ? 0 : Math.abs(amount) >= 1000 ? 0 : 2); | |
| 9 | + try { | |
| 10 | + return new Intl.NumberFormat('en-US', { style: 'currency', currency, notation: opts.compact ? 'compact' : 'standard', maximumFractionDigits: digits, minimumFractionDigits: opts.compact ? 0 : digits }).format(amount); | |
| 11 | + } catch { | |
| 12 | + return `${amount.toFixed(digits)} ${currency}`; | |
| 13 | + } | |
| 14 | +} | |
| 15 | + | |
| 16 | +export function fmtPct(value: number | null | undefined, digits = 2, signed = true): string { | |
| 17 | + if (value === null || value === undefined || !Number.isFinite(value)) return '—'; | |
| 18 | + const sign = signed && value > 0 ? '+' : ''; | |
| 19 | + return `${sign}${(value * 100).toFixed(digits)}%`; | |
| 20 | +} | |
| 21 | + | |
| 22 | +export function fmtNum(value: number | null | undefined, opts: { compact?: boolean; digits?: number } = {}): string { | |
| 23 | + if (value === null || value === undefined || !Number.isFinite(value)) return '—'; | |
| 24 | + return new Intl.NumberFormat('en-US', { notation: opts.compact ? 'compact' : 'standard', maximumFractionDigits: opts.digits ?? (opts.compact ? 1 : 0) }).format(value); | |
| 25 | +} | |
| 26 | + | |
| 27 | +export function fmtDate(d: Date | string | null | undefined, opts: { month?: 'short' | 'long' | 'numeric'; year?: boolean; time?: boolean } = {}): string { | |
| 28 | + if (!d) return '—'; | |
| 29 | + const date = typeof d === 'string' ? new Date(d.length === 10 ? `${d}T00:00:00Z` : d) : d; | |
| 30 | + if (Number.isNaN(date.getTime())) return '—'; | |
| 31 | + return new Intl.DateTimeFormat('en-US', { month: opts.month ?? 'short', day: 'numeric', year: opts.year === false ? undefined : 'numeric', ...(opts.time ? { hour: 'numeric', minute: '2-digit' } : {}), timeZone: 'UTC' }).format(date); | |
| 32 | +} | |
| 33 | + | |
| 34 | +export function fmtRelative(d: Date | string | null | undefined): string { | |
| 35 | + if (!d) return '—'; | |
| 36 | + const date = typeof d === 'string' ? new Date(d) : d; | |
| 37 | + const diff = Date.now() - date.getTime(); | |
| 38 | + const abs = Math.abs(diff); | |
| 39 | + const rtf = new Intl.RelativeTimeFormat('en', { numeric: 'auto' }); | |
| 40 | + const units: Array<[number, Intl.RelativeTimeFormatUnit]> = [ | |
| 41 | + [60_000, 'second'], | |
| 42 | + [3_600_000, 'minute'], | |
| 43 | + [86_400_000, 'hour'], | |
| 44 | + [604_800_000, 'day'], | |
| 45 | + [2_629_800_000, 'week'], | |
| 46 | + [31_557_600_000, 'month'], | |
| 47 | + [Infinity, 'year'], | |
| 48 | + ]; | |
| 49 | + let prevMs = 1; | |
| 50 | + for (const [ms, unit] of units) { | |
| 51 | + if (abs < ms) return rtf.format(Math.round(-diff / prevMs), unit); | |
| 52 | + prevMs = ms; | |
| 53 | + } | |
| 54 | + return fmtDate(date); | |
| 55 | +} | |
| 56 | + | |
| 57 | +export function deltaClass(value: number | null | undefined): string { | |
| 58 | + if (value === null || value === undefined || !Number.isFinite(value) || Math.abs(value) < 0.00005) return 'text-flat'; | |
| 59 | + return value > 0 ? 'text-gain' : 'text-loss'; | |
| 60 | +} | |
| 61 | + | |
| 62 | +export function confidenceLabel(c: number | null | undefined): 'High' | 'Medium' | 'Low' | 'Insufficient' { | |
| 63 | + if (c === null || c === undefined) return 'Insufficient'; | |
| 64 | + if (c >= 0.75) return 'High'; | |
| 65 | + if (c >= 0.5) return 'Medium'; | |
| 66 | + if (c > 0) return 'Low'; | |
| 67 | + return 'Insufficient'; | |
| 68 | +} | |
| 69 | + | |
| 70 | +export function scoreLabel(s: number | null | undefined): string { | |
| 71 | + if (s === null || s === undefined) return 'n/a'; | |
| 72 | + if (s >= 80) return 'Very high'; | |
| 73 | + if (s >= 60) return 'High'; | |
| 74 | + if (s >= 40) return 'Moderate'; | |
| 75 | + if (s >= 20) return 'Low'; | |
| 76 | + return 'Very low'; | |
| 77 | +} | |
| 78 | + | |
| 79 | +export function cn(...parts: Array<string | false | null | undefined>): string { | |
| 80 | + return parts.filter(Boolean).join(' '); | |
| 81 | +} | |
added
apps/web/tsconfig.json
+22 −0
@@ -0,0 +1,22 @@ | ||
| 1 | +{ | |
| 2 | + "compilerOptions": { | |
| 3 | + "target": "ES2022", | |
| 4 | + "lib": ["dom", "dom.iterable", "esnext"], | |
| 5 | + "allowJs": true, | |
| 6 | + "skipLibCheck": true, | |
| 7 | + "strict": true, | |
| 8 | + "noUncheckedIndexedAccess": true, | |
| 9 | + "noEmit": true, | |
| 10 | + "esModuleInterop": true, | |
| 11 | + "module": "esnext", | |
| 12 | + "moduleResolution": "bundler", | |
| 13 | + "resolveJsonModule": true, | |
| 14 | + "isolatedModules": true, | |
| 15 | + "jsx": "react-jsx", | |
| 16 | + "incremental": true, | |
| 17 | + "plugins": [{ "name": "next" }], | |
| 18 | + "paths": { "@/*": ["./src/*"] } | |
| 19 | + }, | |
| 20 | + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", ".next/dev/types/**/*.ts", "**/*.mts"], | |
| 21 | + "exclude": ["node_modules"] | |
| 22 | +} | |
added
apps/web/vitest.config.ts
+7 −0
@@ -0,0 +1,7 @@ | ||
| 1 | +import { defineConfig } from 'vitest/config'; | |
| 2 | +import path from 'node:path'; | |
| 3 | + | |
| 4 | +export default defineConfig({ | |
| 5 | + resolve: { alias: { '@': path.resolve(__dirname, 'src') } }, | |
| 6 | + test: { include: ['src/**/*.test.ts'] }, | |
| 7 | +}); | |
added
connectors/README.md
+18 −0
@@ -0,0 +1,18 @@ | ||
| 1 | +# Source connectors | |
| 2 | + | |
| 3 | +Every source lives in `connectors/<engine>/<source-id>/index.ts` and is declared in `registry.json` (§106). | |
| 4 | +Adding a marketplace requires only (§197): | |
| 5 | + | |
| 6 | +1. **metadata** — an entry in `registry.json` (`module` points to the folder, e.g. `"api/scryfall"`); | |
| 7 | +2. **extraction schema** — the payload shape the connector captures in `crawl()` (typed with Zod); | |
| 8 | +3. **normalization adapter** — a pure `normalize(raw)` returning canonical `NormalizedRecord[]`; | |
| 9 | +4. **fixtures** — at least one real captured payload in `data/fixtures/<source-id>/*.json` and a | |
| 10 | + `*.test.ts` next to the connector calling `runFixtureSuite`. | |
| 11 | + | |
| 12 | +The generic pipeline (raw store → normalizer → entity resolution → dedupe → validation → canonical | |
| 13 | +tables → valuation → indices) then works without changes. | |
| 14 | + | |
| 15 | +Rules: never invent data, keep source quirks inside the connector, store the source's own dates, | |
| 16 | +keep the native currency, respect robots/terms/rate limits, and never bypass access controls (§179). | |
| 17 | + | |
| 18 | +Module contract: `export default (meta: ConnectorMeta) => RareIndexConnector`. | |
added
connectors/package.json
+21 −0
@@ -0,0 +1,21 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@rareindex/source-connectors", | |
| 3 | + "version": "0.1.0", | |
| 4 | + "private": true, | |
| 5 | + "type": "module", | |
| 6 | + "scripts": { | |
| 7 | + "typecheck": "tsc -p tsconfig.json --noEmit", | |
| 8 | + "test": "vitest run --passWithNoTests" | |
| 9 | + }, | |
| 10 | + "dependencies": { | |
| 11 | + "@rareindex/connectors": "workspace:*", | |
| 12 | + "@rareindex/shared": "workspace:*", | |
| 13 | + "@rareindex/taxonomy": "workspace:*", | |
| 14 | + "zod": "^4.0.0" | |
| 15 | + }, | |
| 16 | + "devDependencies": { | |
| 17 | + "@types/node": "^24.0.0", | |
| 18 | + "typescript": "^5.9.3", | |
| 19 | + "vitest": "^3.2.0" | |
| 20 | + } | |
| 21 | +} | |
added
connectors/registry.json
+4 −0
@@ -0,0 +1,4 @@ | ||
| 1 | +{ | |
| 2 | + "version": "1.0", | |
| 3 | + "connectors": [] | |
| 4 | +} | |
added
connectors/tsconfig.json
+9 −0
@@ -0,0 +1,9 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../tsconfig.base.json", | |
| 3 | + "compilerOptions": { | |
| 4 | + "rootDir": ".", | |
| 5 | + "noEmit": true | |
| 6 | + }, | |
| 7 | + "include": ["./**/*.ts"], | |
| 8 | + "exclude": ["node_modules"] | |
| 9 | +} | |
added
connectors/vitest.config.ts
+5 −0
@@ -0,0 +1,5 @@ | ||
| 1 | +import { defineConfig } from 'vitest/config'; | |
| 2 | + | |
| 3 | +export default defineConfig({ | |
| 4 | + test: { include: ['**/*.test.ts'], exclude: ['node_modules/**'], testTimeout: 30_000 }, | |
| 5 | +}); | |
added
data/taxonomy/categories.json
+160 −0
@@ -0,0 +1,160 @@ | ||
| 1 | +{ | |
| 2 | + "$comment": "Extensible RareIndex taxonomy. Families (level 0) map to CLAUDE.md §5–§100; children are seeded subcategories. New nodes may be added at runtime via approved taxonomy_proposals. phase: 1 = launch wedge, 2 = next, 3 = later. Never hardcode this list in application code.", | |
| 3 | + "nodes": [ | |
| 4 | + { "slug": "trading_cards", "name": "Trading Cards", "short": "TCG", "phase": 1, "index": "RARE-TCG", "conditionScale": "cards", "graders": ["psa", "bgs", "cgc", "sgc", "tag", "ace"], "icon": "cards" }, | |
| 5 | + { "slug": "pokemon", "parent": "trading_cards", "name": "Pokémon", "phase": 1, "index": "RARE-TCG", "conditionScale": "cards", "graders": ["psa", "bgs", "cgc", "sgc", "tag", "ace"] }, | |
| 6 | + { "slug": "magic_the_gathering", "parent": "trading_cards", "name": "Magic: The Gathering", "short": "MTG", "phase": 1, "index": "RARE-TCG", "conditionScale": "cards", "graders": ["psa", "bgs", "cgc"] }, | |
| 7 | + { "slug": "yugioh", "parent": "trading_cards", "name": "Yu-Gi-Oh!", "phase": 1, "index": "RARE-TCG", "conditionScale": "cards", "graders": ["psa", "bgs", "cgc", "ace"] }, | |
| 8 | + { "slug": "one_piece_card_game", "parent": "trading_cards", "name": "One Piece Card Game", "phase": 2, "index": "RARE-TCG", "conditionScale": "cards", "graders": ["psa", "bgs", "cgc"] }, | |
| 9 | + { "slug": "disney_lorcana", "parent": "trading_cards", "name": "Disney Lorcana", "phase": 2, "index": "RARE-TCG", "conditionScale": "cards", "graders": ["psa", "bgs", "cgc"] }, | |
| 10 | + { "slug": "dragon_ball_tcg", "parent": "trading_cards", "name": "Dragon Ball Super / Masters", "phase": 3, "index": "RARE-TCG", "conditionScale": "cards" }, | |
| 11 | + { "slug": "digimon_tcg", "parent": "trading_cards", "name": "Digimon Card Game", "phase": 3, "index": "RARE-TCG", "conditionScale": "cards" }, | |
| 12 | + { "slug": "flesh_and_blood", "parent": "trading_cards", "name": "Flesh and Blood", "phase": 3, "index": "RARE-TCG", "conditionScale": "cards" }, | |
| 13 | + { "slug": "weiss_schwarz", "parent": "trading_cards", "name": "Weiß Schwarz", "phase": 3, "index": "RARE-TCG", "conditionScale": "cards" }, | |
| 14 | + { "slug": "final_fantasy_tcg", "parent": "trading_cards", "name": "Final Fantasy TCG", "phase": 3, "index": "RARE-TCG", "conditionScale": "cards" }, | |
| 15 | + { "slug": "star_wars_tcg", "parent": "trading_cards", "name": "Star Wars (Unlimited, CCG, Destiny)", "phase": 3, "index": "RARE-TCG", "conditionScale": "cards" }, | |
| 16 | + { "slug": "other_tcg", "parent": "trading_cards", "name": "Other TCGs", "phase": 3, "index": "RARE-TCG", "conditionScale": "cards", "description": "Naruto, My Hero Academia, UniVersus, MetaZoo, Cardfight Vanguard, Battle Spirits, Force of Will, KeyForge, Chaotic, Duel Masters, Altered, Sorcery, Riftbound, Grand Archive, Gundam Card Game" }, | |
| 17 | + { "slug": "non_sport_cards", "parent": "trading_cards", "name": "Non-Sport & Entertainment Cards", "phase": 3, "index": "RARE-TCG", "conditionScale": "cards", "description": "Marvel, DC, Garbage Pail Kids, Topps entertainment" }, | |
| 18 | + | |
| 19 | + { "slug": "sports_cards", "name": "Sports Cards", "phase": 1, "index": "RARE-SPORT", "conditionScale": "cards", "graders": ["psa", "bgs", "sgc", "cgc"], "icon": "sports" }, | |
| 20 | + { "slug": "baseball_cards", "parent": "sports_cards", "name": "Baseball Cards", "phase": 1, "index": "RARE-SPORT", "conditionScale": "cards" }, | |
| 21 | + { "slug": "basketball_cards", "parent": "sports_cards", "name": "Basketball Cards", "phase": 1, "index": "RARE-SPORT", "conditionScale": "cards" }, | |
| 22 | + { "slug": "football_cards", "parent": "sports_cards", "name": "Football Cards", "phase": 1, "index": "RARE-SPORT", "conditionScale": "cards" }, | |
| 23 | + { "slug": "hockey_cards", "parent": "sports_cards", "name": "Hockey Cards", "phase": 1, "index": "RARE-SPORT", "conditionScale": "cards" }, | |
| 24 | + { "slug": "soccer_cards", "parent": "sports_cards", "name": "Soccer Cards", "phase": 1, "index": "RARE-SPORT", "conditionScale": "cards" }, | |
| 25 | + { "slug": "f1_cards", "parent": "sports_cards", "name": "Formula 1 Cards", "phase": 2, "index": "RARE-SPORT", "conditionScale": "cards" }, | |
| 26 | + { "slug": "other_sports_cards", "parent": "sports_cards", "name": "Other Sports Cards", "phase": 2, "index": "RARE-SPORT", "conditionScale": "cards", "description": "UFC, boxing, golf, tennis, cricket, wrestling, NASCAR, Olympics, lacrosse, rugby" }, | |
| 27 | + | |
| 28 | + { "slug": "comics", "name": "Comics", "phase": 1, "index": "RARE-COMIC", "conditionScale": "comics", "graders": ["cgc", "cbcs", "pgx"], "icon": "comics" }, | |
| 29 | + { "slug": "marvel_comics", "parent": "comics", "name": "Marvel", "phase": 1, "index": "RARE-COMIC", "conditionScale": "comics" }, | |
| 30 | + { "slug": "dc_comics", "parent": "comics", "name": "DC", "phase": 1, "index": "RARE-COMIC", "conditionScale": "comics" }, | |
| 31 | + { "slug": "independent_comics", "parent": "comics", "name": "Independent & Golden Age", "phase": 2, "index": "RARE-COMIC", "conditionScale": "comics", "description": "Image, Dark Horse, IDW, Boom, Archie, Valiant, Dynamite, EC" }, | |
| 32 | + { "slug": "manga", "name": "Manga", "phase": 2, "index": "RARE-BOOK", "conditionScale": "books", "graders": ["cgc"], "icon": "book" }, | |
| 33 | + | |
| 34 | + { "slug": "video_games", "name": "Video Games", "phase": 1, "index": "RARE-GAME", "conditionScale": "video_games", "graders": ["wata", "vga", "cgc"], "icon": "game" }, | |
| 35 | + { "slug": "nintendo_games", "parent": "video_games", "name": "Nintendo", "phase": 1, "index": "RARE-GAME", "conditionScale": "video_games", "description": "NES, Famicom, SNES, N64, GameCube, Wii, Switch, Game Boy family, DS, 3DS" }, | |
| 36 | + { "slug": "sega_games", "parent": "video_games", "name": "Sega", "phase": 1, "index": "RARE-GAME", "conditionScale": "video_games" }, | |
| 37 | + { "slug": "playstation_games", "parent": "video_games", "name": "PlayStation", "phase": 1, "index": "RARE-GAME", "conditionScale": "video_games" }, | |
| 38 | + { "slug": "xbox_games", "parent": "video_games", "name": "Xbox", "phase": 1, "index": "RARE-GAME", "conditionScale": "video_games" }, | |
| 39 | + { "slug": "atari_retro_games", "parent": "video_games", "name": "Atari & Early Consoles", "phase": 2, "index": "RARE-GAME", "conditionScale": "video_games", "description": "Atari, Intellivision, ColecoVision, Neo Geo, PC Engine/TurboGrafx, MSX, Commodore, Amiga" }, | |
| 40 | + { "slug": "pc_games", "parent": "video_games", "name": "PC Games", "phase": 2, "index": "RARE-GAME", "conditionScale": "video_games" }, | |
| 41 | + { "slug": "gaming_hardware", "name": "Gaming Hardware", "phase": 2, "index": "RARE-GAME", "conditionScale": "electronics", "icon": "console" }, | |
| 42 | + { "slug": "arcade_pinball", "name": "Arcade & Pinball", "phase": 3, "index": "RARE-GAME", "conditionScale": "machines" }, | |
| 43 | + | |
| 44 | + { "slug": "sneakers", "name": "Sneakers", "phase": 1, "index": "RARE-SNEAKER", "conditionScale": "sneakers", "icon": "sneaker" }, | |
| 45 | + { "slug": "nike_jordan", "parent": "sneakers", "name": "Nike & Jordan", "phase": 1, "index": "RARE-SNEAKER", "conditionScale": "sneakers" }, | |
| 46 | + { "slug": "adidas_yeezy", "parent": "sneakers", "name": "adidas & Yeezy", "phase": 1, "index": "RARE-SNEAKER", "conditionScale": "sneakers" }, | |
| 47 | + { "slug": "new_balance_asics_other", "parent": "sneakers", "name": "New Balance, ASICS & Others", "phase": 1, "index": "RARE-SNEAKER", "conditionScale": "sneakers" }, | |
| 48 | + | |
| 49 | + { "slug": "watches", "name": "Watches", "phase": 1, "index": "RARE-WATCH", "conditionScale": "watches", "icon": "watch" }, | |
| 50 | + { "slug": "rolex", "parent": "watches", "name": "Rolex", "phase": 1, "index": "RARE-WATCH", "conditionScale": "watches" }, | |
| 51 | + { "slug": "patek_philippe", "parent": "watches", "name": "Patek Philippe", "phase": 1, "index": "RARE-WATCH", "conditionScale": "watches" }, | |
| 52 | + { "slug": "audemars_piguet", "parent": "watches", "name": "Audemars Piguet", "phase": 1, "index": "RARE-WATCH", "conditionScale": "watches" }, | |
| 53 | + { "slug": "omega", "parent": "watches", "name": "Omega", "phase": 1, "index": "RARE-WATCH", "conditionScale": "watches" }, | |
| 54 | + { "slug": "other_watches", "parent": "watches", "name": "Other Watch Brands", "phase": 1, "index": "RARE-WATCH", "conditionScale": "watches", "description": "Richard Mille, Vacheron Constantin, Cartier, Tudor, Breitling, IWC, JLC, A. Lange & Söhne, Breguet, Blancpain, Zenith, Grand Seiko, Seiko, TAG Heuer, Panerai, Hublot, F.P. Journe, MB&F, De Bethune, Greubel Forsey, Urwerk" }, | |
| 55 | + | |
| 56 | + { "slug": "lego", "name": "LEGO", "phase": 1, "index": "RARE-LEGO", "conditionScale": "lego", "icon": "brick" }, | |
| 57 | + { "slug": "lego_sets", "parent": "lego", "name": "LEGO Sets", "phase": 1, "index": "RARE-LEGO", "conditionScale": "lego" }, | |
| 58 | + { "slug": "lego_minifigures", "parent": "lego", "name": "LEGO Minifigures", "phase": 1, "index": "RARE-LEGO", "conditionScale": "lego" }, | |
| 59 | + | |
| 60 | + { "slug": "funko", "name": "Funko", "phase": 1, "index": "RARE-TOY", "conditionScale": "boxed_toys", "icon": "toy" }, | |
| 61 | + { "slug": "designer_toys", "name": "Designer Toys", "phase": 1, "index": "RARE-TOY", "conditionScale": "boxed_toys", "description": "Bearbrick, Medicom, KAWS, Kidrobot, Superplastic, Mighty Jaxx, Pop Mart (Labubu, Molly, Skullpanda, Dimoo), Murakami" }, | |
| 62 | + { "slug": "action_figures", "name": "Action Figures", "phase": 2, "index": "RARE-TOY", "conditionScale": "boxed_toys" }, | |
| 63 | + { "slug": "vintage_toys", "name": "Vintage Toys", "phase": 2, "index": "RARE-TOY", "conditionScale": "boxed_toys" }, | |
| 64 | + { "slug": "dolls", "name": "Dolls", "phase": 3, "index": "RARE-TOY", "conditionScale": "boxed_toys" }, | |
| 65 | + { "slug": "plush", "name": "Plush", "phase": 3, "index": "RARE-TOY", "conditionScale": "boxed_toys" }, | |
| 66 | + { "slug": "model_cars", "name": "Model Cars", "phase": 2, "index": "RARE-TOY", "conditionScale": "boxed_toys" }, | |
| 67 | + { "slug": "model_trains", "name": "Model Trains", "phase": 3, "index": "RARE-TOY", "conditionScale": "boxed_toys" }, | |
| 68 | + | |
| 69 | + { "slug": "automobiles", "name": "Automobiles", "phase": 2, "index": "RARE-AUTO", "conditionScale": "vehicles", "icon": "car" }, | |
| 70 | + { "slug": "motorcycles", "name": "Motorcycles", "phase": 3, "index": "RARE-AUTO", "conditionScale": "vehicles" }, | |
| 71 | + { "slug": "automotive_memorabilia", "name": "Automotive Memorabilia", "phase": 3, "index": "RARE-AUTO", "conditionScale": "general" }, | |
| 72 | + { "slug": "formula_1", "name": "Formula 1 Memorabilia", "phase": 3, "index": "RARE-AUTO", "conditionScale": "general" }, | |
| 73 | + { "slug": "sports_memorabilia", "name": "Sports Memorabilia", "phase": 2, "index": "RARE-SPORT", "conditionScale": "general" }, | |
| 74 | + | |
| 75 | + { "slug": "coins", "name": "Coins", "phase": 2, "index": "RARE-COIN", "conditionScale": "coins", "graders": ["pcgs", "ngc", "anacs", "iccs"], "icon": "coin" }, | |
| 76 | + { "slug": "banknotes", "name": "Banknotes", "phase": 3, "index": "RARE-COIN", "conditionScale": "coins", "graders": ["pmg", "pcgs"] }, | |
| 77 | + { "slug": "stamps", "name": "Stamps", "phase": 3, "index": "RARE-COIN", "conditionScale": "stamps" }, | |
| 78 | + | |
| 79 | + { "slug": "books", "name": "Books", "phase": 2, "index": "RARE-BOOK", "conditionScale": "books", "icon": "book" }, | |
| 80 | + { "slug": "historical_documents", "name": "Historical Documents", "phase": 3, "index": "RARE-BOOK", "conditionScale": "books" }, | |
| 81 | + { "slug": "autographs", "name": "Autographs", "phase": 3, "index": "RARE-BOOK", "conditionScale": "general", "graders": ["psa_dna", "jsa", "beckett_auth"] }, | |
| 82 | + { "slug": "maps", "name": "Maps & Globes", "phase": 3, "index": "RARE-BOOK", "conditionScale": "books" }, | |
| 83 | + { "slug": "postcards", "name": "Postcards", "phase": 3, "index": "RARE-BOOK", "conditionScale": "general" }, | |
| 84 | + | |
| 85 | + { "slug": "music", "name": "Music (Vinyl & Recordings)", "phase": 2, "index": "RARE-MUSIC", "conditionScale": "records", "icon": "vinyl" }, | |
| 86 | + { "slug": "music_memorabilia", "name": "Music Memorabilia", "phase": 3, "index": "RARE-MUSIC", "conditionScale": "general" }, | |
| 87 | + { "slug": "musical_instruments", "name": "Musical Instruments", "phase": 3, "index": "RARE-MUSIC", "conditionScale": "general" }, | |
| 88 | + | |
| 89 | + { "slug": "movie_memorabilia", "name": "Movie Memorabilia & Props", "phase": 3, "index": "RARE-ART", "conditionScale": "general" }, | |
| 90 | + { "slug": "movie_posters", "name": "Movie Posters", "phase": 3, "index": "RARE-ART", "conditionScale": "paper" }, | |
| 91 | + { "slug": "animation_art", "name": "Animation Art", "phase": 3, "index": "RARE-ART", "conditionScale": "paper" }, | |
| 92 | + { "slug": "art", "name": "Art", "phase": 2, "index": "RARE-ART", "conditionScale": "art", "icon": "art" }, | |
| 93 | + { "slug": "contemporary_art", "parent": "art", "name": "Contemporary Art & Editions", "phase": 2, "index": "RARE-ART", "conditionScale": "art" }, | |
| 94 | + { "slug": "photography", "name": "Photography", "phase": 3, "index": "RARE-ART", "conditionScale": "paper" }, | |
| 95 | + { "slug": "cameras", "name": "Cameras", "phase": 3, "index": "RARE-TECH", "conditionScale": "electronics" }, | |
| 96 | + | |
| 97 | + { "slug": "apple_collectibles", "name": "Apple Collectibles", "phase": 3, "index": "RARE-TECH", "conditionScale": "electronics", "icon": "tech" }, | |
| 98 | + { "slug": "vintage_computers", "name": "Vintage Computers", "phase": 3, "index": "RARE-TECH", "conditionScale": "electronics" }, | |
| 99 | + { "slug": "computer_hardware", "name": "Computer Hardware", "phase": 3, "index": "RARE-TECH", "conditionScale": "electronics" }, | |
| 100 | + { "slug": "mobile_phones", "name": "Mobile Phones", "phase": 3, "index": "RARE-TECH", "conditionScale": "electronics" }, | |
| 101 | + { "slug": "keyboards", "name": "Keyboards", "phase": 3, "index": "RARE-TECH", "conditionScale": "electronics" }, | |
| 102 | + { "slug": "audio_equipment", "name": "Audio Equipment", "phase": 3, "index": "RARE-TECH", "conditionScale": "electronics" }, | |
| 103 | + | |
| 104 | + { "slug": "wine", "name": "Wine", "phase": 2, "index": "RARE-WINE", "conditionScale": "bottles", "icon": "wine" }, | |
| 105 | + { "slug": "whisky", "name": "Whisky", "phase": 2, "index": "RARE-WINE", "conditionScale": "bottles" }, | |
| 106 | + { "slug": "rum", "name": "Rum", "phase": 3, "index": "RARE-WINE", "conditionScale": "bottles" }, | |
| 107 | + { "slug": "cognac", "name": "Cognac", "phase": 3, "index": "RARE-WINE", "conditionScale": "bottles" }, | |
| 108 | + { "slug": "perfume", "name": "Perfume", "phase": 3, "index": "RARE-LUXURY", "conditionScale": "bottles" }, | |
| 109 | + | |
| 110 | + { "slug": "luxury_handbags", "name": "Luxury Handbags", "phase": 2, "index": "RARE-LUXURY", "conditionScale": "luxury", "icon": "bag" }, | |
| 111 | + { "slug": "fashion_streetwear", "name": "Fashion & Streetwear", "phase": 3, "index": "RARE-LUXURY", "conditionScale": "luxury" }, | |
| 112 | + { "slug": "jewelry", "name": "Jewelry", "phase": 3, "index": "RARE-LUXURY", "conditionScale": "luxury" }, | |
| 113 | + { "slug": "gemstones", "name": "Gemstones", "phase": 3, "index": "RARE-LUXURY", "conditionScale": "general", "compliance": ["certification_required"] }, | |
| 114 | + { "slug": "pens", "name": "Pens", "phase": 3, "index": "RARE-LUXURY", "conditionScale": "general" }, | |
| 115 | + { "slug": "lighters", "name": "Lighters", "phase": 3, "index": "RARE-LUXURY", "conditionScale": "general" }, | |
| 116 | + | |
| 117 | + { "slug": "minerals", "name": "Minerals", "phase": 3, "index": "RARE-FOSSIL", "conditionScale": "general" }, | |
| 118 | + { "slug": "meteorites", "name": "Meteorites", "phase": 3, "index": "RARE-FOSSIL", "conditionScale": "general" }, | |
| 119 | + { "slug": "fossils", "name": "Fossils", "phase": 3, "index": "RARE-FOSSIL", "conditionScale": "general", "compliance": ["jurisdiction_check", "provenance_required"] }, | |
| 120 | + | |
| 121 | + { "slug": "antiques", "name": "Antiques", "phase": 3, "index": "RARE-DESIGN", "conditionScale": "general" }, | |
| 122 | + { "slug": "porcelain", "name": "Porcelain", "phase": 3, "index": "RARE-DESIGN", "conditionScale": "general" }, | |
| 123 | + { "slug": "glass_crystal", "name": "Glass & Crystal", "phase": 3, "index": "RARE-DESIGN", "conditionScale": "general" }, | |
| 124 | + { "slug": "silver", "name": "Silver", "phase": 3, "index": "RARE-DESIGN", "conditionScale": "general" }, | |
| 125 | + { "slug": "clocks", "name": "Clocks", "phase": 3, "index": "RARE-DESIGN", "conditionScale": "general" }, | |
| 126 | + { "slug": "design_furniture", "name": "Design & Furniture", "phase": 3, "index": "RARE-DESIGN", "conditionScale": "general" }, | |
| 127 | + { "slug": "scientific_instruments", "name": "Scientific Instruments", "phase": 3, "index": "RARE-DESIGN", "conditionScale": "general" }, | |
| 128 | + { "slug": "typewriters", "name": "Typewriters", "phase": 3, "index": "RARE-DESIGN", "conditionScale": "general" }, | |
| 129 | + { "slug": "vending_machines", "name": "Vending Machines", "phase": 3, "index": "RARE-DESIGN", "conditionScale": "machines" }, | |
| 130 | + | |
| 131 | + { "slug": "advertising", "name": "Advertising Collectibles", "phase": 3, "index": "RARE-DESIGN", "conditionScale": "general" }, | |
| 132 | + { "slug": "disney_collectibles", "name": "Disney Collectibles", "phase": 3, "index": "RARE-TOY", "conditionScale": "general" }, | |
| 133 | + { "slug": "sanrio", "name": "Sanrio", "phase": 3, "index": "RARE-TOY", "conditionScale": "general" }, | |
| 134 | + { "slug": "star_wars", "name": "Star Wars (cross-category)", "phase": 3, "index": "RARE-TOY", "conditionScale": "general" }, | |
| 135 | + { "slug": "marvel", "name": "Marvel (cross-category)", "phase": 3, "index": "RARE-TOY", "conditionScale": "general" }, | |
| 136 | + { "slug": "dc", "name": "DC (cross-category)", "phase": 3, "index": "RARE-TOY", "conditionScale": "general" }, | |
| 137 | + { "slug": "harry_potter", "name": "Harry Potter", "phase": 3, "index": "RARE-BOOK", "conditionScale": "general" }, | |
| 138 | + { "slug": "lord_of_the_rings", "name": "Lord of the Rings", "phase": 3, "index": "RARE-BOOK", "conditionScale": "general" }, | |
| 139 | + { "slug": "warhammer", "name": "Warhammer", "phase": 3, "index": "RARE-TOY", "conditionScale": "boxed_toys" }, | |
| 140 | + { "slug": "gundam", "name": "Gundam & Gunpla", "phase": 3, "index": "RARE-TOY", "conditionScale": "boxed_toys" }, | |
| 141 | + | |
| 142 | + { "slug": "travel_collectibles", "name": "Travel Collectibles", "phase": 3, "index": "RARE-DESIGN", "conditionScale": "general" }, | |
| 143 | + { "slug": "airline_collectibles", "name": "Airline Collectibles", "phase": 3, "index": "RARE-DESIGN", "conditionScale": "general" }, | |
| 144 | + { "slug": "aviation", "name": "Aviation", "phase": 3, "index": "RARE-SPACE", "conditionScale": "general" }, | |
| 145 | + { "slug": "space", "name": "Space Memorabilia", "phase": 3, "index": "RARE-SPACE", "conditionScale": "general" }, | |
| 146 | + { "slug": "militaria", "name": "Militaria", "phase": 3, "index": "RARE-MILITARIA", "conditionScale": "general", "compliance": ["jurisdiction_check", "restricted_symbols_review"] }, | |
| 147 | + { "slug": "medals", "name": "Medals", "phase": 3, "index": "RARE-MILITARIA", "conditionScale": "coins" }, | |
| 148 | + { "slug": "olympic_collectibles", "name": "Olympic Collectibles", "phase": 3, "index": "RARE-SPORT", "conditionScale": "general" }, | |
| 149 | + { "slug": "license_plates", "name": "License Plates", "phase": 3, "index": "RARE-AUTO", "conditionScale": "general" }, | |
| 150 | + { "slug": "pins", "name": "Pins", "phase": 3, "index": "RARE-TOY", "conditionScale": "general" }, | |
| 151 | + { "slug": "board_games", "name": "Board Games", "phase": 3, "index": "RARE-GAME", "conditionScale": "boxed_toys" }, | |
| 152 | + { "slug": "chess", "name": "Chess", "phase": 3, "index": "RARE-DESIGN", "conditionScale": "general" }, | |
| 153 | + { "slug": "playing_cards", "name": "Playing Cards", "phase": 3, "index": "RARE-TCG", "conditionScale": "general" }, | |
| 154 | + { "slug": "casino_memorabilia", "name": "Casino Memorabilia", "phase": 3, "index": "RARE-DESIGN", "conditionScale": "general", "compliance": ["jurisdiction_check"] }, | |
| 155 | + { "slug": "political_memorabilia", "name": "Political Memorabilia", "phase": 3, "index": "RARE-BOOK", "conditionScale": "general", "compliance": ["neutral_presentation"] }, | |
| 156 | + { "slug": "royal_memorabilia", "name": "Royal Memorabilia", "phase": 3, "index": "RARE-BOOK", "conditionScale": "general" }, | |
| 157 | + { "slug": "corporate_memorabilia", "name": "Historic Corporate Memorabilia", "phase": 3, "index": "RARE-TECH", "conditionScale": "general" }, | |
| 158 | + { "slug": "digital_collectibles", "name": "Digital Collectibles", "phase": 3, "index": null, "conditionScale": "digital", "description": "NFTs, tokenized assets, game skins — separate valuation model (§100)", "compliance": ["separate_valuation_model"] } | |
| 159 | + ] | |
| 160 | +} | |
added
data/taxonomy/conditions.json
+69 −0
@@ -0,0 +1,69 @@ | ||
| 1 | +{ | |
| 2 | + "$comment": "Category-specific condition scales (§117). `values` ordered best → worst. `aliases` map raw source strings (lowercased) to slugs.", | |
| 3 | + "scales": { | |
| 4 | + "cards": { | |
| 5 | + "values": ["gem_mint", "mint", "near_mint", "excellent", "very_good", "good", "fair", "poor"], | |
| 6 | + "completeness": [], | |
| 7 | + "aliases": { "gem mint": "gem_mint", "gem mt": "gem_mint", "mint": "mint", "nm": "near_mint", "near mint": "near_mint", "nm-mt": "near_mint", "nm/m": "near_mint", "lp": "excellent", "lightly played": "excellent", "ex": "excellent", "excellent": "excellent", "mp": "very_good", "moderately played": "very_good", "vg": "very_good", "hp": "good", "heavily played": "good", "good": "good", "damaged": "poor", "poor": "poor", "dmg": "poor", "raw": null, "ungraded": null } | |
| 8 | + }, | |
| 9 | + "video_games": { | |
| 10 | + "values": ["sealed", "cib", "loose"], | |
| 11 | + "completeness": ["sealed", "cib", "box_only", "manual_only", "loose"], | |
| 12 | + "aliases": { "new": "sealed", "sealed": "sealed", "factory sealed": "sealed", "brand new": "sealed", "cib": "cib", "complete in box": "cib", "complete": "cib", "boxed": "cib", "loose": "loose", "cart only": "loose", "cartridge only": "loose", "disc only": "loose", "used": "loose", "graded": null } | |
| 13 | + }, | |
| 14 | + "sneakers": { | |
| 15 | + "values": ["new", "deadstock", "lightly_used", "used"], | |
| 16 | + "completeness": ["with_box", "no_box", "replacement_box"], | |
| 17 | + "aliases": { "new": "new", "ds": "deadstock", "deadstock": "deadstock", "brand new": "new", "vnds": "lightly_used", "lightly used": "lightly_used", "pre-owned": "used", "used": "used", "worn": "used" } | |
| 18 | + }, | |
| 19 | + "watches": { | |
| 20 | + "values": ["unworn", "excellent", "good", "fair", "poor", "parts"], | |
| 21 | + "completeness": ["full_set", "box_papers", "papers_only", "box_only", "watch_only"], | |
| 22 | + "aliases": { "new": "unworn", "unworn": "unworn", "new with tags": "unworn", "like new": "excellent", "excellent": "excellent", "very good": "excellent", "good": "good", "fair": "fair", "poor": "poor", "for parts": "parts", "parts": "parts", "incomplete": "parts", "pre-owned": null, "used": null } | |
| 23 | + }, | |
| 24 | + "books": { | |
| 25 | + "values": ["fine", "very_good", "good", "fair", "poor"], | |
| 26 | + "completeness": ["dust_jacket", "no_dust_jacket", "slipcase"], | |
| 27 | + "aliases": { "as new": "fine", "fine": "fine", "f": "fine", "near fine": "fine", "vg": "very_good", "very good": "very_good", "good": "good", "g": "good", "fair": "fair", "poor": "poor", "reading copy": "poor" } | |
| 28 | + }, | |
| 29 | + "comics": { | |
| 30 | + "values": ["gem_mint", "mint", "near_mint", "very_fine", "fine", "very_good", "good", "fair", "poor"], | |
| 31 | + "completeness": [], | |
| 32 | + "aliases": { "nm": "near_mint", "near mint": "near_mint", "vf": "very_fine", "very fine": "very_fine", "fn": "fine", "fine": "fine", "vg": "very_good", "very good": "very_good", "gd": "good", "good": "good", "fr": "fair", "fair": "fair", "pr": "poor", "poor": "poor" } | |
| 33 | + }, | |
| 34 | + "lego": { | |
| 35 | + "values": ["sealed", "opened_complete", "used_complete", "incomplete"], | |
| 36 | + "completeness": ["sealed", "opened_complete", "used_complete", "incomplete", "minifigure_only", "instructions_only"], | |
| 37 | + "aliases": { "new": "sealed", "sealed": "sealed", "misb": "sealed", "nisb": "sealed", "new in sealed box": "sealed", "complete": "opened_complete", "used complete": "used_complete", "used": "used_complete", "incomplete": "incomplete" } | |
| 38 | + }, | |
| 39 | + "boxed_toys": { | |
| 40 | + "values": ["mint_in_box", "near_mint_box", "boxed", "loose_complete", "loose"], | |
| 41 | + "completeness": ["sealed", "boxed", "loose"], | |
| 42 | + "aliases": { "mib": "mint_in_box", "misb": "mint_in_box", "moc": "mint_in_box", "nib": "mint_in_box", "new": "mint_in_box", "boxed": "boxed", "in box": "boxed", "loose": "loose", "complete": "loose_complete" } | |
| 43 | + }, | |
| 44 | + "coins": { | |
| 45 | + "values": ["proof", "mint_state", "about_uncirculated", "extremely_fine", "very_fine", "fine", "very_good", "good", "about_good", "poor"], | |
| 46 | + "completeness": [], | |
| 47 | + "aliases": { "pf": "proof", "pr": "proof", "proof": "proof", "ms": "mint_state", "unc": "mint_state", "bu": "mint_state", "au": "about_uncirculated", "xf": "extremely_fine", "ef": "extremely_fine", "vf": "very_fine", "f": "fine", "vg": "very_good", "g": "good", "ag": "about_good", "p": "poor" } | |
| 48 | + }, | |
| 49 | + "records": { | |
| 50 | + "values": ["mint", "near_mint", "very_good_plus", "very_good", "good_plus", "good", "fair", "poor"], | |
| 51 | + "completeness": ["sealed", "with_sleeve", "no_sleeve"], | |
| 52 | + "aliases": { "m": "mint", "sealed": "mint", "nm": "near_mint", "vg+": "very_good_plus", "vg": "very_good", "g+": "good_plus", "g": "good", "f": "fair", "p": "poor" } | |
| 53 | + }, | |
| 54 | + "luxury": { | |
| 55 | + "values": ["new", "pristine", "excellent", "very_good", "good", "fair"], | |
| 56 | + "completeness": ["full_set", "dust_bag", "box", "receipt", "item_only"], | |
| 57 | + "aliases": { "new": "new", "new with tags": "new", "pristine": "pristine", "excellent": "excellent", "very good": "very_good", "good": "good", "fair": "fair" } | |
| 58 | + }, | |
| 59 | + "art": { "values": ["excellent", "very_good", "good", "fair", "restored"], "completeness": ["framed", "unframed", "coa"], "aliases": {} }, | |
| 60 | + "paper": { "values": ["mint", "near_mint", "very_fine", "fine", "very_good", "good", "fair", "poor"], "completeness": ["rolled", "folded", "linen_backed"], "aliases": {} }, | |
| 61 | + "electronics": { "values": ["sealed", "mint", "excellent", "good", "fair", "for_parts"], "completeness": ["sealed", "boxed", "unit_only"], "aliases": { "sealed": "sealed", "new": "sealed", "mint": "mint", "excellent": "excellent", "good": "good", "fair": "fair", "for parts": "for_parts", "not working": "for_parts" } }, | |
| 62 | + "bottles": { "values": ["pristine", "excellent", "good", "fair"], "completeness": ["owc", "oc", "sealed", "opened"], "aliases": {} }, | |
| 63 | + "vehicles": { "values": ["concours", "excellent", "good", "fair", "project"], "completeness": [], "aliases": {} }, | |
| 64 | + "machines": { "values": ["restored", "working_original", "working", "non_working", "project"], "completeness": [], "aliases": {} }, | |
| 65 | + "stamps": { "values": ["superb", "extremely_fine", "very_fine", "fine", "average", "poor"], "completeness": ["mnh", "mh", "used"], "aliases": {} }, | |
| 66 | + "general": { "values": ["excellent", "very_good", "good", "fair", "poor"], "completeness": [], "aliases": { "excellent": "excellent", "very good": "very_good", "good": "good", "fair": "fair", "poor": "poor" } }, | |
| 67 | + "digital": { "values": [], "completeness": [], "aliases": {} } | |
| 68 | + } | |
| 69 | +} | |
added
data/taxonomy/graders.json
+24 −0
@@ -0,0 +1,24 @@ | ||
| 1 | +{ | |
| 2 | + "$comment": "Grading companies (§118). Grades are tracked per grader; premiums are measured empirically, never assumed equal across graders.", | |
| 3 | + "graders": [ | |
| 4 | + { "slug": "psa", "name": "PSA", "categories": ["trading_cards", "sports_cards", "non_sport_cards"], "scale": { "type": "numeric", "values": ["1", "1.5", "2", "3", "4", "5", "6", "7", "8", "9", "10"], "top": "10" }, "populationUrl": "https://www.psacard.com/pop", "verifyUrl": "https://www.psacard.com/cert/{cert}", "aliases": ["psa", "professional sports authenticator"] }, | |
| 5 | + { "slug": "bgs", "name": "BGS (Beckett)", "categories": ["trading_cards", "sports_cards"], "scale": { "type": "numeric", "values": ["1", "2", "3", "4", "5", "6", "7", "7.5", "8", "8.5", "9", "9.5", "10"], "top": "10" }, "populationUrl": "https://www.beckett.com/grading/pop-report", "verifyUrl": "https://www.beckett.com/grading/card-lookup", "aliases": ["bgs", "beckett", "bccg"] }, | |
| 6 | + { "slug": "cgc", "name": "CGC", "categories": ["trading_cards", "sports_cards", "comics", "manga", "video_games"], "scale": { "type": "numeric", "values": ["0.5", "1", "1.5", "2", "2.5", "3", "3.5", "4", "4.5", "5", "5.5", "6", "6.5", "7", "7.5", "8", "8.5", "9", "9.2", "9.4", "9.6", "9.8", "9.9", "10"], "top": "10" }, "populationUrl": "https://www.cgccomics.com/census/", "verifyUrl": "https://www.cgccomics.com/certlookup/{cert}", "aliases": ["cgc"] }, | |
| 7 | + { "slug": "sgc", "name": "SGC", "categories": ["trading_cards", "sports_cards"], "scale": { "type": "numeric", "values": ["1", "1.5", "2", "2.5", "3", "3.5", "4", "4.5", "5", "5.5", "6", "6.5", "7", "7.5", "8", "8.5", "9", "9.5", "10"], "top": "10" }, "populationUrl": "https://gosgc.com/pop-report", "verifyUrl": "https://gosgc.com/card-registry", "aliases": ["sgc"] }, | |
| 8 | + { "slug": "tag", "name": "TAG", "categories": ["trading_cards", "sports_cards"], "scale": { "type": "numeric", "values": ["1", "2", "3", "4", "5", "6", "7", "8", "8.5", "9", "9.5", "10"], "top": "10" }, "aliases": ["tag grading"] }, | |
| 9 | + { "slug": "ace", "name": "ACE Grading", "categories": ["trading_cards"], "scale": { "type": "numeric", "values": ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"], "top": "10" }, "aliases": ["ace"] }, | |
| 10 | + { "slug": "cbcs", "name": "CBCS", "categories": ["comics"], "scale": { "type": "numeric", "values": ["0.5", "1", "2", "3", "4", "5", "6", "7", "8", "9", "9.2", "9.4", "9.6", "9.8", "10"], "top": "10" }, "aliases": ["cbcs"] }, | |
| 11 | + { "slug": "pgx", "name": "PGX", "categories": ["comics"], "scale": { "type": "numeric", "values": ["1", "2", "3", "4", "5", "6", "7", "8", "9", "9.8", "10"], "top": "10" }, "aliases": ["pgx"] }, | |
| 12 | + { "slug": "wata", "name": "WATA", "categories": ["video_games"], "scale": { "type": "numeric", "values": ["1", "2", "3", "4", "5", "6", "7", "7.5", "8", "8.5", "9", "9.2", "9.4", "9.6", "9.8", "10"], "top": "10" }, "populationUrl": "https://www.watagames.com/population", "aliases": ["wata"] }, | |
| 13 | + { "slug": "vga", "name": "VGA", "categories": ["video_games", "vintage_toys"], "scale": { "type": "numeric", "values": ["10", "20", "30", "40", "50", "60", "65", "70", "75", "80", "85", "90", "95", "100"], "top": "100" }, "aliases": ["vga"] }, | |
| 14 | + { "slug": "pcgs", "name": "PCGS", "categories": ["coins", "banknotes"], "scale": { "type": "sheldon", "values": ["1", "2", "3", "4", "6", "8", "10", "12", "15", "20", "25", "30", "35", "40", "45", "50", "53", "55", "58", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70"], "top": "70" }, "populationUrl": "https://www.pcgs.com/pop", "verifyUrl": "https://www.pcgs.com/cert/{cert}", "aliases": ["pcgs"] }, | |
| 15 | + { "slug": "ngc", "name": "NGC", "categories": ["coins", "medals"], "scale": { "type": "sheldon", "values": ["1", "2", "3", "4", "6", "8", "10", "12", "15", "20", "25", "30", "35", "40", "45", "50", "53", "55", "58", "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "70"], "top": "70" }, "populationUrl": "https://www.ngccoin.com/census/", "verifyUrl": "https://www.ngccoin.com/certlookup/{cert}", "aliases": ["ngc"] }, | |
| 16 | + { "slug": "anacs", "name": "ANACS", "categories": ["coins"], "scale": { "type": "sheldon", "values": [], "top": "70" }, "aliases": ["anacs"] }, | |
| 17 | + { "slug": "iccs", "name": "ICCS", "categories": ["coins"], "scale": { "type": "sheldon", "values": [], "top": "70" }, "aliases": ["iccs"] }, | |
| 18 | + { "slug": "pmg", "name": "PMG", "categories": ["banknotes"], "scale": { "type": "sheldon", "values": [], "top": "70" }, "aliases": ["pmg"] }, | |
| 19 | + { "slug": "psa_dna", "name": "PSA/DNA", "categories": ["autographs", "sports_memorabilia"], "scale": { "type": "numeric", "values": ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"], "top": "10" }, "aliases": ["psa/dna", "psa dna"] }, | |
| 20 | + { "slug": "jsa", "name": "JSA", "categories": ["autographs", "sports_memorabilia"], "scale": { "type": "descriptive", "values": ["authentic"], "top": "authentic" }, "aliases": ["jsa"] }, | |
| 21 | + { "slug": "beckett_auth", "name": "Beckett Authentication", "categories": ["autographs"], "scale": { "type": "numeric", "values": ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10"], "top": "10" }, "aliases": ["bas", "beckett authentication"] }, | |
| 22 | + { "slug": "raw", "name": "Raw / Ungraded", "categories": [], "scale": { "type": "descriptive", "values": [], "top": "" }, "aliases": ["raw", "ungraded"] } | |
| 23 | + ] | |
| 24 | +} | |
added
data/taxonomy/indices.json
+28 −0
@@ -0,0 +1,28 @@ | ||
| 1 | +{ | |
| 2 | + "$comment": "Index definitions (§3). Family slugs map categories → subindex; RARE aggregates all subindices. base_value 1000 at base_date. Values are only computed from observed data; an index publishes nothing until it has ≥ minConstituents priced constituents.", | |
| 3 | + "baseDate": "2024-01-01", | |
| 4 | + "baseValue": 1000, | |
| 5 | + "indices": [ | |
| 6 | + { "ticker": "RARE", "name": "RareIndex Global Collectibles Index", "flagship": true, "description": "Broad benchmark of the global collectibles market, aggregating all RareIndex subindices.", "families": [], "color": "#0f172a", "minConstituents": 25 }, | |
| 7 | + { "ticker": "RARE-TCG", "name": "RareIndex Trading Cards", "families": ["trading_cards", "playing_cards"], "color": "#b45309", "minConstituents": 10 }, | |
| 8 | + { "ticker": "RARE-SPORT", "name": "RareIndex Sports", "families": ["sports_cards", "sports_memorabilia", "olympic_collectibles"], "color": "#1d4ed8", "minConstituents": 10 }, | |
| 9 | + { "ticker": "RARE-WATCH", "name": "RareIndex Watches", "families": ["watches"], "color": "#334155", "minConstituents": 10 }, | |
| 10 | + { "ticker": "RARE-SNEAKER", "name": "RareIndex Sneakers", "families": ["sneakers"], "color": "#dc2626", "minConstituents": 10 }, | |
| 11 | + { "ticker": "RARE-LEGO", "name": "RareIndex LEGO", "families": ["lego"], "color": "#ca8a04", "minConstituents": 10 }, | |
| 12 | + { "ticker": "RARE-COMIC", "name": "RareIndex Comics", "families": ["comics"], "color": "#7c3aed", "minConstituents": 10 }, | |
| 13 | + { "ticker": "RARE-GAME", "name": "RareIndex Video Games", "families": ["video_games", "gaming_hardware", "arcade_pinball", "board_games"], "color": "#059669", "minConstituents": 10 }, | |
| 14 | + { "ticker": "RARE-ART", "name": "RareIndex Art", "families": ["art", "movie_memorabilia", "movie_posters", "animation_art", "photography"], "color": "#be185d", "minConstituents": 10 }, | |
| 15 | + { "ticker": "RARE-LUXURY", "name": "RareIndex Luxury", "families": ["luxury_handbags", "fashion_streetwear", "jewelry", "gemstones", "pens", "lighters", "perfume"], "color": "#a16207", "minConstituents": 10 }, | |
| 16 | + { "ticker": "RARE-WINE", "name": "RareIndex Wine & Spirits", "families": ["wine", "whisky", "rum", "cognac"], "color": "#7f1d1d", "minConstituents": 10 }, | |
| 17 | + { "ticker": "RARE-COIN", "name": "RareIndex Coins & Currency", "families": ["coins", "banknotes", "stamps"], "color": "#92400e", "minConstituents": 10 }, | |
| 18 | + { "ticker": "RARE-TOY", "name": "RareIndex Toys", "families": ["funko", "designer_toys", "action_figures", "vintage_toys", "dolls", "plush", "model_cars", "model_trains", "disney_collectibles", "sanrio", "star_wars", "marvel", "dc", "warhammer", "gundam", "pins"], "color": "#ea580c", "minConstituents": 10 }, | |
| 19 | + { "ticker": "RARE-MUSIC", "name": "RareIndex Music", "families": ["music", "music_memorabilia", "musical_instruments"], "color": "#4338ca", "minConstituents": 10 }, | |
| 20 | + { "ticker": "RARE-AUTO", "name": "RareIndex Automotive", "families": ["automobiles", "motorcycles", "automotive_memorabilia", "formula_1", "license_plates"], "color": "#0f766e", "minConstituents": 10 }, | |
| 21 | + { "ticker": "RARE-TECH", "name": "RareIndex Technology", "families": ["apple_collectibles", "vintage_computers", "computer_hardware", "mobile_phones", "keyboards", "audio_equipment", "cameras", "corporate_memorabilia"], "color": "#475569", "minConstituents": 10 }, | |
| 22 | + { "ticker": "RARE-BOOK", "name": "RareIndex Books & Paper", "families": ["books", "manga", "historical_documents", "autographs", "maps", "postcards", "harry_potter", "lord_of_the_rings", "political_memorabilia", "royal_memorabilia"], "color": "#713f12", "minConstituents": 10 }, | |
| 23 | + { "ticker": "RARE-MILITARIA", "name": "RareIndex Militaria & Medals", "families": ["militaria", "medals"], "color": "#3f3f46", "minConstituents": 10 }, | |
| 24 | + { "ticker": "RARE-SPACE", "name": "RareIndex Space & Aviation", "families": ["space", "aviation"], "color": "#1e3a8a", "minConstituents": 10 }, | |
| 25 | + { "ticker": "RARE-FOSSIL", "name": "RareIndex Natural History", "families": ["fossils", "minerals", "meteorites"], "color": "#65a30d", "minConstituents": 10 }, | |
| 26 | + { "ticker": "RARE-DESIGN", "name": "RareIndex Design & Antiques", "families": ["antiques", "porcelain", "glass_crystal", "silver", "clocks", "design_furniture", "scientific_instruments", "typewriters", "vending_machines", "advertising", "travel_collectibles", "airline_collectibles", "chess", "casino_memorabilia"], "color": "#57534e", "minConstituents": 10 } | |
| 27 | + ] | |
| 28 | +} | |
added
docs/ARCHITECTURE.md
+76 −0
@@ -0,0 +1,76 @@ | ||
| 1 | +# RareIndex — Architecture (Phase 1 foundation) | |
| 2 | + | |
| 3 | +This document is the practical companion to `CLAUDE.md` (the product & engineering mandate). It | |
| 4 | +describes what exists in the repository, how the pieces fit, and the decisions taken so far. | |
| 5 | + | |
| 6 | +## Monorepo | |
| 7 | + | |
| 8 | +pnpm workspaces, TypeScript strict everywhere, ESM. | |
| 9 | + | |
| 10 | +``` | |
| 11 | +apps/web Next.js 16 (App Router, React 19, Tailwind v4) — public site, account, admin | |
| 12 | +apps/api Fastify — public REST API /v1 (API keys, tiers, rate limits, exports) | |
| 13 | +packages/shared ids, money/FX helpers, canonical Zod schemas, stats helpers, logger, env | |
| 14 | +packages/database Drizzle ORM schema (55 tables), migrations, client, seed | |
| 15 | +packages/taxonomy extensible category tree, condition scales, graders, index definitions (data/taxonomy) | |
| 16 | +packages/connectors connector framework: interface, Firecrawl/Scrapfly/HTTP engines, router, quality, health, fixtures | |
| 17 | +packages/valuation price engine (RIV), outliers, grade premiums, scores | |
| 18 | +packages/indices index computation (chain-linked, repeat-sales), category snapshots, correlations | |
| 19 | +packages/search hybrid search (FTS + trigram + optional vectors) and natural-language query parsing | |
| 20 | +packages/ai ModelProvider abstraction (Anthropic, OpenAI-compatible), extraction, embeddings, vision | |
| 21 | +connectors/ source connectors grouped by primary engine (api/, feeds/, firecrawl/, scrapfly/) + registry.json | |
| 22 | +workers/ pipeline processes: crawler, normalizer, entity-resolution, valuation, image-processing, indices | |
| 23 | +data/taxonomy seed JSON for the taxonomy | |
| 24 | +data/fixtures captured real payloads per connector for tests | |
| 25 | +scripts/ operational CLI (`ri`), registry builder, deploy helpers | |
| 26 | +docs/ this file, ADRs, methodology | |
| 27 | +``` | |
| 28 | + | |
| 29 | +## Data flow (never write scraped data into product tables directly — §108) | |
| 30 | + | |
| 31 | +``` | |
| 32 | +connector.crawl() → raw_records (immutable, content-hash dedupe, snapshot on disk) | |
| 33 | + → connector.normalize(raw) → normalized_records (staging, auditable) | |
| 34 | + → entity resolution (identifiers → canonical key → fuzzy → embeddings/LLM) | |
| 35 | + → assets / asset_variants (+ sets, brands) | |
| 36 | + → dedupe + price validation (flags, audit_log; nothing deleted) | |
| 37 | + → sales / listings / auction_lots / price_observations (native currency + USD at historical FX) | |
| 38 | + → valuations, asset_stats, price_snapshots | |
| 39 | + → indices (index_values), category_snapshots, radar_findings | |
| 40 | +``` | |
| 41 | + | |
| 42 | +Queue: pg-boss (PostgreSQL-backed) behind a tiny abstraction so Redis Streams/Kafka can replace it | |
| 43 | +at scale (§140). Domain events are also appended to `events`. | |
| 44 | + | |
| 45 | +## Engines & routing (§198) | |
| 46 | + | |
| 47 | +`packages/connectors/src/router.ts`: `api/feed (direct HTTP) → firecrawl → scrapfly → requiresReview`. | |
| 48 | +Each engine result is scored (§199) by the connector's parser through `FetchOptions.parse/expect`. | |
| 49 | +Engines are only used on publicly accessible pages, with an honest user agent and rate limiting (§179). | |
| 50 | + | |
| 51 | +## Connector contract (§102, §197) | |
| 52 | + | |
| 53 | +`connectors/<engine>/<id>/{meta.json,index.ts,index.test.ts}` + `data/fixtures/<id>/*.json`. | |
| 54 | +`scripts/build-registry.ts` assembles `connectors/registry.json` from the `meta.json` files. | |
| 55 | +`packages/database/src/seed.ts` mirrors the registry into `sources`/`connectors` tables. | |
| 56 | + | |
| 57 | +## Canonical model highlights | |
| 58 | + | |
| 59 | +- `assets` = the object independent of grade/condition; `asset_variants` = grade/condition/size slice | |
| 60 | + (PSA 10, CIB, deadstock size 10). Sales, listings and valuations reference both. | |
| 61 | +- `canonical_key` (deterministic normalised key) + `identifiers` (JSONB of external ids) power entity | |
| 62 | + resolution; merges are recorded in `merged_from` and `audit_log`. | |
| 63 | +- Prices: `NUMERIC(18,4)` native + `price_usd` + `fx_rate`/`fx_date`. FX from ECB (frankfurter) stored | |
| 64 | + in `fx_rates`; historical conversions always use the rate of the sale date (§136). | |
| 65 | +- Price-guide numbers (Scryfall, TCG APIs) are `price_observations`, never `sales`. | |
| 66 | +- Every statistic exposes sample size, confidence and last update (§191); unknown stays NULL (§192). | |
| 67 | + | |
| 68 | +## Deployment | |
| 69 | + | |
| 70 | +Target: MacLustr node with PostgreSQL 17 + pgvector, deployed through the `mld` gateway (M1M32). | |
| 71 | +Processes (PM2): `rareindex-web` (Next.js), `rareindex-api` (Fastify), `rareindex-worker` (pipeline), | |
| 72 | +`rareindex-ngrok` (www.rareindex.io). Secrets live only in the mld manifest / `.env` on the node. | |
| 73 | + | |
| 74 | +## Decisions log | |
| 75 | + | |
| 76 | +See `docs/adr/`. | |
added
docs/adr/0001-stack-and-layout.md
+28 −0
@@ -0,0 +1,28 @@ | ||
| 1 | +# ADR 0001 — TypeScript end-to-end, pnpm monorepo, PostgreSQL-backed queue | |
| 2 | + | |
| 3 | +Date: 2026-09-07 · Status: accepted | |
| 4 | + | |
| 5 | +## Context | |
| 6 | +CLAUDE.md allows Node/TypeScript or Python services (§167) and suggests a layout (§195). The launch | |
| 7 | +wedge must ship quickly on a single node while the architecture must scale to hundreds of millions | |
| 8 | +of observations. | |
| 9 | + | |
| 10 | +## Decision | |
| 11 | +1. **TypeScript everywhere** (web, API, workers, connectors). One runtime, shared Zod schemas between | |
| 12 | + pipeline and UI, Drizzle typed queries, and the connector interface exactly as specified (§102). | |
| 13 | +2. **pnpm workspaces**, packages consumed as TS sources (`transpilePackages` in Next, `tsx` for workers). | |
| 14 | +3. **PostgreSQL 17** as system of record (pg_trgm, unaccent, pgvector). No Timescale for now; time | |
| 15 | + series tables (`price_snapshots`, `index_values`) use composite PKs and date indexes; partitioning | |
| 16 | + can be added by migration. | |
| 17 | +4. **pg-boss** as the queue (Postgres-backed), wrapped by a small `Queue` interface in `workers/lib` | |
| 18 | + so Redis Streams/Kafka can be substituted without touching connectors or handlers (§140). | |
| 19 | +5. **Admin UI lives inside `apps/web` under `/admin`** (token-protected) instead of a separate | |
| 20 | + `apps/admin`, to avoid duplicating the design system in Phase 1. It can be split later. | |
| 21 | +6. **Registry from meta files**: `connectors/registry.json` is generated from per-connector | |
| 22 | + `meta.json` (avoids merge conflicts between parallel contributors) — it remains the artefact §106 asks for. | |
| 23 | + | |
| 24 | +## Consequences | |
| 25 | +- Data-science-heavy methods (hedonic regression, repeat-sales) are implemented in TS with small | |
| 26 | + numerical helpers; a Python research service can be added later behind the same tables. | |
| 27 | +- Everything deploys as PM2 processes on one node via `mld`; horizontal scale = more worker processes | |
| 28 | + pointed at the same Postgres/pg-boss. | |
added
docs/adr/0002-data-honesty.md
+15 −0
@@ -0,0 +1,15 @@ | ||
| 1 | +# ADR 0002 — Data honesty rules enforced in code | |
| 2 | + | |
| 3 | +Date: 2026-09-07 · Status: accepted | |
| 4 | + | |
| 5 | +- No fabricated data, ever (§192). Seeds contain taxonomy and index *definitions* only. Sales, listings, | |
| 6 | + prices, populations and market caps come from connectors with provenance (`source_url`, `raw_record_id`, | |
| 7 | + `parser_version`, `connector_version`). | |
| 8 | +- Price-guide values (Scryfall/TCG APIs, guide pages) are stored as `price_observations`, shown as | |
| 9 | + "guide" numbers and weighted below transactions in RIV. They never populate `sales`. | |
| 10 | +- A valuation is published only with `sample_size`, `confidence`, `low/high` and `computed_at`. Below | |
| 11 | + the evidence threshold the UI renders "Data unavailable" (`<Unavailable/>`). | |
| 12 | +- Indices publish nothing until `minConstituents` priced constituents exist; coverage is stored per day. | |
| 13 | +- Outliers are flagged (`status='flagged'|'excluded'`, `flags[]`, `audit_log`) — never deleted. | |
| 14 | +- Crawl time ≠ sale time: connectors must parse the source's own date; the fixture suite checks it. | |
| 15 | +- Historical FX is applied at the sale date; the display currency is a view-time conversion. | |
added
package.json
+31 −0
@@ -0,0 +1,31 @@ | ||
| 1 | +{ | |
| 2 | + "name": "rareindex", | |
| 3 | + "version": "0.1.0", | |
| 4 | + "private": true, | |
| 5 | + "description": "RareIndex.io — global collectibles market intelligence, search, pricing & index platform", | |
| 6 | + "type": "module", | |
| 7 | + "packageManager": "pnpm@11.1.2", | |
| 8 | + "engines": { | |
| 9 | + "node": ">=22" | |
| 10 | + }, | |
| 11 | + "scripts": { | |
| 12 | + "build": "pnpm -r --filter './packages/**' run build && pnpm --filter @rareindex/api run build && pnpm --filter @rareindex/web run build", | |
| 13 | + "build:packages": "pnpm -r --filter './packages/**' run build", | |
| 14 | + "typecheck": "pnpm -r run typecheck", | |
| 15 | + "test": "pnpm -r run test", | |
| 16 | + "lint": "pnpm -r run lint", | |
| 17 | + "db:generate": "pnpm --filter @rareindex/database run generate", | |
| 18 | + "db:migrate": "pnpm --filter @rareindex/database run migrate", | |
| 19 | + "db:seed": "pnpm --filter @rareindex/database run seed", | |
| 20 | + "dev:web": "pnpm --filter @rareindex/web run dev", | |
| 21 | + "dev:api": "pnpm --filter @rareindex/api run dev", | |
| 22 | + "worker": "tsx workers/main.ts", | |
| 23 | + "ri": "tsx scripts/ri.ts" | |
| 24 | + }, | |
| 25 | + "devDependencies": { | |
| 26 | + "@types/node": "^24.0.0", | |
| 27 | + "tsx": "^4.20.0", | |
| 28 | + "typescript": "^5.9.3", | |
| 29 | + "vitest": "^3.2.0" | |
| 30 | + } | |
| 31 | +} | |
added
packages/connectors/package.json
+32 −0
@@ -0,0 +1,32 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@rareindex/connectors", | |
| 3 | + "version": "0.1.0", | |
| 4 | + "private": true, | |
| 5 | + "type": "module", | |
| 6 | + "exports": { | |
| 7 | + ".": { | |
| 8 | + "types": "./src/index.ts", | |
| 9 | + "default": "./src/index.ts" | |
| 10 | + }, | |
| 11 | + "./testing": { | |
| 12 | + "types": "./src/testing.ts", | |
| 13 | + "default": "./src/testing.ts" | |
| 14 | + } | |
| 15 | + }, | |
| 16 | + "scripts": { | |
| 17 | + "build": "tsc -p tsconfig.json --noEmit", | |
| 18 | + "typecheck": "tsc -p tsconfig.json --noEmit", | |
| 19 | + "test": "vitest run --passWithNoTests" | |
| 20 | + }, | |
| 21 | + "dependencies": { | |
| 22 | + "@rareindex/shared": "workspace:*", | |
| 23 | + "@rareindex/taxonomy": "workspace:*", | |
| 24 | + "cheerio": "^1.1.0", | |
| 25 | + "zod": "^4.0.0" | |
| 26 | + }, | |
| 27 | + "devDependencies": { | |
| 28 | + "@types/node": "^24.0.0", | |
| 29 | + "typescript": "^5.9.3", | |
| 30 | + "vitest": "^3.2.0" | |
| 31 | + } | |
| 32 | +} | |
added
packages/connectors/src/base.ts
+49 −0
@@ -0,0 +1,49 @@ | ||
| 1 | +import { sha256, type ConnectorHealth, type NormalizedRecord } from '@rareindex/shared'; | |
| 2 | +import { healthFromRuns } from './health.js'; | |
| 3 | +import type { ConnectorMeta, CrawlContext, HealthContext, RareIndexConnector, RawRecordInput, RawRecordLike } from './types.js'; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * Convenience base class. Connectors may implement the interface directly; this class adds | |
| 7 | + * rate limiting, checkpointing helpers and a default health check. | |
| 8 | + */ | |
| 9 | +export abstract class BaseConnector implements RareIndexConnector { | |
| 10 | + abstract readonly version: string; | |
| 11 | + abstract readonly parserVersion: string; | |
| 12 | + readonly urlPatterns?: RegExp[]; | |
| 13 | + /** minimum ms between requests to the source (politeness) */ | |
| 14 | + protected minIntervalMs = 500; | |
| 15 | + private lastRequestAt = 0; | |
| 16 | + | |
| 17 | + constructor(public readonly meta: ConnectorMeta) {} | |
| 18 | + | |
| 19 | + abstract crawl(ctx: CrawlContext): AsyncIterable<RawRecordInput>; | |
| 20 | + abstract normalize(raw: RawRecordLike): Promise<NormalizedRecord[]>; | |
| 21 | + | |
| 22 | + async healthCheck(ctx: HealthContext): Promise<ConnectorHealth> { | |
| 23 | + const h = healthFromRuns(ctx, this.meta.schemaVersion); | |
| 24 | + if (ctx.recentRuns.length === 0) { | |
| 25 | + // Fresh connector: light probe of the source root. | |
| 26 | + const res = await ctx.fetch(this.meta.sourceUrl, { engines: ['api'], failOnHttpError: false, responseType: 'text', minQuality: 0 }); | |
| 27 | + h.status = res.httpStatus && res.httpStatus < 500 ? 'unknown' : 'failing'; | |
| 28 | + h.last_error = res.error; | |
| 29 | + } | |
| 30 | + return h; | |
| 31 | + } | |
| 32 | + | |
| 33 | + /** Politeness delay between requests. */ | |
| 34 | + protected async throttle(): Promise<void> { | |
| 35 | + const wait = this.lastRequestAt + this.minIntervalMs - Date.now(); | |
| 36 | + if (wait > 0) await new Promise((r) => setTimeout(r, wait)); | |
| 37 | + this.lastRequestAt = Date.now(); | |
| 38 | + } | |
| 39 | + | |
| 40 | + /** Stable content hash for dedupe of raw payloads. */ | |
| 41 | + protected hash(payload: unknown): string { | |
| 42 | + return sha256(typeof payload === 'string' ? payload : JSON.stringify(payload)); | |
| 43 | + } | |
| 44 | + | |
| 45 | + /** Helper: yield-limit aware counter. */ | |
| 46 | + protected reached(ctx: CrawlContext, count: number): boolean { | |
| 47 | + return ctx.options.limit !== undefined && count >= ctx.options.limit; | |
| 48 | + } | |
| 49 | +} | |
added
packages/connectors/src/context.ts
+94 −0
@@ -0,0 +1,94 @@ | ||
| 1 | +import { childLogger, sha256, type Logger } from '@rareindex/shared'; | |
| 2 | +import type { Router } from './router.js'; | |
| 3 | +import type { ConnectorMeta, CrawlContext, CrawlOptions, EngineStats, FetchOptions, HealthContext } from './types.js'; | |
| 4 | + | |
| 5 | +export interface BudgetStore { | |
| 6 | + /** return previously stored content hash + next due time for url */ | |
| 7 | + get(urlHash: string): Promise<{ contentHash: string | null; nextFetchAt: Date | null } | null>; | |
| 8 | + /** record a fetch outcome; implementation updates change-interval estimate (§170) */ | |
| 9 | + record(input: { urlHash: string; url: string; connectorId: string; contentHash: string | null; changed: boolean; status: number | null }): Promise<void>; | |
| 10 | +} | |
| 11 | + | |
| 12 | +export interface ContextDeps { | |
| 13 | + router: Router; | |
| 14 | + meta: ConnectorMeta; | |
| 15 | + options: CrawlOptions; | |
| 16 | + log?: Logger; | |
| 17 | + budget?: BudgetStore; | |
| 18 | + onCursor?: (cursor: Record<string, unknown>) => Promise<void>; | |
| 19 | + onAnomaly?: (kind: string, detail?: string) => void; | |
| 20 | + signal?: AbortSignal; | |
| 21 | +} | |
| 22 | + | |
| 23 | +/** Build the CrawlContext handed to connectors; wires the router, budget store and stats. */ | |
| 24 | +export function createCrawlContext(deps: ContextDeps): CrawlContext & { anomalies: string[] } { | |
| 25 | + const engineStats: Record<string, EngineStats> = {}; | |
| 26 | + const anomalies: string[] = []; | |
| 27 | + const log = deps.log ?? childLogger({ connector: deps.meta.id }); | |
| 28 | + const fc = deps.router.engines.firecrawl; | |
| 29 | + | |
| 30 | + const ctx: CrawlContext & { anomalies: string[] } = { | |
| 31 | + meta: deps.meta, | |
| 32 | + log, | |
| 33 | + options: deps.options, | |
| 34 | + engineStats, | |
| 35 | + anomalies, | |
| 36 | + signal: deps.signal, | |
| 37 | + async fetch(url: string, opts: FetchOptions = {}) { | |
| 38 | + const res = await deps.router.fetch(url, opts, { enginePriority: deps.meta.enginePriority, stats: engineStats }); | |
| 39 | + if (deps.budget && !opts.force) { | |
| 40 | + const urlHash = sha256(url); | |
| 41 | + const content = res.json !== null && res.json !== undefined ? JSON.stringify(res.json) : (res.html ?? res.markdown ?? ''); | |
| 42 | + const contentHash = content ? sha256(content) : null; | |
| 43 | + const prev = await deps.budget.get(urlHash); | |
| 44 | + await deps.budget.record({ urlHash, url, connectorId: deps.meta.id, contentHash, changed: prev?.contentHash !== contentHash, status: res.httpStatus }); | |
| 45 | + } | |
| 46 | + return res; | |
| 47 | + }, | |
| 48 | + search: fc | |
| 49 | + ? async (query, o = {}) => { | |
| 50 | + const r = await fc.search(query, o); | |
| 51 | + const s = (engineStats.firecrawl ??= { attempts: 0, success: 0, credits: 0, ms: 0 }); | |
| 52 | + s.attempts++; | |
| 53 | + s.success++; | |
| 54 | + s.credits += r.credits; | |
| 55 | + return r.items; | |
| 56 | + } | |
| 57 | + : undefined, | |
| 58 | + map: fc | |
| 59 | + ? async (url, o = {}) => { | |
| 60 | + const r = await fc.map(url, o); | |
| 61 | + const s = (engineStats.firecrawl ??= { attempts: 0, success: 0, credits: 0, ms: 0 }); | |
| 62 | + s.attempts++; | |
| 63 | + s.success++; | |
| 64 | + s.credits += r.credits; | |
| 65 | + return r.links; | |
| 66 | + } | |
| 67 | + : undefined, | |
| 68 | + async shouldFetch(url: string) { | |
| 69 | + if (!deps.budget || deps.options.mode === 'backfill') return true; | |
| 70 | + const prev = await deps.budget.get(sha256(url)); | |
| 71 | + if (!prev || !prev.nextFetchAt) return true; | |
| 72 | + return prev.nextFetchAt.getTime() <= Date.now(); | |
| 73 | + }, | |
| 74 | + async setCursor(cursor) { | |
| 75 | + await deps.onCursor?.(cursor); | |
| 76 | + }, | |
| 77 | + anomaly(kind, detail) { | |
| 78 | + const s = detail ? `${kind}: ${detail}` : kind; | |
| 79 | + anomalies.push(s); | |
| 80 | + deps.onAnomaly?.(kind, detail); | |
| 81 | + log.warn({ kind, detail }, 'connector anomaly'); | |
| 82 | + }, | |
| 83 | + }; | |
| 84 | + return ctx; | |
| 85 | +} | |
| 86 | + | |
| 87 | +export function createHealthContext(deps: { router: Router; meta: ConnectorMeta; recentRuns: HealthContext['recentRuns']; log?: Logger }): HealthContext { | |
| 88 | + return { | |
| 89 | + meta: deps.meta, | |
| 90 | + log: deps.log ?? childLogger({ connector: deps.meta.id }), | |
| 91 | + recentRuns: deps.recentRuns, | |
| 92 | + fetch: (url, opts) => deps.router.fetch(url, opts, { enginePriority: deps.meta.enginePriority }), | |
| 93 | + }; | |
| 94 | +} | |
added
packages/connectors/src/engines/firecrawl.ts
+112 −0
@@ -0,0 +1,112 @@ | ||
| 1 | +import type { ExtractionResult } from '@rareindex/shared'; | |
| 2 | +import type { FetchOptions } from '../types.js'; | |
| 3 | + | |
| 4 | +export interface FirecrawlEngineOptions { | |
| 5 | + apiKey: string; | |
| 6 | + baseUrl?: string; | |
| 7 | + defaultTimeoutMs?: number; | |
| 8 | +} | |
| 9 | + | |
| 10 | +interface FirecrawlScrapeResponse { | |
| 11 | + success: boolean; | |
| 12 | + data?: { | |
| 13 | + markdown?: string; | |
| 14 | + html?: string; | |
| 15 | + rawHtml?: string; | |
| 16 | + json?: unknown; | |
| 17 | + links?: string[]; | |
| 18 | + metadata?: { statusCode?: number; sourceURL?: string; url?: string; title?: string; error?: string; creditsUsed?: number }; | |
| 19 | + }; | |
| 20 | + error?: string; | |
| 21 | + creditsUsed?: number; | |
| 22 | +} | |
| 23 | + | |
| 24 | +/** | |
| 25 | + * Firecrawl v2 REST client (§103). Preferred engine for parseable public pages: returns markdown + | |
| 26 | + * HTML (+ optional JSON extraction with a schema). Never used to bypass access controls (§179). | |
| 27 | + */ | |
| 28 | +export function createFirecrawlEngine(opts: FirecrawlEngineOptions) { | |
| 29 | + const base = (opts.baseUrl ?? 'https://api.firecrawl.dev').replace(/\/$/, ''); | |
| 30 | + const headers = { authorization: `Bearer ${opts.apiKey}`, 'content-type': 'application/json' }; | |
| 31 | + | |
| 32 | + async function post<T>(path: string, body: unknown, timeoutMs: number): Promise<T> { | |
| 33 | + const ctrl = new AbortController(); | |
| 34 | + const timer = setTimeout(() => ctrl.abort(), timeoutMs + 5_000); | |
| 35 | + try { | |
| 36 | + const res = await fetch(`${base}${path}`, { method: 'POST', headers, body: JSON.stringify(body), signal: ctrl.signal }); | |
| 37 | + const text = await res.text(); | |
| 38 | + let json: unknown = null; | |
| 39 | + try { | |
| 40 | + json = JSON.parse(text); | |
| 41 | + } catch { | |
| 42 | + throw new Error(`firecrawl ${path} HTTP ${res.status}: ${text.slice(0, 200)}`); | |
| 43 | + } | |
| 44 | + if (!res.ok) { | |
| 45 | + const msg = (json as { error?: string })?.error ?? text.slice(0, 200); | |
| 46 | + throw new Error(`firecrawl ${path} HTTP ${res.status}: ${msg}`); | |
| 47 | + } | |
| 48 | + return json as T; | |
| 49 | + } finally { | |
| 50 | + clearTimeout(timer); | |
| 51 | + } | |
| 52 | + } | |
| 53 | + | |
| 54 | + async function scrape(url: string, o: FetchOptions = {}): Promise<ExtractionResult> { | |
| 55 | + const started = Date.now(); | |
| 56 | + const timeoutMs = o.timeoutMs ?? opts.defaultTimeoutMs ?? 60_000; | |
| 57 | + const formats: unknown[] = ['markdown', 'html']; | |
| 58 | + if (o.jsonSchema || o.jsonPrompt) formats.push({ type: 'json', ...(o.jsonSchema ? { schema: o.jsonSchema } : {}), ...(o.jsonPrompt ? { prompt: o.jsonPrompt } : {}) }); | |
| 59 | + const body: Record<string, unknown> = { | |
| 60 | + url, | |
| 61 | + formats, | |
| 62 | + onlyMainContent: false, | |
| 63 | + timeout: timeoutMs, | |
| 64 | + ...(o.waitForMs ? { waitFor: o.waitForMs } : {}), | |
| 65 | + ...(o.country ? { location: { country: o.country.toUpperCase() } } : {}), | |
| 66 | + ...(o.headers ? { headers: o.headers } : {}), | |
| 67 | + }; | |
| 68 | + try { | |
| 69 | + const r = await post<FirecrawlScrapeResponse>('/v2/scrape', body, timeoutMs); | |
| 70 | + const d = r.data; | |
| 71 | + const status = d?.metadata?.statusCode ?? null; | |
| 72 | + const ok = Boolean(r.success && d && (status === null || status < 400)); | |
| 73 | + return { | |
| 74 | + success: ok, | |
| 75 | + engine: 'firecrawl', | |
| 76 | + url, | |
| 77 | + finalUrl: d?.metadata?.url ?? d?.metadata?.sourceURL ?? null, | |
| 78 | + httpStatus: status, | |
| 79 | + html: d?.html ?? d?.rawHtml ?? null, | |
| 80 | + markdown: d?.markdown ?? null, | |
| 81 | + json: d?.json ?? null, | |
| 82 | + qualityScore: 0, | |
| 83 | + requiresReview: false, | |
| 84 | + error: ok ? null : (r.error ?? d?.metadata?.error ?? `status ${status}`), | |
| 85 | + costCredits: r.creditsUsed ?? d?.metadata?.creditsUsed ?? 1, | |
| 86 | + durationMs: Date.now() - started, | |
| 87 | + fetchedAt: new Date(), | |
| 88 | + }; | |
| 89 | + } catch (err) { | |
| 90 | + return { success: false, engine: 'firecrawl', url, finalUrl: null, httpStatus: null, html: null, markdown: null, json: null, qualityScore: 0, requiresReview: false, error: err instanceof Error ? err.message : String(err), costCredits: 0, durationMs: Date.now() - started, fetchedAt: new Date() }; | |
| 91 | + } | |
| 92 | + } | |
| 93 | + | |
| 94 | + async function search(query: string, o: { limit?: number; scrape?: boolean; country?: string; tbs?: string } = {}) { | |
| 95 | + const body: Record<string, unknown> = { query, limit: o.limit ?? 10, ...(o.country ? { country: o.country } : {}), ...(o.tbs ? { tbs: o.tbs } : {}) }; | |
| 96 | + if (o.scrape) body.scrapeOptions = { formats: ['markdown'] }; | |
| 97 | + const r = await post<{ success: boolean; data?: { web?: Array<{ url: string; title?: string; description?: string; markdown?: string }> } | Array<{ url: string; title?: string; description?: string; markdown?: string }>; creditsUsed?: number }>('/v2/search', body, 60_000); | |
| 98 | + const data = r.data; | |
| 99 | + const items = Array.isArray(data) ? data : (data?.web ?? []); | |
| 100 | + return { items, credits: r.creditsUsed ?? items.length }; | |
| 101 | + } | |
| 102 | + | |
| 103 | + async function map(url: string, o: { search?: string; limit?: number } = {}) { | |
| 104 | + const r = await post<{ success: boolean; links?: Array<string | { url: string }>; creditsUsed?: number }>('/v2/map', { url, limit: o.limit ?? 5000, ...(o.search ? { search: o.search } : {}) }, 60_000); | |
| 105 | + const links = (r.links ?? []).map((l) => (typeof l === 'string' ? l : l.url)); | |
| 106 | + return { links, credits: r.creditsUsed ?? 1 }; | |
| 107 | + } | |
| 108 | + | |
| 109 | + return { scrape, search, map }; | |
| 110 | +} | |
| 111 | + | |
| 112 | +export type FirecrawlEngine = ReturnType<typeof createFirecrawlEngine>; | |
added
packages/connectors/src/engines/http.ts
+100 −0
@@ -0,0 +1,100 @@ | ||
| 1 | +import type { ExtractionResult } from '@rareindex/shared'; | |
| 2 | +import type { FetchOptions } from '../types.js'; | |
| 3 | + | |
| 4 | +const DEFAULT_UA = 'RareIndexBot/0.1 (+https://www.rareindex.io/about/data; market-data research; contact: data@rareindex.io)'; | |
| 5 | + | |
| 6 | +export interface HttpEngineOptions { | |
| 7 | + userAgent?: string; | |
| 8 | + defaultTimeoutMs?: number; | |
| 9 | + maxRetries?: number; | |
| 10 | +} | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * Direct HTTP engine for official APIs, feeds and plain public pages. Honest user agent, no | |
| 14 | + * evasion, exponential backoff on 429/5xx, and conditional requests when the caller passes | |
| 15 | + * If-None-Match / If-Modified-Since headers (budget engine). | |
| 16 | + */ | |
| 17 | +export function createHttpEngine(opts: HttpEngineOptions = {}) { | |
| 18 | + const ua = opts.userAgent ?? DEFAULT_UA; | |
| 19 | + const maxRetries = opts.maxRetries ?? 3; | |
| 20 | + | |
| 21 | + async function fetchUrl(url: string, o: FetchOptions = {}): Promise<ExtractionResult> { | |
| 22 | + const started = Date.now(); | |
| 23 | + const timeoutMs = o.timeoutMs ?? opts.defaultTimeoutMs ?? 30_000; | |
| 24 | + let attempt = 0; | |
| 25 | + let lastErr: string | null = null; | |
| 26 | + while (attempt <= maxRetries) { | |
| 27 | + attempt++; | |
| 28 | + const ctrl = new AbortController(); | |
| 29 | + const timer = setTimeout(() => ctrl.abort(), timeoutMs); | |
| 30 | + try { | |
| 31 | + const res = await fetch(url, { | |
| 32 | + method: o.method ?? 'GET', | |
| 33 | + headers: { | |
| 34 | + 'user-agent': ua, | |
| 35 | + accept: o.responseType === 'text' ? 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' : 'application/json, text/plain, */*', | |
| 36 | + 'accept-language': 'en-US,en;q=0.9', | |
| 37 | + ...(o.body !== undefined ? { 'content-type': 'application/json' } : {}), | |
| 38 | + ...(o.headers ?? {}), | |
| 39 | + }, | |
| 40 | + body: o.body !== undefined ? JSON.stringify(o.body) : undefined, | |
| 41 | + signal: ctrl.signal, | |
| 42 | + redirect: 'follow', | |
| 43 | + }); | |
| 44 | + clearTimeout(timer); | |
| 45 | + const status = res.status; | |
| 46 | + if (status === 304) { | |
| 47 | + return { success: true, engine: 'api', url, finalUrl: res.url, httpStatus: 304, html: null, markdown: null, json: null, qualityScore: 1, requiresReview: false, error: null, costCredits: 0, durationMs: Date.now() - started, fetchedAt: new Date() }; | |
| 48 | + } | |
| 49 | + if ((status === 429 || status >= 500) && attempt <= maxRetries) { | |
| 50 | + const retryAfter = Number(res.headers.get('retry-after')); | |
| 51 | + const wait = Number.isFinite(retryAfter) && retryAfter > 0 ? retryAfter * 1000 : Math.min(30_000, 1000 * 2 ** attempt); | |
| 52 | + lastErr = `HTTP ${status}`; | |
| 53 | + await new Promise((r) => setTimeout(r, wait)); | |
| 54 | + continue; | |
| 55 | + } | |
| 56 | + const ctype = res.headers.get('content-type') ?? ''; | |
| 57 | + const isJson = o.responseType !== 'text' && (ctype.includes('json') || o.responseType === 'json'); | |
| 58 | + let json: unknown = null; | |
| 59 | + let text: string | null = null; | |
| 60 | + if (isJson) { | |
| 61 | + const raw = await res.text(); | |
| 62 | + try { | |
| 63 | + json = raw ? JSON.parse(raw) : null; | |
| 64 | + } catch { | |
| 65 | + text = raw; | |
| 66 | + } | |
| 67 | + } else { | |
| 68 | + text = await res.text(); | |
| 69 | + } | |
| 70 | + const ok = res.ok && (o.failOnHttpError === false || status < 400); | |
| 71 | + return { | |
| 72 | + success: ok, | |
| 73 | + engine: 'api', | |
| 74 | + url, | |
| 75 | + finalUrl: res.url, | |
| 76 | + httpStatus: status, | |
| 77 | + html: text, | |
| 78 | + markdown: null, | |
| 79 | + json, | |
| 80 | + qualityScore: ok ? 1 : 0, | |
| 81 | + requiresReview: false, | |
| 82 | + error: ok ? null : `HTTP ${status}`, | |
| 83 | + costCredits: 0, | |
| 84 | + durationMs: Date.now() - started, | |
| 85 | + fetchedAt: new Date(), | |
| 86 | + }; | |
| 87 | + } catch (err) { | |
| 88 | + clearTimeout(timer); | |
| 89 | + lastErr = err instanceof Error ? err.message : String(err); | |
| 90 | + if (attempt > maxRetries) break; | |
| 91 | + await new Promise((r) => setTimeout(r, Math.min(15_000, 500 * 2 ** attempt))); | |
| 92 | + } | |
| 93 | + } | |
| 94 | + return { success: false, engine: 'api', url, finalUrl: null, httpStatus: null, html: null, markdown: null, json: null, qualityScore: 0, requiresReview: false, error: lastErr ?? 'fetch failed', costCredits: 0, durationMs: Date.now() - started, fetchedAt: new Date() }; | |
| 95 | + } | |
| 96 | + | |
| 97 | + return { fetch: fetchUrl }; | |
| 98 | +} | |
| 99 | + | |
| 100 | +export type HttpEngine = ReturnType<typeof createHttpEngine>; | |
added
packages/connectors/src/engines/scrapfly.ts
+113 −0
@@ -0,0 +1,113 @@ | ||
| 1 | +import type { ExtractionResult } from '@rareindex/shared'; | |
| 2 | +import type { FetchOptions } from '../types.js'; | |
| 3 | + | |
| 4 | +export interface ScrapflyEngineOptions { | |
| 5 | + apiKey: string; | |
| 6 | + baseUrl?: string; | |
| 7 | + defaultCountry?: string; | |
| 8 | + defaultTimeoutMs?: number; | |
| 9 | +} | |
| 10 | + | |
| 11 | +interface ScrapflyResponse { | |
| 12 | + result?: { | |
| 13 | + content?: string; | |
| 14 | + status_code?: number; | |
| 15 | + url?: string; | |
| 16 | + success?: boolean; | |
| 17 | + error?: { message?: string; code?: string } | null; | |
| 18 | + format?: string; | |
| 19 | + extracted_data?: { data?: unknown } | unknown; | |
| 20 | + }; | |
| 21 | + context?: { cost?: { total?: number } }; | |
| 22 | + config?: Record<string, unknown>; | |
| 23 | + cost?: number; | |
| 24 | + message?: string; | |
| 25 | +} | |
| 26 | + | |
| 27 | +/** | |
| 28 | + * Scrapfly REST client (§104): secondary engine for JS-heavy or difficult public pages, with | |
| 29 | + * geo routing and rendering. `asp` (anti-scraping protection) is only used on publicly accessible | |
| 30 | + * pages within the source's terms — never to defeat logins, paywalls or CAPTCHAs (§179). | |
| 31 | + */ | |
| 32 | +export function createScrapflyEngine(opts: ScrapflyEngineOptions) { | |
| 33 | + const base = (opts.baseUrl ?? 'https://api.scrapfly.io').replace(/\/$/, ''); | |
| 34 | + | |
| 35 | + async function scrape(url: string, o: FetchOptions = {}): Promise<ExtractionResult> { | |
| 36 | + const started = Date.now(); | |
| 37 | + const timeoutMs = o.timeoutMs ?? opts.defaultTimeoutMs ?? 90_000; | |
| 38 | + const params = new URLSearchParams({ | |
| 39 | + key: opts.apiKey, | |
| 40 | + url, | |
| 41 | + asp: 'true', | |
| 42 | + render_js: o.renderJs === false ? 'false' : 'true', | |
| 43 | + country: (o.country ?? opts.defaultCountry ?? 'us').toLowerCase(), | |
| 44 | + retry: 'true', | |
| 45 | + format: 'raw', | |
| 46 | + }); | |
| 47 | + if (o.waitForMs) params.set('rendering_wait', String(Math.min(o.waitForMs, 25_000))); | |
| 48 | + if (o.extractionModel) params.set('extraction_model', o.extractionModel); | |
| 49 | + if (o.headers) for (const [k, v] of Object.entries(o.headers)) params.append(`headers[${k}]`, v); | |
| 50 | + if (o.method === 'POST') params.set('method', 'POST'); | |
| 51 | + const ctrl = new AbortController(); | |
| 52 | + const timer = setTimeout(() => ctrl.abort(), timeoutMs + 5_000); | |
| 53 | + try { | |
| 54 | + const res = await fetch(`${base}/scrape?${params.toString()}`, { | |
| 55 | + method: o.method === 'POST' ? 'POST' : 'GET', | |
| 56 | + body: o.method === 'POST' && o.body !== undefined ? JSON.stringify(o.body) : undefined, | |
| 57 | + headers: o.method === 'POST' ? { 'content-type': 'application/json' } : undefined, | |
| 58 | + signal: ctrl.signal, | |
| 59 | + }); | |
| 60 | + const text = await res.text(); | |
| 61 | + let json: ScrapflyResponse | null = null; | |
| 62 | + try { | |
| 63 | + json = JSON.parse(text) as ScrapflyResponse; | |
| 64 | + } catch { | |
| 65 | + return fail(`scrapfly HTTP ${res.status}: ${text.slice(0, 200)}`, started, url); | |
| 66 | + } | |
| 67 | + const r = json.result; | |
| 68 | + const status = r?.status_code ?? null; | |
| 69 | + const cost = json.context?.cost?.total ?? json.cost ?? 1; | |
| 70 | + if (!res.ok || !r) return fail(`scrapfly HTTP ${res.status}: ${json.message ?? r?.error?.message ?? 'no result'}`, started, url, cost); | |
| 71 | + const ok = Boolean(r.success !== false && (status === null || status < 400)); | |
| 72 | + const content = r.content ?? null; | |
| 73 | + const extracted = (r.extracted_data as { data?: unknown } | undefined)?.data ?? r.extracted_data ?? null; | |
| 74 | + const looksJson = content && /^\s*[[{]/.test(content); | |
| 75 | + let parsed: unknown = extracted; | |
| 76 | + if (!parsed && looksJson) { | |
| 77 | + try { | |
| 78 | + parsed = JSON.parse(content!); | |
| 79 | + } catch { | |
| 80 | + parsed = null; | |
| 81 | + } | |
| 82 | + } | |
| 83 | + return { | |
| 84 | + success: ok, | |
| 85 | + engine: 'scrapfly', | |
| 86 | + url, | |
| 87 | + finalUrl: r.url ?? null, | |
| 88 | + httpStatus: status, | |
| 89 | + html: content, | |
| 90 | + markdown: null, | |
| 91 | + json: parsed, | |
| 92 | + qualityScore: 0, | |
| 93 | + requiresReview: false, | |
| 94 | + error: ok ? null : (r.error?.message ?? `status ${status}`), | |
| 95 | + costCredits: cost, | |
| 96 | + durationMs: Date.now() - started, | |
| 97 | + fetchedAt: new Date(), | |
| 98 | + }; | |
| 99 | + } catch (err) { | |
| 100 | + return fail(err instanceof Error ? err.message : String(err), started, url); | |
| 101 | + } finally { | |
| 102 | + clearTimeout(timer); | |
| 103 | + } | |
| 104 | + } | |
| 105 | + | |
| 106 | + function fail(error: string, started: number, url: string, cost = 0): ExtractionResult { | |
| 107 | + return { success: false, engine: 'scrapfly', url, finalUrl: null, httpStatus: null, html: null, markdown: null, json: null, qualityScore: 0, requiresReview: false, error, costCredits: cost, durationMs: Date.now() - started, fetchedAt: new Date() }; | |
| 108 | + } | |
| 109 | + | |
| 110 | + return { scrape }; | |
| 111 | +} | |
| 112 | + | |
| 113 | +export type ScrapflyEngine = ReturnType<typeof createScrapflyEngine>; | |
added
packages/connectors/src/health.ts
+88 −0
@@ -0,0 +1,88 @@ | ||
| 1 | +import type { ConnectorHealth } from '@rareindex/shared'; | |
| 2 | +import type { HealthContext } from './types.js'; | |
| 3 | + | |
| 4 | +/** | |
| 5 | + * Derive a ConnectorHealth snapshot (§105) from recent runs. Anomaly detectors that need data | |
| 6 | + * distributions (price drift, duplicate explosion) run in the normalizer and are passed in as | |
| 7 | + * run anomalies. | |
| 8 | + */ | |
| 9 | +export function healthFromRuns(ctx: HealthContext, schemaVersion: string): ConnectorHealth { | |
| 10 | + const now = Date.now(); | |
| 11 | + const runs24h = ctx.recentRuns.filter((r) => now - r.startedAt.getTime() <= 24 * 3600_000); | |
| 12 | + const attempted = runs24h.reduce((a, r) => a + r.pagesAttempted, 0); | |
| 13 | + const success = runs24h.reduce((a, r) => a + r.pagesSuccess, 0); | |
| 14 | + const rawRecords = runs24h.reduce((a, r) => a + r.recordsRaw, 0); | |
| 15 | + const dupes = runs24h.reduce((a, r) => a + r.recordsDuplicate, 0); | |
| 16 | + const fc = sumEngine(runs24h, 'firecrawl'); | |
| 17 | + const sf = sumEngine(runs24h, 'scrapfly'); | |
| 18 | + const lastOk = [...ctx.recentRuns].reverse().find((r) => r.status === 'success' || r.status === 'partial'); | |
| 19 | + const lastErr = [...ctx.recentRuns].reverse().find((r) => r.error)?.error ?? null; | |
| 20 | + const anomalies = [...new Set(runs24h.flatMap((r) => r.anomalies))]; | |
| 21 | + const successRate = attempted > 0 ? success / attempted : null; | |
| 22 | + const failing = ctx.recentRuns.slice(-3).length >= 3 && ctx.recentRuns.slice(-3).every((r) => r.status === 'failed'); | |
| 23 | + | |
| 24 | + let status: ConnectorHealth['status'] = 'unknown'; | |
| 25 | + if (ctx.recentRuns.length === 0) status = 'unknown'; | |
| 26 | + else if (failing) status = 'failing'; | |
| 27 | + else if (successRate !== null && successRate < 0.5) status = 'failing'; | |
| 28 | + else if ((successRate !== null && successRate < 0.85) || anomalies.length > 0) status = 'degraded'; | |
| 29 | + else status = 'healthy'; | |
| 30 | + | |
| 31 | + return { | |
| 32 | + connector: ctx.meta.id, | |
| 33 | + status, | |
| 34 | + success_rate_24h: successRate === null ? null : round3(successRate), | |
| 35 | + pages_attempted: attempted, | |
| 36 | + pages_success: success, | |
| 37 | + firecrawl_success_rate: fc.attempts ? round3(fc.success / fc.attempts) : null, | |
| 38 | + scrapfly_fallback_rate: attempted ? round3(sf.attempts / attempted) : null, | |
| 39 | + parse_failure_rate: rawRecords ? round3(runs24h.reduce((a, r) => a + (r.anomalies.filter((x) => x.startsWith('parse_failure')).length), 0) / rawRecords) : null, | |
| 40 | + last_success: lastOk ? lastOk.startedAt.toISOString() : null, | |
| 41 | + last_error: lastErr, | |
| 42 | + schema_version: schemaVersion, | |
| 43 | + records_24h: rawRecords, | |
| 44 | + duplicates_24h: dupes, | |
| 45 | + anomalies, | |
| 46 | + }; | |
| 47 | +} | |
| 48 | + | |
| 49 | +function sumEngine(runs: HealthContext['recentRuns'], engine: string) { | |
| 50 | + return runs.reduce( | |
| 51 | + (acc, r) => { | |
| 52 | + const s = r.engineStats[engine]; | |
| 53 | + if (s) { | |
| 54 | + acc.attempts += s.attempts; | |
| 55 | + acc.success += s.success; | |
| 56 | + } | |
| 57 | + return acc; | |
| 58 | + }, | |
| 59 | + { attempts: 0, success: 0 }, | |
| 60 | + ); | |
| 61 | +} | |
| 62 | + | |
| 63 | +function round3(x: number): number { | |
| 64 | + return Math.round(x * 1000) / 1000; | |
| 65 | +} | |
| 66 | + | |
| 67 | +/** | |
| 68 | + * Detect abnormal price distributions between a baseline and a new batch (§105): median shift | |
| 69 | + * beyond a factor or a collapse of dispersion suggests a parser/currency problem. | |
| 70 | + */ | |
| 71 | +export function priceDistributionAnomaly(baseline: number[], batch: number[], factor = 3): string | null { | |
| 72 | + if (baseline.length < 20 || batch.length < 10) return null; | |
| 73 | + const med = (xs: number[]) => { | |
| 74 | + const s = [...xs].sort((a, b) => a - b); | |
| 75 | + return s[Math.floor(s.length / 2)]!; | |
| 76 | + }; | |
| 77 | + const b = med(baseline); | |
| 78 | + const n = med(batch); | |
| 79 | + if (b > 0 && (n / b > factor || b / n > factor)) return `price_distribution_shift: median ${b.toFixed(2)} → ${n.toFixed(2)}`; | |
| 80 | + return null; | |
| 81 | +} | |
| 82 | + | |
| 83 | +/** Duplicate explosion: share of duplicate raw records in a run is far above baseline. */ | |
| 84 | +export function duplicateExplosion(records: number, duplicates: number, threshold = 0.9): string | null { | |
| 85 | + if (records < 50) return null; | |
| 86 | + const share = duplicates / records; | |
| 87 | + return share >= threshold ? `duplicate_explosion: ${(share * 100).toFixed(0)}% duplicates` : null; | |
| 88 | +} | |
added
packages/connectors/src/html.ts
+87 −0
@@ -0,0 +1,87 @@ | ||
| 1 | +import * as cheerio from 'cheerio'; | |
| 2 | + | |
| 3 | +/** Thin HTML helpers shared by connectors (cheerio). */ | |
| 4 | +export function load(html: string) { | |
| 5 | + return cheerio.load(html); | |
| 6 | +} | |
| 7 | + | |
| 8 | +export type CheerioRoot = ReturnType<typeof cheerio.load>; | |
| 9 | + | |
| 10 | +export function text($el: { text(): string } | null | undefined): string | null { | |
| 11 | + const t = $el?.text()?.replace(/\s+/g, ' ').trim(); | |
| 12 | + return t ? t : null; | |
| 13 | +} | |
| 14 | + | |
| 15 | +export function absUrl(base: string, href: string | null | undefined): string | null { | |
| 16 | + if (!href) return null; | |
| 17 | + try { | |
| 18 | + return new URL(href, base).toString(); | |
| 19 | + } catch { | |
| 20 | + return null; | |
| 21 | + } | |
| 22 | +} | |
| 23 | + | |
| 24 | +/** Extract JSON-LD blocks of a given @type (e.g. Product, Offer) from HTML. */ | |
| 25 | +export function jsonLd(html: string, type?: string): Record<string, unknown>[] { | |
| 26 | + const $ = cheerio.load(html); | |
| 27 | + const out: Record<string, unknown>[] = []; | |
| 28 | + $('script[type="application/ld+json"]').each((_, el) => { | |
| 29 | + const raw = $(el).contents().text(); | |
| 30 | + try { | |
| 31 | + const parsed = JSON.parse(raw) as unknown; | |
| 32 | + const items = Array.isArray(parsed) ? parsed : (parsed && typeof parsed === 'object' && '@graph' in (parsed as object) ? ((parsed as { '@graph': unknown[] })['@graph'] ?? []) : [parsed]); | |
| 33 | + for (const it of items) { | |
| 34 | + if (it && typeof it === 'object') { | |
| 35 | + const t = (it as { '@type'?: string | string[] })['@type']; | |
| 36 | + const types = Array.isArray(t) ? t : t ? [t] : []; | |
| 37 | + if (!type || types.includes(type)) out.push(it as Record<string, unknown>); | |
| 38 | + } | |
| 39 | + } | |
| 40 | + } catch { | |
| 41 | + /* ignore malformed JSON-LD */ | |
| 42 | + } | |
| 43 | + }); | |
| 44 | + return out; | |
| 45 | +} | |
| 46 | + | |
| 47 | +/** Extract Next.js __NEXT_DATA__ payload when present. */ | |
| 48 | +export function nextData(html: string): unknown | null { | |
| 49 | + const m = html.match(/<script id="__NEXT_DATA__"[^>]*>([\s\S]*?)<\/script>/); | |
| 50 | + if (!m) return null; | |
| 51 | + try { | |
| 52 | + return JSON.parse(m[1]!); | |
| 53 | + } catch { | |
| 54 | + return null; | |
| 55 | + } | |
| 56 | +} | |
| 57 | + | |
| 58 | +/** Extract a JS object literal assigned to a global, e.g. window.__INITIAL_STATE__ = {...}; */ | |
| 59 | +export function inlineJson(html: string, marker: string): unknown | null { | |
| 60 | + const idx = html.indexOf(marker); | |
| 61 | + if (idx < 0) return null; | |
| 62 | + const start = html.indexOf('{', idx); | |
| 63 | + if (start < 0) return null; | |
| 64 | + let depth = 0; | |
| 65 | + let inStr: string | null = null; | |
| 66 | + for (let i = start; i < html.length; i++) { | |
| 67 | + const ch = html[i]!; | |
| 68 | + if (inStr) { | |
| 69 | + if (ch === '\\') i++; | |
| 70 | + else if (ch === inStr) inStr = null; | |
| 71 | + continue; | |
| 72 | + } | |
| 73 | + if (ch === '"' || ch === "'") inStr = ch; | |
| 74 | + else if (ch === '{') depth++; | |
| 75 | + else if (ch === '}') { | |
| 76 | + depth--; | |
| 77 | + if (depth === 0) { | |
| 78 | + try { | |
| 79 | + return JSON.parse(html.slice(start, i + 1)); | |
| 80 | + } catch { | |
| 81 | + return null; | |
| 82 | + } | |
| 83 | + } | |
| 84 | + } | |
| 85 | + } | |
| 86 | + return null; | |
| 87 | +} | |
added
packages/connectors/src/index.ts
+11 −0
@@ -0,0 +1,11 @@ | ||
| 1 | +export * from './types.js'; | |
| 2 | +export * from './quality.js'; | |
| 3 | +export * from './router.js'; | |
| 4 | +export * from './health.js'; | |
| 5 | +export * from './registry.js'; | |
| 6 | +export * from './base.js'; | |
| 7 | +export * from './context.js'; | |
| 8 | +export * as html from './html.js'; | |
| 9 | +export { createHttpEngine } from './engines/http.js'; | |
| 10 | +export { createFirecrawlEngine } from './engines/firecrawl.js'; | |
| 11 | +export { createScrapflyEngine } from './engines/scrapfly.js'; | |
added
packages/connectors/src/quality.test.ts
+34 −0
@@ -0,0 +1,34 @@ | ||
| 1 | +import { describe, expect, it } from 'vitest'; | |
| 2 | +import { qualityScore, documentQuality } from './quality.js'; | |
| 3 | +import { healthFromRuns } from './health.js'; | |
| 4 | +import { childLogger } from '@rareindex/shared'; | |
| 5 | +import type { ConnectorMeta } from './types.js'; | |
| 6 | + | |
| 7 | +const meta = { id: 'x', schemaVersion: '1.0' } as unknown as ConnectorMeta; | |
| 8 | + | |
| 9 | +describe('quality', () => { | |
| 10 | + it('scores expected fields', () => { | |
| 11 | + expect(qualityScore({ title: 'a', price: 1, status: 'sold', date: new Date(), images: ['u'], description: 'd', identifiers: { a: 'b' }, category: 'c', currency: 'USD' })).toBe(1); | |
| 12 | + expect(qualityScore({ title: 'a' }, ['title', 'price'])).toBe(0.5); | |
| 13 | + expect(qualityScore(null)).toBe(0); | |
| 14 | + }); | |
| 15 | + it('flags blocked documents', () => { | |
| 16 | + expect(documentQuality({ html: 'Just a moment... Cloudflare', httpStatus: 200 })).toBeLessThan(0.5); | |
| 17 | + expect(documentQuality({ html: 'x'.repeat(5000), httpStatus: 200 })).toBeGreaterThanOrEqual(0.8); | |
| 18 | + expect(documentQuality({ html: 'x'.repeat(5000), httpStatus: 403 })).toBe(0); | |
| 19 | + }); | |
| 20 | + it('derives health', () => { | |
| 21 | + const h = healthFromRuns( | |
| 22 | + { | |
| 23 | + meta, | |
| 24 | + log: childLogger({}), | |
| 25 | + fetch: async () => ({}) as never, | |
| 26 | + recentRuns: [{ startedAt: new Date(), status: 'success', pagesAttempted: 100, pagesSuccess: 98, recordsRaw: 500, recordsDuplicate: 20, engineStats: { firecrawl: { attempts: 100, success: 91, credits: 100, ms: 1 }, scrapfly: { attempts: 7, success: 7, credits: 7, ms: 1 } }, anomalies: [], error: null }], | |
| 27 | + }, | |
| 28 | + '1.0', | |
| 29 | + ); | |
| 30 | + expect(h.status).toBe('healthy'); | |
| 31 | + expect(h.success_rate_24h).toBe(0.98); | |
| 32 | + expect(h.scrapfly_fallback_rate).toBe(0.07); | |
| 33 | + }); | |
| 34 | +}); | |
added
packages/connectors/src/quality.ts
+58 −0
@@ -0,0 +1,58 @@ | ||
| 1 | +import type { QualityField } from './types.js'; | |
| 2 | + | |
| 3 | +/** Extraction quality weights (§199). */ | |
| 4 | +export const QUALITY_WEIGHTS: Record<QualityField, number> = { | |
| 5 | + title: 0.2, | |
| 6 | + price: 0.2, | |
| 7 | + status: 0.15, | |
| 8 | + date: 0.1, | |
| 9 | + images: 0.1, | |
| 10 | + description: 0.05, | |
| 11 | + identifiers: 0.1, | |
| 12 | + category: 0.05, | |
| 13 | + currency: 0.05, | |
| 14 | +}; | |
| 15 | + | |
| 16 | +export const MIN_QUALITY = 0.6; | |
| 17 | + | |
| 18 | +function present(v: unknown): boolean { | |
| 19 | + if (v === null || v === undefined) return false; | |
| 20 | + if (typeof v === 'string') return v.trim().length > 0; | |
| 21 | + if (Array.isArray(v)) return v.length > 0; | |
| 22 | + if (typeof v === 'number') return Number.isFinite(v); | |
| 23 | + if (v instanceof Date) return !Number.isNaN(v.getTime()); | |
| 24 | + if (typeof v === 'object') return Object.keys(v as object).length > 0; | |
| 25 | + return Boolean(v); | |
| 26 | +} | |
| 27 | + | |
| 28 | +/** | |
| 29 | + * Score 0–1 = weighted share of expected fields that were found. When `expect` is omitted all | |
| 30 | + * weighted fields count; otherwise weights are renormalised over the expected subset so that a | |
| 31 | + * catalog page (no price/status) can still reach 1.0. | |
| 32 | + */ | |
| 33 | +export function qualityScore(found: Partial<Record<QualityField, unknown>> | null | undefined, expect?: QualityField[]): number { | |
| 34 | + if (!found) return 0; | |
| 35 | + const fields = (expect && expect.length ? expect : (Object.keys(QUALITY_WEIGHTS) as QualityField[])); | |
| 36 | + let total = 0; | |
| 37 | + let got = 0; | |
| 38 | + for (const f of fields) { | |
| 39 | + const w = QUALITY_WEIGHTS[f] ?? 0; | |
| 40 | + total += w; | |
| 41 | + if (present(found[f])) got += w; | |
| 42 | + } | |
| 43 | + return total > 0 ? Math.round((got / total) * 1000) / 1000 : 0; | |
| 44 | +} | |
| 45 | + | |
| 46 | +/** Heuristic score for a document when the connector provides no parser: did we get real content? */ | |
| 47 | +export function documentQuality(doc: { html?: string | null; markdown?: string | null; json?: unknown; httpStatus?: number | null }): number { | |
| 48 | + if (doc.httpStatus && (doc.httpStatus >= 400 || doc.httpStatus === 0)) return 0; | |
| 49 | + if (doc.json && present(doc.json)) return 0.9; | |
| 50 | + const text = doc.markdown ?? doc.html ?? ''; | |
| 51 | + if (!text) return 0; | |
| 52 | + const len = text.length; | |
| 53 | + const blocked = /access denied|captcha|verify you are human|attention required|cloudflare|just a moment|request blocked|unusual traffic|enable javascript and cookies/i.test(text.slice(0, 4000)); | |
| 54 | + if (blocked && len < 20_000) return 0.1; | |
| 55 | + if (len < 500) return 0.2; | |
| 56 | + if (len < 2_000) return 0.5; | |
| 57 | + return 0.8; | |
| 58 | +} | |
added
packages/connectors/src/registry.ts
+62 −0
@@ -0,0 +1,62 @@ | ||
| 1 | +import { readFileSync } from 'node:fs'; | |
| 2 | +import path from 'node:path'; | |
| 3 | +import { fileURLToPath } from 'node:url'; | |
| 4 | +import { RegistrySchema, type ConnectorMeta, type Registry, type RareIndexConnector } from './types.js'; | |
| 5 | + | |
| 6 | +const here = path.dirname(fileURLToPath(import.meta.url)); | |
| 7 | +export const CONNECTORS_DIR = path.resolve(here, '../../../connectors'); | |
| 8 | +export const REGISTRY_PATH = path.join(CONNECTORS_DIR, 'registry.json'); | |
| 9 | + | |
| 10 | +let cached: Registry | null = null; | |
| 11 | + | |
| 12 | +/** Load and validate connectors/registry.json (§106). */ | |
| 13 | +export function loadRegistry(force = false): Registry { | |
| 14 | + if (cached && !force) return cached; | |
| 15 | + const raw = JSON.parse(readFileSync(REGISTRY_PATH, 'utf8')); | |
| 16 | + cached = RegistrySchema.parse(raw); | |
| 17 | + const ids = new Set<string>(); | |
| 18 | + for (const c of cached.connectors) { | |
| 19 | + if (ids.has(c.id)) throw new Error(`registry: duplicate connector id ${c.id}`); | |
| 20 | + ids.add(c.id); | |
| 21 | + } | |
| 22 | + return cached; | |
| 23 | +} | |
| 24 | + | |
| 25 | +export function getConnectorMeta(id: string): ConnectorMeta { | |
| 26 | + const meta = loadRegistry().connectors.find((c) => c.id === id); | |
| 27 | + if (!meta) throw new Error(`Unknown connector: ${id}`); | |
| 28 | + return meta; | |
| 29 | +} | |
| 30 | + | |
| 31 | +export function listConnectorMeta(filter: { enabled?: boolean; category?: string; sourceType?: string } = {}): ConnectorMeta[] { | |
| 32 | + return loadRegistry().connectors.filter((c) => { | |
| 33 | + if (filter.enabled !== undefined && c.enabled !== filter.enabled) return false; | |
| 34 | + if (filter.category && !c.categories.includes(filter.category)) return false; | |
| 35 | + if (filter.sourceType && c.sourceType !== filter.sourceType) return false; | |
| 36 | + return true; | |
| 37 | + }); | |
| 38 | +} | |
| 39 | + | |
| 40 | +/** | |
| 41 | + * Dynamically import a connector module. Each module default-exports a factory | |
| 42 | + * `(meta: ConnectorMeta) => RareIndexConnector`. | |
| 43 | + */ | |
| 44 | +export async function loadConnector(id: string): Promise<RareIndexConnector> { | |
| 45 | + const meta = getConnectorMeta(id); | |
| 46 | + const modPath = path.join(CONNECTORS_DIR, meta.module, 'index.ts'); | |
| 47 | + const mod = (await import(modPath)) as { default?: (meta: ConnectorMeta) => RareIndexConnector | Promise<RareIndexConnector>; createConnector?: (meta: ConnectorMeta) => RareIndexConnector | Promise<RareIndexConnector> }; | |
| 48 | + const factory = mod.default ?? mod.createConnector; | |
| 49 | + if (!factory) throw new Error(`connector module ${meta.module} must default-export a factory`); | |
| 50 | + return factory(meta); | |
| 51 | +} | |
| 52 | + | |
| 53 | +/** Find connectors whose urlPatterns match a URL (scanner paste-URL, §114). */ | |
| 54 | +export async function connectorsForUrl(url: string): Promise<RareIndexConnector[]> { | |
| 55 | + const out: RareIndexConnector[] = []; | |
| 56 | + for (const meta of listConnectorMeta({ enabled: true })) { | |
| 57 | + if (!meta.supportsLookup) continue; | |
| 58 | + const c = await loadConnector(meta.id); | |
| 59 | + if (c.urlPatterns?.some((re) => re.test(url))) out.push(c); | |
| 60 | + } | |
| 61 | + return out; | |
| 62 | +} | |
added
packages/connectors/src/router.ts
+101 −0
@@ -0,0 +1,101 @@ | ||
| 1 | +import type { Engine, ExtractionResult, Logger } from '@rareindex/shared'; | |
| 2 | +import { createHttpEngine, type HttpEngine } from './engines/http.js'; | |
| 3 | +import { createFirecrawlEngine, type FirecrawlEngine } from './engines/firecrawl.js'; | |
| 4 | +import { createScrapflyEngine, type ScrapflyEngine } from './engines/scrapfly.js'; | |
| 5 | +import { documentQuality, qualityScore, MIN_QUALITY } from './quality.js'; | |
| 6 | +import type { EngineStats, FetchOptions } from './types.js'; | |
| 7 | + | |
| 8 | +export interface RouterOptions { | |
| 9 | + firecrawlApiKey?: string; | |
| 10 | + scrapflyApiKey?: string; | |
| 11 | + log?: Logger; | |
| 12 | + /** called for every engine attempt (cost ledger, metrics) */ | |
| 13 | + onAttempt?: (info: { engine: Engine; url: string; success: boolean; credits: number; ms: number; quality: number; error: string | null }) => void; | |
| 14 | +} | |
| 15 | + | |
| 16 | +export interface Router { | |
| 17 | + fetch(url: string, opts?: FetchOptions, defaults?: { enginePriority: Engine[]; stats?: Record<string, EngineStats> }): Promise<ExtractionResult>; | |
| 18 | + engines: { http: HttpEngine; firecrawl: FirecrawlEngine | null; scrapfly: ScrapflyEngine | null }; | |
| 19 | + available(): Engine[]; | |
| 20 | +} | |
| 21 | + | |
| 22 | +/** | |
| 23 | + * Firecrawl → Scrapfly router (§198). Tries engines in priority order, scores each result with the | |
| 24 | + * connector's parser (or a document heuristic), and falls through until quality ≥ minQuality. | |
| 25 | + * A result that fails everywhere is returned with requiresReview=true — never silently dropped. | |
| 26 | + */ | |
| 27 | +export function createRouter(opts: RouterOptions = {}): Router { | |
| 28 | + const http = createHttpEngine(); | |
| 29 | + const firecrawl = opts.firecrawlApiKey ? createFirecrawlEngine({ apiKey: opts.firecrawlApiKey }) : null; | |
| 30 | + const scrapfly = opts.scrapflyApiKey ? createScrapflyEngine({ apiKey: opts.scrapflyApiKey }) : null; | |
| 31 | + | |
| 32 | + function available(): Engine[] { | |
| 33 | + const out: Engine[] = ['api', 'feed']; | |
| 34 | + if (firecrawl) out.push('firecrawl'); | |
| 35 | + if (scrapfly) out.push('scrapfly'); | |
| 36 | + return out; | |
| 37 | + } | |
| 38 | + | |
| 39 | + async function runEngine(engine: Engine, url: string, o: FetchOptions): Promise<ExtractionResult | null> { | |
| 40 | + switch (engine) { | |
| 41 | + case 'api': | |
| 42 | + case 'feed': | |
| 43 | + return http.fetch(url, o); | |
| 44 | + case 'firecrawl': | |
| 45 | + return firecrawl ? firecrawl.scrape(url, o) : null; | |
| 46 | + case 'scrapfly': | |
| 47 | + return scrapfly ? scrapfly.scrape(url, o) : null; | |
| 48 | + default: | |
| 49 | + return null; | |
| 50 | + } | |
| 51 | + } | |
| 52 | + | |
| 53 | + async function routedFetch(url: string, o: FetchOptions = {}, defaults?: { enginePriority: Engine[]; stats?: Record<string, EngineStats> }): Promise<ExtractionResult> { | |
| 54 | + const engines = (o.engines ?? defaults?.enginePriority ?? ['api', 'firecrawl', 'scrapfly']).filter((e) => available().includes(e)); | |
| 55 | + const minQuality = o.minQuality ?? MIN_QUALITY; | |
| 56 | + let last: ExtractionResult | null = null; | |
| 57 | + const errors: string[] = []; | |
| 58 | + for (const engine of engines) { | |
| 59 | + const res = await runEngine(engine, url, o); | |
| 60 | + if (!res) continue; | |
| 61 | + let quality = 0; | |
| 62 | + if (res.success) { | |
| 63 | + if (o.parse) { | |
| 64 | + try { | |
| 65 | + const found = o.parse(res); | |
| 66 | + quality = qualityScore(found, o.expect); | |
| 67 | + } catch (err) { | |
| 68 | + quality = 0; | |
| 69 | + res.error = `parse: ${err instanceof Error ? err.message : String(err)}`; | |
| 70 | + } | |
| 71 | + } else { | |
| 72 | + quality = documentQuality(res); | |
| 73 | + } | |
| 74 | + } | |
| 75 | + res.qualityScore = quality; | |
| 76 | + const stats = defaults?.stats; | |
| 77 | + if (stats) { | |
| 78 | + const s = (stats[engine] ??= { attempts: 0, success: 0, credits: 0, ms: 0 }); | |
| 79 | + s.attempts++; | |
| 80 | + s.credits += res.costCredits ?? 0; | |
| 81 | + s.ms += res.durationMs ?? 0; | |
| 82 | + if (res.success && quality >= minQuality) s.success++; | |
| 83 | + } | |
| 84 | + opts.onAttempt?.({ engine, url, success: res.success && quality >= minQuality, credits: res.costCredits ?? 0, ms: res.durationMs ?? 0, quality, error: res.error }); | |
| 85 | + if (res.success && quality >= minQuality) return res; | |
| 86 | + errors.push(`${engine}: ${res.error ?? `quality ${quality}`}`); | |
| 87 | + last = res; | |
| 88 | + opts.log?.debug({ url, engine, quality, error: res.error }, 'engine fallback'); | |
| 89 | + // Do not escalate on hard "not found"/"gone" statuses: the page does not exist. | |
| 90 | + if (res.httpStatus === 404 || res.httpStatus === 410) break; | |
| 91 | + } | |
| 92 | + return { | |
| 93 | + ...(last ?? { engine: engines[0] ?? 'api', url, finalUrl: null, httpStatus: null, html: null, markdown: null, json: null, costCredits: 0, durationMs: 0, fetchedAt: new Date(), qualityScore: 0 }), | |
| 94 | + success: false, | |
| 95 | + requiresReview: true, | |
| 96 | + error: errors.join(' | ') || 'no engine available', | |
| 97 | + }; | |
| 98 | + } | |
| 99 | + | |
| 100 | + return { fetch: routedFetch, engines: { http, firecrawl, scrapfly }, available }; | |
| 101 | +} | |
added
packages/connectors/src/testing.ts
+133 −0
@@ -0,0 +1,133 @@ | ||
| 1 | +import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs'; | |
| 2 | +import path from 'node:path'; | |
| 3 | +import { fileURLToPath } from 'node:url'; | |
| 4 | +import { NormalizedRecordSchema, type NormalizedRecord } from '@rareindex/shared'; | |
| 5 | +import type { RareIndexConnector, RawRecordLike } from './types.js'; | |
| 6 | + | |
| 7 | +const here = path.dirname(fileURLToPath(import.meta.url)); | |
| 8 | +export const FIXTURES_DIR = path.resolve(here, '../../../data/fixtures'); | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * Fixture conventions (§146): data/fixtures/<connectorId>/<name>.json holds a captured RawRecordLike | |
| 12 | + * (`{ url, externalId, kind, engine, fetchedAt, payload }`) plus optional `expect` block used by | |
| 13 | + * the standard test-suite. Large HTML captures live next to it as <name>.html and are referenced | |
| 14 | + * by payload.snapshot = "<name>.html". | |
| 15 | + */ | |
| 16 | +export interface Fixture { | |
| 17 | + raw: RawRecordLike; | |
| 18 | + expect?: { | |
| 19 | + count?: number; | |
| 20 | + minCount?: number; | |
| 21 | + kinds?: string[]; | |
| 22 | + first?: Partial<Record<string, unknown>>; | |
| 23 | + /** every record must have these fields non-null */ | |
| 24 | + requiredFields?: string[]; | |
| 25 | + }; | |
| 26 | + capturedAt?: string; | |
| 27 | + note?: string; | |
| 28 | +} | |
| 29 | + | |
| 30 | +export function fixtureDir(connectorId: string): string { | |
| 31 | + return path.join(FIXTURES_DIR, connectorId); | |
| 32 | +} | |
| 33 | + | |
| 34 | +export function listFixtures(connectorId: string): string[] { | |
| 35 | + const dir = fixtureDir(connectorId); | |
| 36 | + if (!existsSync(dir)) return []; | |
| 37 | + return readdirSync(dir).filter((f) => f.endsWith('.json')).map((f) => f.replace(/\.json$/, '')); | |
| 38 | +} | |
| 39 | + | |
| 40 | +export function loadFixture(connectorId: string, name: string): Fixture { | |
| 41 | + const dir = fixtureDir(connectorId); | |
| 42 | + const f = JSON.parse(readFileSync(path.join(dir, `${name}.json`), 'utf8')) as Fixture; | |
| 43 | + f.raw.fetchedAt = new Date(f.raw.fetchedAt); | |
| 44 | + const p = f.raw.payload as { snapshot?: string } | null; | |
| 45 | + if (p && typeof p === 'object' && typeof p.snapshot === 'string' && p.snapshot.endsWith('.html')) { | |
| 46 | + p.snapshot = readFileSync(path.join(dir, p.snapshot), 'utf8'); | |
| 47 | + } | |
| 48 | + return f; | |
| 49 | +} | |
| 50 | + | |
| 51 | +export function saveFixture(connectorId: string, name: string, fixture: Fixture): void { | |
| 52 | + const dir = fixtureDir(connectorId); | |
| 53 | + mkdirSync(dir, { recursive: true }); | |
| 54 | + const p = fixture.raw.payload as { snapshot?: string } | null; | |
| 55 | + if (p && typeof p === 'object' && typeof p.snapshot === 'string' && p.snapshot.length > 20_000) { | |
| 56 | + writeFileSync(path.join(dir, `${name}.html`), p.snapshot); | |
| 57 | + p.snapshot = `${name}.html`; | |
| 58 | + } | |
| 59 | + writeFileSync(path.join(dir, `${name}.json`), JSON.stringify({ ...fixture, capturedAt: fixture.capturedAt ?? new Date().toISOString() }, null, 2)); | |
| 60 | +} | |
| 61 | + | |
| 62 | +/** Validate normalised output against the canonical schemas. Throws with a readable message. */ | |
| 63 | +export function assertNormalized(records: NormalizedRecord[]): NormalizedRecord[] { | |
| 64 | + return records.map((r, i) => { | |
| 65 | + const parsed = NormalizedRecordSchema.safeParse(r); | |
| 66 | + if (!parsed.success) throw new Error(`record[${i}] invalid: ${parsed.error.issues.map((x) => `${x.path.join('.')}: ${x.message}`).join('; ')}`); | |
| 67 | + return parsed.data; | |
| 68 | + }); | |
| 69 | +} | |
| 70 | + | |
| 71 | +/** | |
| 72 | + * Standard fixture suite: run `normalize` on every fixture of a connector and check the common | |
| 73 | + * invariants (schema validity, no crawl-time-as-sale-date, positive prices, currency present, | |
| 74 | + * canonical URL, duplicate handling). Use from vitest: | |
| 75 | + * | |
| 76 | + * describe('scryfall', () => runFixtureSuite(connector, it, expect)) | |
| 77 | + */ | |
| 78 | +export function runFixtureSuite(connector: RareIndexConnector, it: (name: string, fn: () => Promise<void>) => void, expectFn: (v: unknown) => any): void { | |
| 79 | + const names = listFixtures(connector.meta.id); | |
| 80 | + it('has at least one fixture', async () => { | |
| 81 | + expectFn(names.length).toBeGreaterThan(0); | |
| 82 | + }); | |
| 83 | + for (const name of names) { | |
| 84 | + it(`fixture ${name} normalises`, async () => { | |
| 85 | + const fx = loadFixture(connector.meta.id, name); | |
| 86 | + const out = assertNormalized(await connector.normalize(fx.raw)); | |
| 87 | + if (fx.expect?.count !== undefined) expectFn(out.length).toBe(fx.expect.count); | |
| 88 | + if (fx.expect?.minCount !== undefined) expectFn(out.length).toBeGreaterThanOrEqual(fx.expect.minCount); | |
| 89 | + if (fx.expect?.kinds) for (const r of out) expectFn(fx.expect.kinds).toContain(r.kind); | |
| 90 | + const seen = new Set<string>(); | |
| 91 | + for (const r of out) { | |
| 92 | + expectFn(r.sourceUrl.startsWith('http')).toBe(true); | |
| 93 | + expectFn(r.connectorId).toBe(connector.meta.id); | |
| 94 | + if (r.kind === 'sale') { | |
| 95 | + expectFn(r.price).toBeGreaterThan(0); | |
| 96 | + expectFn(r.currency).toBeTruthy(); | |
| 97 | + expectFn(r.saleDate.getTime()).toBeLessThanOrEqual(Date.now() + 86_400_000); | |
| 98 | + // sale date must not simply equal the fetch time (§172) | |
| 99 | + expectFn(Math.abs(r.saleDate.getTime() - fx.raw.fetchedAt.getTime()) > 1000 || r.saleDate.getUTCHours() === 0).toBe(true); | |
| 100 | + } | |
| 101 | + if (r.kind === 'listing' && r.price !== null) { | |
| 102 | + expectFn(r.price).toBeGreaterThanOrEqual(0); | |
| 103 | + expectFn(r.currency).toBeTruthy(); | |
| 104 | + } | |
| 105 | + if (r.kind === 'price_observation') { | |
| 106 | + expectFn(r.price).toBeGreaterThan(0); | |
| 107 | + expectFn(r.currency).toBeTruthy(); | |
| 108 | + } | |
| 109 | + if ('rawTitle' in r) expectFn(r.rawTitle.length).toBeGreaterThan(0); | |
| 110 | + if ('attributes' in r) expectFn(r.attributes.categorySlug.length).toBeGreaterThan(0); | |
| 111 | + const key = `${r.kind}|${'externalId' in r ? r.externalId : ''}|${r.sourceUrl}|${'price' in r ? r.price : ''}|${'saleDate' in r ? r.saleDate.toISOString() : ''}|${'priceKind' in r ? r.priceKind : ''}`; | |
| 112 | + expectFn(seen.has(key)).toBe(false); | |
| 113 | + seen.add(key); | |
| 114 | + } | |
| 115 | + if (fx.expect?.first) { | |
| 116 | + const first = out[0] as unknown as Record<string, unknown>; | |
| 117 | + for (const [k, v] of Object.entries(fx.expect.first)) { | |
| 118 | + const actual = k.includes('.') ? k.split('.').reduce<unknown>((acc, p) => (acc && typeof acc === 'object' ? (acc as Record<string, unknown>)[p] : undefined), first) : first[k]; | |
| 119 | + expectFn(actual).toEqual(v); | |
| 120 | + } | |
| 121 | + } | |
| 122 | + if (fx.expect?.requiredFields) { | |
| 123 | + for (const r of out) { | |
| 124 | + const rec = r as unknown as Record<string, unknown>; | |
| 125 | + for (const f of fx.expect.requiredFields) { | |
| 126 | + const val = f.includes('.') ? f.split('.').reduce<unknown>((acc, p) => (acc && typeof acc === 'object' ? (acc as Record<string, unknown>)[p] : undefined), rec) : rec[f]; | |
| 127 | + expectFn(val === null || val === undefined || val === '').toBe(false); | |
| 128 | + } | |
| 129 | + } | |
| 130 | + } | |
| 131 | + }); | |
| 132 | + } | |
| 133 | +} | |
added
packages/connectors/src/types.ts
+165 −0
@@ -0,0 +1,165 @@ | ||
| 1 | +import { z } from 'zod'; | |
| 2 | +import type { Logger } from '@rareindex/shared'; | |
| 3 | +import { EngineSchema, SourceTypeSchema, type Engine, type ExtractionResult, type NormalizedRecord, type RawRecord, type ConnectorHealth, type RecordKind } from '@rareindex/shared'; | |
| 4 | + | |
| 5 | +/** Registry entry — mirrors connectors/registry.json (§106). */ | |
| 6 | +export const ConnectorMetaSchema = z.object({ | |
| 7 | + id: z.string().regex(/^[a-z0-9-]+$/), | |
| 8 | + displayName: z.string(), | |
| 9 | + sourceId: z.string(), | |
| 10 | + sourceName: z.string(), | |
| 11 | + sourceType: SourceTypeSchema, | |
| 12 | + sourceUrl: z.string().url(), | |
| 13 | + /** module path relative to /connectors, e.g. "api/scryfall" */ | |
| 14 | + module: z.string(), | |
| 15 | + enginePriority: z.array(EngineSchema).min(1), | |
| 16 | + categories: z.array(z.string()).min(1), | |
| 17 | + regions: z.array(z.string()).default([]), | |
| 18 | + languages: z.array(z.string()).default(['en']), | |
| 19 | + currency: z.array(z.string()).default(['USD']), | |
| 20 | + supportsListings: z.boolean().default(false), | |
| 21 | + supportsSold: z.boolean().default(false), | |
| 22 | + supportsAuctions: z.boolean().default(false), | |
| 23 | + supportsImages: z.boolean().default(true), | |
| 24 | + supportsCatalog: z.boolean().default(false), | |
| 25 | + supportsPopulation: z.boolean().default(false), | |
| 26 | + supportsLookup: z.boolean().default(false), | |
| 27 | + refreshFrequencyMinutes: z.number().int().positive().default(1440), | |
| 28 | + priority: z.enum(['high', 'medium', 'low']).default('medium'), | |
| 29 | + /** 0–1 baseline trust for the source (§143) */ | |
| 30 | + trustScore: z.number().min(0).max(1).default(0.6), | |
| 31 | + attributionRequired: z.boolean().default(true), | |
| 32 | + termsUrl: z.string().optional(), | |
| 33 | + /** legal/ethical notes: what we do and do not fetch from this source */ | |
| 34 | + accessNotes: z.string().optional(), | |
| 35 | + enabled: z.boolean().default(true), | |
| 36 | + schemaVersion: z.string().default('1.0'), | |
| 37 | + config: z.record(z.string(), z.unknown()).default({}), | |
| 38 | +}); | |
| 39 | +export type ConnectorMeta = z.infer<typeof ConnectorMetaSchema>; | |
| 40 | + | |
| 41 | +export const RegistrySchema = z.object({ | |
| 42 | + version: z.string(), | |
| 43 | + connectors: z.array(ConnectorMetaSchema), | |
| 44 | +}); | |
| 45 | +export type Registry = z.infer<typeof RegistrySchema>; | |
| 46 | + | |
| 47 | +/** What a connector yields while crawling; the worker adds ids, run id and persistence. */ | |
| 48 | +export interface RawRecordInput { | |
| 49 | + url: string; | |
| 50 | + externalId?: string | null; | |
| 51 | + kind: RecordKind; | |
| 52 | + engine: Engine; | |
| 53 | + httpStatus?: number | null; | |
| 54 | + payload: unknown; | |
| 55 | + /** optional large text (HTML/markdown) persisted to disk, not the DB */ | |
| 56 | + snapshot?: string | null; | |
| 57 | + fetchedAt?: Date; | |
| 58 | +} | |
| 59 | + | |
| 60 | +export type QualityField = 'title' | 'price' | 'status' | 'date' | 'images' | 'description' | 'identifiers' | 'category' | 'currency'; | |
| 61 | + | |
| 62 | +export interface FetchOptions { | |
| 63 | + /** Restrict/override the engines to try, in order. Defaults to meta.enginePriority. */ | |
| 64 | + engines?: Engine[]; | |
| 65 | + /** Fields the parser is expected to find; drives the quality score (§199). */ | |
| 66 | + expect?: QualityField[]; | |
| 67 | + /** Parse the fetched document; return the fields found so the router can score quality. */ | |
| 68 | + parse?: (res: ExtractionResult) => Partial<Record<QualityField, unknown>> | null; | |
| 69 | + /** Minimum quality to accept an engine result before falling back (default 0.6). */ | |
| 70 | + minQuality?: number; | |
| 71 | + /** Engine hints */ | |
| 72 | + renderJs?: boolean; | |
| 73 | + waitForMs?: number; | |
| 74 | + country?: string; | |
| 75 | + headers?: Record<string, string>; | |
| 76 | + /** Firecrawl JSON extraction schema (when using the json format) */ | |
| 77 | + jsonSchema?: Record<string, unknown>; | |
| 78 | + jsonPrompt?: string; | |
| 79 | + /** Scrapfly extraction model (e.g. "product") */ | |
| 80 | + extractionModel?: string; | |
| 81 | + timeoutMs?: number; | |
| 82 | + /** skip cache/budget checks */ | |
| 83 | + force?: boolean; | |
| 84 | + /** treat non-2xx as failure (default true) */ | |
| 85 | + failOnHttpError?: boolean; | |
| 86 | + /** Body for POST requests (api engine) */ | |
| 87 | + method?: 'GET' | 'POST'; | |
| 88 | + body?: unknown; | |
| 89 | + /** Return type for api engine: json (default) or text */ | |
| 90 | + responseType?: 'json' | 'text'; | |
| 91 | +} | |
| 92 | + | |
| 93 | +export interface CrawlOptions { | |
| 94 | + mode: 'incremental' | 'backfill' | 'probe'; | |
| 95 | + /** soft cap on records to yield (probe/tests) */ | |
| 96 | + limit?: number; | |
| 97 | + /** cursor persisted between runs (connector-defined shape) */ | |
| 98 | + cursor?: Record<string, unknown>; | |
| 99 | + /** optional category filter (slugs) */ | |
| 100 | + categories?: string[]; | |
| 101 | + /** optional seed URLs/queries (manual runs) */ | |
| 102 | + seeds?: string[]; | |
| 103 | +} | |
| 104 | + | |
| 105 | +export interface EngineStats { | |
| 106 | + attempts: number; | |
| 107 | + success: number; | |
| 108 | + credits: number; | |
| 109 | + ms: number; | |
| 110 | +} | |
| 111 | + | |
| 112 | +export interface CrawlContext { | |
| 113 | + meta: ConnectorMeta; | |
| 114 | + log: Logger; | |
| 115 | + options: CrawlOptions; | |
| 116 | + /** Routed fetch: api/http → firecrawl → scrapfly (§198). Records stats and cost. */ | |
| 117 | + fetch(url: string, opts?: FetchOptions): Promise<ExtractionResult>; | |
| 118 | + /** Firecrawl search (when available) — returns urls + snippets/markdown. */ | |
| 119 | + search?(query: string, opts?: { limit?: number; scrape?: boolean; country?: string }): Promise<Array<{ url: string; title?: string; description?: string; markdown?: string }>>; | |
| 120 | + /** Firecrawl map — discover URLs of a site. */ | |
| 121 | + map?(url: string, opts?: { search?: string; limit?: number }): Promise<string[]>; | |
| 122 | + /** Crawl budget: true when the URL content changed since last time or is due (§170). */ | |
| 123 | + shouldFetch(url: string): Promise<boolean>; | |
| 124 | + /** Persist an updated cursor (called by connector at checkpoints). */ | |
| 125 | + setCursor(cursor: Record<string, unknown>): Promise<void>; | |
| 126 | + /** Report a non-fatal anomaly for health tracking (§105). */ | |
| 127 | + anomaly(kind: string, detail?: string): void; | |
| 128 | + engineStats: Record<string, EngineStats>; | |
| 129 | + /** Cooperative cancellation */ | |
| 130 | + signal?: AbortSignal; | |
| 131 | +} | |
| 132 | + | |
| 133 | +export interface HealthContext { | |
| 134 | + meta: ConnectorMeta; | |
| 135 | + log: Logger; | |
| 136 | + fetch(url: string, opts?: FetchOptions): Promise<ExtractionResult>; | |
| 137 | + /** Recent run metrics supplied by the worker (may be empty for a fresh connector). */ | |
| 138 | + recentRuns: Array<{ startedAt: Date; status: string; pagesAttempted: number; pagesSuccess: number; recordsRaw: number; recordsDuplicate: number; engineStats: Record<string, EngineStats>; anomalies: string[]; error: string | null }>; | |
| 139 | +} | |
| 140 | + | |
| 141 | +/** | |
| 142 | + * The connector contract (§102). Every source implements exactly this. Everything else — | |
| 143 | + * persistence, dedupe, entity resolution, valuation — is generic pipeline code. | |
| 144 | + */ | |
| 145 | +export interface RareIndexConnector { | |
| 146 | + readonly meta: ConnectorMeta; | |
| 147 | + /** semantic version of connector code; bump when crawl logic changes */ | |
| 148 | + readonly version: string; | |
| 149 | + /** version of the parsing/normalisation logic; bump when field mapping changes */ | |
| 150 | + readonly parserVersion: string; | |
| 151 | + /** Yield raw records. Must be resumable through options.cursor. */ | |
| 152 | + crawl(ctx: CrawlContext): AsyncIterable<RawRecordInput>; | |
| 153 | + /** Pure function: raw payload → canonical normalised records. Must be deterministic and fixture-testable. */ | |
| 154 | + normalize(raw: RawRecordLike): Promise<NormalizedRecord[]>; | |
| 155 | + /** Liveness/probe check. Base implementation derives status from recent runs and a light probe. */ | |
| 156 | + healthCheck(ctx: HealthContext): Promise<ConnectorHealth>; | |
| 157 | + /** Optional: resolve a single source URL (scanner/paste URL, §114). */ | |
| 158 | + lookup?(url: string, ctx: CrawlContext): Promise<RawRecordInput[]>; | |
| 159 | + /** Optional: URL patterns this connector understands (for lookup routing). */ | |
| 160 | + readonly urlPatterns?: RegExp[]; | |
| 161 | +} | |
| 162 | + | |
| 163 | +export type RawRecordLike = Pick<RawRecord, 'url' | 'externalId' | 'kind' | 'payload' | 'fetchedAt' | 'engine'> & { id?: string; connectorId?: string; sourceId?: string }; | |
| 164 | + | |
| 165 | +export type ConnectorFactory = () => RareIndexConnector | Promise<RareIndexConnector>; | |
added
packages/connectors/tsconfig.json
+9 −0
@@ -0,0 +1,9 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.base.json", | |
| 3 | + "compilerOptions": { | |
| 4 | + "rootDir": "src", | |
| 5 | + "outDir": "dist", | |
| 6 | + "noEmit": true | |
| 7 | + }, | |
| 8 | + "include": ["src"] | |
| 9 | +} | |
added
packages/connectors/vitest.config.ts
+5 −0
@@ -0,0 +1,5 @@ | ||
| 1 | +import { defineConfig } from 'vitest/config'; | |
| 2 | + | |
| 3 | +export default defineConfig({ | |
| 4 | + test: { include: ['src/**/*.test.ts'] }, | |
| 5 | +}); | |
added
packages/database/drizzle.config.ts
+10 −0
@@ -0,0 +1,10 @@ | ||
| 1 | +import { defineConfig } from 'drizzle-kit'; | |
| 2 | + | |
| 3 | +export default defineConfig({ | |
| 4 | + dialect: 'postgresql', | |
| 5 | + schema: './src/schema/index.ts', | |
| 6 | + out: './migrations', | |
| 7 | + dbCredentials: { url: process.env.DATABASE_URL ?? 'postgres://localhost:5432/rareindex' }, | |
| 8 | + strict: true, | |
| 9 | + verbose: true, | |
| 10 | +}); | |
added
packages/database/migrations/0000_clear_unicorn.sql
+941 −0
@@ -0,0 +1,941 @@ | ||
| 1 | +CREATE TABLE "brands" ( | |
| 2 | + "slug" text PRIMARY KEY NOT NULL, | |
| 3 | + "name" text NOT NULL, | |
| 4 | + "category_slugs" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 5 | + "country" text, | |
| 6 | + "founded_year" integer, | |
| 7 | + "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 8 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 9 | +); | |
| 10 | +--> statement-breakpoint | |
| 11 | +CREATE TABLE "categories" ( | |
| 12 | + "slug" text PRIMARY KEY NOT NULL, | |
| 13 | + "parent_slug" text, | |
| 14 | + "family_slug" text NOT NULL, | |
| 15 | + "name" text NOT NULL, | |
| 16 | + "short_name" text, | |
| 17 | + "description" text, | |
| 18 | + "level" integer DEFAULT 0 NOT NULL, | |
| 19 | + "phase" integer DEFAULT 3 NOT NULL, | |
| 20 | + "active" boolean DEFAULT true NOT NULL, | |
| 21 | + "condition_scale" text, | |
| 22 | + "graders" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 23 | + "index_ticker" text, | |
| 24 | + "attribute_schema" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 25 | + "sort_order" integer DEFAULT 0 NOT NULL, | |
| 26 | + "compliance_flags" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 27 | + "icon" text, | |
| 28 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL, | |
| 29 | + "updated_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 30 | +); | |
| 31 | +--> statement-breakpoint | |
| 32 | +CREATE TABLE "franchises" ( | |
| 33 | + "slug" text PRIMARY KEY NOT NULL, | |
| 34 | + "name" text NOT NULL, | |
| 35 | + "owner" text, | |
| 36 | + "category_slugs" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 37 | + "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 38 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 39 | +); | |
| 40 | +--> statement-breakpoint | |
| 41 | +CREATE TABLE "graders" ( | |
| 42 | + "slug" text PRIMARY KEY NOT NULL, | |
| 43 | + "name" text NOT NULL, | |
| 44 | + "category_slugs" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 45 | + "scale" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 46 | + "population_url" text, | |
| 47 | + "verify_url" text, | |
| 48 | + "active" boolean DEFAULT true NOT NULL | |
| 49 | +); | |
| 50 | +--> statement-breakpoint | |
| 51 | +CREATE TABLE "sets" ( | |
| 52 | + "slug" text PRIMARY KEY NOT NULL, | |
| 53 | + "name" text NOT NULL, | |
| 54 | + "code" text, | |
| 55 | + "category_slug" text NOT NULL, | |
| 56 | + "franchise_slug" text, | |
| 57 | + "brand_slug" text, | |
| 58 | + "release_year" integer, | |
| 59 | + "release_date" text, | |
| 60 | + "language" text, | |
| 61 | + "total_items" integer, | |
| 62 | + "identifiers" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 63 | + "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 64 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 65 | +); | |
| 66 | +--> statement-breakpoint | |
| 67 | +CREATE TABLE "taxonomy_proposals" ( | |
| 68 | + "id" text PRIMARY KEY NOT NULL, | |
| 69 | + "proposed_slug" text NOT NULL, | |
| 70 | + "name" text NOT NULL, | |
| 71 | + "parent_slug" text, | |
| 72 | + "evidence" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 73 | + "volume_estimate" integer, | |
| 74 | + "status" text DEFAULT 'pending' NOT NULL, | |
| 75 | + "decided_by" text, | |
| 76 | + "decided_at" text, | |
| 77 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 78 | +); | |
| 79 | +--> statement-breakpoint | |
| 80 | +CREATE TABLE "connector_health" ( | |
| 81 | + "connector_id" text PRIMARY KEY NOT NULL, | |
| 82 | + "computed_at" timestamp with time zone NOT NULL, | |
| 83 | + "status" text NOT NULL, | |
| 84 | + "health" jsonb DEFAULT '{}'::jsonb NOT NULL | |
| 85 | +); | |
| 86 | +--> statement-breakpoint | |
| 87 | +CREATE TABLE "connector_runs" ( | |
| 88 | + "id" text PRIMARY KEY NOT NULL, | |
| 89 | + "connector_id" text NOT NULL, | |
| 90 | + "trigger" text DEFAULT 'schedule' NOT NULL, | |
| 91 | + "started_at" timestamp with time zone NOT NULL, | |
| 92 | + "finished_at" timestamp with time zone, | |
| 93 | + "status" text DEFAULT 'running' NOT NULL, | |
| 94 | + "pages_attempted" integer DEFAULT 0 NOT NULL, | |
| 95 | + "pages_success" integer DEFAULT 0 NOT NULL, | |
| 96 | + "records_raw" integer DEFAULT 0 NOT NULL, | |
| 97 | + "records_normalized" integer DEFAULT 0 NOT NULL, | |
| 98 | + "records_duplicate" integer DEFAULT 0 NOT NULL, | |
| 99 | + "records_rejected" integer DEFAULT 0 NOT NULL, | |
| 100 | + "engine_stats" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 101 | + "anomalies" jsonb DEFAULT '[]'::jsonb NOT NULL, | |
| 102 | + "error" text, | |
| 103 | + "cost_credits" real DEFAULT 0 NOT NULL, | |
| 104 | + "cost_usd_est" real DEFAULT 0 NOT NULL, | |
| 105 | + "cursor" jsonb DEFAULT '{}'::jsonb NOT NULL | |
| 106 | +); | |
| 107 | +--> statement-breakpoint | |
| 108 | +CREATE TABLE "connectors" ( | |
| 109 | + "id" text PRIMARY KEY NOT NULL, | |
| 110 | + "source_id" text NOT NULL, | |
| 111 | + "display_name" text NOT NULL, | |
| 112 | + "engine_priority" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 113 | + "categories" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 114 | + "regions" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 115 | + "languages" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 116 | + "currency" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 117 | + "supports_listings" boolean DEFAULT false NOT NULL, | |
| 118 | + "supports_sold" boolean DEFAULT false NOT NULL, | |
| 119 | + "supports_auctions" boolean DEFAULT false NOT NULL, | |
| 120 | + "supports_images" boolean DEFAULT true NOT NULL, | |
| 121 | + "supports_catalog" boolean DEFAULT false NOT NULL, | |
| 122 | + "supports_population" boolean DEFAULT false NOT NULL, | |
| 123 | + "refresh_frequency_minutes" integer DEFAULT 1440 NOT NULL, | |
| 124 | + "priority" text DEFAULT 'medium' NOT NULL, | |
| 125 | + "status" text DEFAULT 'active' NOT NULL, | |
| 126 | + "schema_version" text DEFAULT '1.0' NOT NULL, | |
| 127 | + "connector_version" text DEFAULT '1.0.0' NOT NULL, | |
| 128 | + "config" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 129 | + "last_run_at" timestamp with time zone, | |
| 130 | + "last_success_at" timestamp with time zone, | |
| 131 | + "next_run_at" timestamp with time zone, | |
| 132 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL, | |
| 133 | + "updated_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 134 | +); | |
| 135 | +--> statement-breakpoint | |
| 136 | +CREATE TABLE "costs" ( | |
| 137 | + "id" text PRIMARY KEY NOT NULL, | |
| 138 | + "occurred_at" timestamp with time zone NOT NULL, | |
| 139 | + "kind" text NOT NULL, | |
| 140 | + "provider" text, | |
| 141 | + "connector_id" text, | |
| 142 | + "category_slug" text, | |
| 143 | + "endpoint" text, | |
| 144 | + "user_id" text, | |
| 145 | + "units" real DEFAULT 1 NOT NULL, | |
| 146 | + "credits" real DEFAULT 0 NOT NULL, | |
| 147 | + "usd_est" real DEFAULT 0 NOT NULL, | |
| 148 | + "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL | |
| 149 | +); | |
| 150 | +--> statement-breakpoint | |
| 151 | +CREATE TABLE "crawl_state" ( | |
| 152 | + "url_hash" text PRIMARY KEY NOT NULL, | |
| 153 | + "connector_id" text NOT NULL, | |
| 154 | + "url" text NOT NULL, | |
| 155 | + "etag" text, | |
| 156 | + "last_modified" text, | |
| 157 | + "content_hash" text, | |
| 158 | + "last_fetched_at" timestamp with time zone, | |
| 159 | + "last_changed_at" timestamp with time zone, | |
| 160 | + "fetch_count" integer DEFAULT 0 NOT NULL, | |
| 161 | + "change_count" integer DEFAULT 0 NOT NULL, | |
| 162 | + "change_interval_hours" real, | |
| 163 | + "next_fetch_at" timestamp with time zone, | |
| 164 | + "last_status" integer, | |
| 165 | + "failures" integer DEFAULT 0 NOT NULL | |
| 166 | +); | |
| 167 | +--> statement-breakpoint | |
| 168 | +CREATE TABLE "sources" ( | |
| 169 | + "id" text PRIMARY KEY NOT NULL, | |
| 170 | + "name" text NOT NULL, | |
| 171 | + "source_type" text NOT NULL, | |
| 172 | + "url" text, | |
| 173 | + "countries" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 174 | + "languages" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 175 | + "currencies" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 176 | + "trust_score" numeric(8, 6) DEFAULT 0.5 NOT NULL, | |
| 177 | + "trust_factors" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 178 | + "attribution_required" boolean DEFAULT true NOT NULL, | |
| 179 | + "terms_url" text, | |
| 180 | + "active" boolean DEFAULT true NOT NULL, | |
| 181 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL, | |
| 182 | + "updated_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 183 | +); | |
| 184 | +--> statement-breakpoint | |
| 185 | +CREATE TABLE "audit_log" ( | |
| 186 | + "id" text PRIMARY KEY NOT NULL, | |
| 187 | + "entity_type" text NOT NULL, | |
| 188 | + "entity_id" text NOT NULL, | |
| 189 | + "action" text NOT NULL, | |
| 190 | + "reason" text NOT NULL, | |
| 191 | + "actor" text DEFAULT 'system' NOT NULL, | |
| 192 | + "details" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 193 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 194 | +); | |
| 195 | +--> statement-breakpoint | |
| 196 | +CREATE TABLE "events" ( | |
| 197 | + "id" text PRIMARY KEY NOT NULL, | |
| 198 | + "type" text NOT NULL, | |
| 199 | + "entity_type" text, | |
| 200 | + "entity_id" text, | |
| 201 | + "payload" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 202 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 203 | +); | |
| 204 | +--> statement-breakpoint | |
| 205 | +CREATE TABLE "normalized_records" ( | |
| 206 | + "id" text PRIMARY KEY NOT NULL, | |
| 207 | + "raw_record_id" text NOT NULL, | |
| 208 | + "connector_id" text NOT NULL, | |
| 209 | + "source_id" text NOT NULL, | |
| 210 | + "kind" text NOT NULL, | |
| 211 | + "payload" jsonb NOT NULL, | |
| 212 | + "asset_id" text, | |
| 213 | + "variant_id" text, | |
| 214 | + "match_method" text, | |
| 215 | + "match_confidence" numeric(8, 6), | |
| 216 | + "status" text DEFAULT 'pending' NOT NULL, | |
| 217 | + "reject_reason" text, | |
| 218 | + "target_id" text, | |
| 219 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL, | |
| 220 | + "processed_at" timestamp with time zone | |
| 221 | +); | |
| 222 | +--> statement-breakpoint | |
| 223 | +CREATE TABLE "raw_records" ( | |
| 224 | + "id" text PRIMARY KEY NOT NULL, | |
| 225 | + "connector_id" text NOT NULL, | |
| 226 | + "source_id" text NOT NULL, | |
| 227 | + "run_id" text, | |
| 228 | + "engine" text NOT NULL, | |
| 229 | + "url" text NOT NULL, | |
| 230 | + "external_id" text, | |
| 231 | + "kind" text NOT NULL, | |
| 232 | + "fetched_at" timestamp with time zone NOT NULL, | |
| 233 | + "content_hash" text NOT NULL, | |
| 234 | + "http_status" integer, | |
| 235 | + "payload" jsonb NOT NULL, | |
| 236 | + "snapshot_ref" text, | |
| 237 | + "parser_version" text NOT NULL, | |
| 238 | + "connector_version" text NOT NULL, | |
| 239 | + "processed_at" timestamp with time zone, | |
| 240 | + "process_error" text, | |
| 241 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 242 | +); | |
| 243 | +--> statement-breakpoint | |
| 244 | +CREATE TABLE "asset_embeddings" ( | |
| 245 | + "asset_id" text PRIMARY KEY NOT NULL, | |
| 246 | + "model" text NOT NULL, | |
| 247 | + "embedding" vector(1536) NOT NULL, | |
| 248 | + "updated_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 249 | +); | |
| 250 | +--> statement-breakpoint | |
| 251 | +CREATE TABLE "asset_stats" ( | |
| 252 | + "asset_id" text PRIMARY KEY NOT NULL, | |
| 253 | + "riv_usd" numeric(18, 4), | |
| 254 | + "riv_low_usd" numeric(18, 4), | |
| 255 | + "riv_high_usd" numeric(18, 4), | |
| 256 | + "riv_confidence" numeric(8, 6), | |
| 257 | + "riv_sample_size" integer DEFAULT 0 NOT NULL, | |
| 258 | + "riv_variant_id" text, | |
| 259 | + "latest_sale_usd" numeric(18, 4), | |
| 260 | + "latest_sale_at" timestamp with time zone, | |
| 261 | + "change_1d" numeric(8, 6), | |
| 262 | + "change_7d" numeric(8, 6), | |
| 263 | + "change_30d" numeric(8, 6), | |
| 264 | + "change_90d" numeric(8, 6), | |
| 265 | + "change_1y" numeric(8, 6), | |
| 266 | + "ath_usd" numeric(18, 4), | |
| 267 | + "ath_at" timestamp with time zone, | |
| 268 | + "atl_usd" numeric(18, 4), | |
| 269 | + "atl_at" timestamp with time zone, | |
| 270 | + "sales_count" integer DEFAULT 0 NOT NULL, | |
| 271 | + "sales_30d" integer DEFAULT 0 NOT NULL, | |
| 272 | + "sales_1y" integer DEFAULT 0 NOT NULL, | |
| 273 | + "volume_30d_usd" numeric(18, 4), | |
| 274 | + "active_listings" integer DEFAULT 0 NOT NULL, | |
| 275 | + "min_ask_usd" numeric(18, 4), | |
| 276 | + "observations_count" integer DEFAULT 0 NOT NULL, | |
| 277 | + "sources_count" integer DEFAULT 0 NOT NULL, | |
| 278 | + "liquidity_score" real, | |
| 279 | + "rarity_score" real, | |
| 280 | + "momentum_7d" real, | |
| 281 | + "momentum_30d" real, | |
| 282 | + "momentum_90d" real, | |
| 283 | + "momentum_1y" real, | |
| 284 | + "trending_score" real, | |
| 285 | + "value_opportunity" real, | |
| 286 | + "data_quality" real, | |
| 287 | + "watchers" integer DEFAULT 0 NOT NULL, | |
| 288 | + "views_30d" integer DEFAULT 0 NOT NULL, | |
| 289 | + "updated_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 290 | +); | |
| 291 | +--> statement-breakpoint | |
| 292 | +CREATE TABLE "asset_variants" ( | |
| 293 | + "id" text PRIMARY KEY NOT NULL, | |
| 294 | + "asset_id" text NOT NULL, | |
| 295 | + "variant_key" text NOT NULL, | |
| 296 | + "grader" text, | |
| 297 | + "grade" text, | |
| 298 | + "qualifier" text, | |
| 299 | + "condition" text, | |
| 300 | + "completeness" text, | |
| 301 | + "size_label" text, | |
| 302 | + "label" text NOT NULL, | |
| 303 | + "is_default" boolean DEFAULT false NOT NULL, | |
| 304 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 305 | +); | |
| 306 | +--> statement-breakpoint | |
| 307 | +CREATE TABLE "assets" ( | |
| 308 | + "id" text PRIMARY KEY NOT NULL, | |
| 309 | + "slug" text NOT NULL, | |
| 310 | + "canonical_key" text NOT NULL, | |
| 311 | + "category_slug" text NOT NULL, | |
| 312 | + "subcategory_slug" text, | |
| 313 | + "family_slug" text NOT NULL, | |
| 314 | + "franchise" text, | |
| 315 | + "brand" text, | |
| 316 | + "series" text, | |
| 317 | + "set_slug" text, | |
| 318 | + "set_name" text, | |
| 319 | + "set_code" text, | |
| 320 | + "name" text NOT NULL, | |
| 321 | + "title" text NOT NULL, | |
| 322 | + "model" text, | |
| 323 | + "reference" text, | |
| 324 | + "number" text, | |
| 325 | + "year" integer, | |
| 326 | + "edition" text, | |
| 327 | + "variant" text, | |
| 328 | + "language" text, | |
| 329 | + "region" text, | |
| 330 | + "country" text, | |
| 331 | + "material" text, | |
| 332 | + "size" text, | |
| 333 | + "color" text, | |
| 334 | + "rarity" text, | |
| 335 | + "production_quantity" integer, | |
| 336 | + "original_msrp" numeric(18, 4), | |
| 337 | + "original_msrp_currency" text, | |
| 338 | + "release_date" text, | |
| 339 | + "description" text, | |
| 340 | + "hero_image_url" text, | |
| 341 | + "identifiers" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 342 | + "metadata" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 343 | + "merged_from" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 344 | + "data_quality" real DEFAULT 0 NOT NULL, | |
| 345 | + "verified" boolean DEFAULT false NOT NULL, | |
| 346 | + "search" "tsvector" GENERATED ALWAYS AS (setweight(to_tsvector('simple', coalesce(name, '')), 'A') || setweight(to_tsvector('simple', coalesce(set_name, '') || ' ' || coalesce(number, '') || ' ' || coalesce(variant, '') || ' ' || coalesce(edition, '')), 'B') || setweight(to_tsvector('simple', coalesce(brand, '') || ' ' || coalesce(franchise, '') || ' ' || coalesce(reference, '') || ' ' || coalesce(model, '') || ' ' || coalesce(year::text, '') || ' ' || coalesce(category_slug, '')), 'C')) STORED, | |
| 347 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL, | |
| 348 | + "updated_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 349 | +); | |
| 350 | +--> statement-breakpoint | |
| 351 | +CREATE TABLE "grade_premiums" ( | |
| 352 | + "id" text PRIMARY KEY NOT NULL, | |
| 353 | + "category_slug" text NOT NULL, | |
| 354 | + "grader" text NOT NULL, | |
| 355 | + "grade" text NOT NULL, | |
| 356 | + "market_multiplier" real NOT NULL, | |
| 357 | + "sample_size" integer NOT NULL, | |
| 358 | + "computed_at" timestamp with time zone NOT NULL | |
| 359 | +); | |
| 360 | +--> statement-breakpoint | |
| 361 | +CREATE TABLE "images" ( | |
| 362 | + "id" text PRIMARY KEY NOT NULL, | |
| 363 | + "asset_id" text, | |
| 364 | + "listing_id" text, | |
| 365 | + "sale_id" text, | |
| 366 | + "source_id" text, | |
| 367 | + "url" text NOT NULL, | |
| 368 | + "role" text DEFAULT 'gallery' NOT NULL, | |
| 369 | + "width" integer, | |
| 370 | + "height" integer, | |
| 371 | + "phash" text, | |
| 372 | + "embedding" vector(512), | |
| 373 | + "attribution" text, | |
| 374 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 375 | +); | |
| 376 | +--> statement-breakpoint | |
| 377 | +CREATE TABLE "population_reports" ( | |
| 378 | + "id" text PRIMARY KEY NOT NULL, | |
| 379 | + "asset_id" text NOT NULL, | |
| 380 | + "grader" text NOT NULL, | |
| 381 | + "source_id" text NOT NULL, | |
| 382 | + "source_url" text, | |
| 383 | + "report_date" text NOT NULL, | |
| 384 | + "total" integer NOT NULL, | |
| 385 | + "by_grade" jsonb NOT NULL, | |
| 386 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 387 | +); | |
| 388 | +--> statement-breakpoint | |
| 389 | +CREATE TABLE "variant_stats" ( | |
| 390 | + "variant_id" text PRIMARY KEY NOT NULL, | |
| 391 | + "asset_id" text NOT NULL, | |
| 392 | + "riv_usd" numeric(18, 4), | |
| 393 | + "riv_low_usd" numeric(18, 4), | |
| 394 | + "riv_high_usd" numeric(18, 4), | |
| 395 | + "riv_confidence" numeric(8, 6), | |
| 396 | + "riv_sample_size" integer DEFAULT 0 NOT NULL, | |
| 397 | + "latest_sale_usd" numeric(18, 4), | |
| 398 | + "latest_sale_at" timestamp with time zone, | |
| 399 | + "change_30d" numeric(8, 6), | |
| 400 | + "change_1y" numeric(8, 6), | |
| 401 | + "sales_count" integer DEFAULT 0 NOT NULL, | |
| 402 | + "sales_30d" integer DEFAULT 0 NOT NULL, | |
| 403 | + "active_listings" integer DEFAULT 0 NOT NULL, | |
| 404 | + "min_ask_usd" numeric(18, 4), | |
| 405 | + "liquidity_score" real, | |
| 406 | + "updated_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 407 | +); | |
| 408 | +--> statement-breakpoint | |
| 409 | +CREATE TABLE "auction_lots" ( | |
| 410 | + "id" text PRIMARY KEY NOT NULL, | |
| 411 | + "auction_id" text NOT NULL, | |
| 412 | + "asset_id" text, | |
| 413 | + "variant_id" text, | |
| 414 | + "source_id" text NOT NULL, | |
| 415 | + "lot_number" text, | |
| 416 | + "title" text NOT NULL, | |
| 417 | + "url" text NOT NULL, | |
| 418 | + "estimate_low" numeric(18, 4), | |
| 419 | + "estimate_high" numeric(18, 4), | |
| 420 | + "current_bid" numeric(18, 4), | |
| 421 | + "hammer_price" numeric(18, 4), | |
| 422 | + "currency" text, | |
| 423 | + "bid_count" integer, | |
| 424 | + "starts_at" timestamp with time zone, | |
| 425 | + "ends_at" timestamp with time zone, | |
| 426 | + "status" text DEFAULT 'upcoming' NOT NULL, | |
| 427 | + "image_urls" jsonb DEFAULT '[]'::jsonb NOT NULL, | |
| 428 | + "grader" text, | |
| 429 | + "grade" text, | |
| 430 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL, | |
| 431 | + "updated_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 432 | +); | |
| 433 | +--> statement-breakpoint | |
| 434 | +CREATE TABLE "auctions" ( | |
| 435 | + "id" text PRIMARY KEY NOT NULL, | |
| 436 | + "source_id" text NOT NULL, | |
| 437 | + "auction_house" text NOT NULL, | |
| 438 | + "name" text NOT NULL, | |
| 439 | + "url" text NOT NULL, | |
| 440 | + "starts_at" timestamp with time zone, | |
| 441 | + "ends_at" timestamp with time zone, | |
| 442 | + "location" text, | |
| 443 | + "category_slugs" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 444 | + "lot_count" integer, | |
| 445 | + "status" text DEFAULT 'upcoming' NOT NULL, | |
| 446 | + "currency" text, | |
| 447 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL, | |
| 448 | + "updated_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 449 | +); | |
| 450 | +--> statement-breakpoint | |
| 451 | +CREATE TABLE "cross_listing_groups" ( | |
| 452 | + "id" text PRIMARY KEY NOT NULL, | |
| 453 | + "asset_id" text, | |
| 454 | + "signals" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 455 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 456 | +); | |
| 457 | +--> statement-breakpoint | |
| 458 | +CREATE TABLE "fx_rates" ( | |
| 459 | + "date" date NOT NULL, | |
| 460 | + "base" text NOT NULL, | |
| 461 | + "quote" text NOT NULL, | |
| 462 | + "rate" real NOT NULL, | |
| 463 | + "source" text DEFAULT 'ecb' NOT NULL | |
| 464 | +); | |
| 465 | +--> statement-breakpoint | |
| 466 | +CREATE TABLE "listing_events" ( | |
| 467 | + "id" text PRIMARY KEY NOT NULL, | |
| 468 | + "listing_id" text NOT NULL, | |
| 469 | + "event_type" text NOT NULL, | |
| 470 | + "old_price" numeric(18, 4), | |
| 471 | + "new_price" numeric(18, 4), | |
| 472 | + "currency" text, | |
| 473 | + "occurred_at" timestamp with time zone NOT NULL | |
| 474 | +); | |
| 475 | +--> statement-breakpoint | |
| 476 | +CREATE TABLE "listings" ( | |
| 477 | + "id" text PRIMARY KEY NOT NULL, | |
| 478 | + "asset_id" text NOT NULL, | |
| 479 | + "variant_id" text, | |
| 480 | + "source_id" text NOT NULL, | |
| 481 | + "connector_id" text NOT NULL, | |
| 482 | + "raw_record_id" text, | |
| 483 | + "source_url" text NOT NULL, | |
| 484 | + "external_id" text NOT NULL, | |
| 485 | + "listing_type" text DEFAULT 'unknown' NOT NULL, | |
| 486 | + "price" numeric(18, 4), | |
| 487 | + "currency" text, | |
| 488 | + "price_usd" numeric(18, 4), | |
| 489 | + "seller" text, | |
| 490 | + "seller_reputation" text, | |
| 491 | + "location" text, | |
| 492 | + "shipping_cost" numeric(18, 4), | |
| 493 | + "quantity" integer, | |
| 494 | + "condition" text, | |
| 495 | + "grader" text, | |
| 496 | + "grade" text, | |
| 497 | + "certification_number" text, | |
| 498 | + "image_urls" jsonb DEFAULT '[]'::jsonb NOT NULL, | |
| 499 | + "raw_title" text NOT NULL, | |
| 500 | + "description" text, | |
| 501 | + "listed_at" timestamp with time zone, | |
| 502 | + "ends_at" timestamp with time zone, | |
| 503 | + "availability" text DEFAULT 'available' NOT NULL, | |
| 504 | + "bid_count" integer, | |
| 505 | + "first_seen_at" timestamp with time zone NOT NULL, | |
| 506 | + "last_seen_at" timestamp with time zone NOT NULL, | |
| 507 | + "price_changed_at" timestamp with time zone, | |
| 508 | + "cross_listing_group_id" text, | |
| 509 | + "confidence" numeric(8, 6) DEFAULT 0.8 NOT NULL, | |
| 510 | + "data_quality" real DEFAULT 0 NOT NULL, | |
| 511 | + "flags" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 512 | + "discount_to_riv" numeric(8, 6), | |
| 513 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL, | |
| 514 | + "updated_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 515 | +); | |
| 516 | +--> statement-breakpoint | |
| 517 | +CREATE TABLE "news" ( | |
| 518 | + "id" text PRIMARY KEY NOT NULL, | |
| 519 | + "source_id" text NOT NULL, | |
| 520 | + "url" text NOT NULL, | |
| 521 | + "title" text NOT NULL, | |
| 522 | + "summary" text, | |
| 523 | + "ai_summary" text, | |
| 524 | + "published_at" timestamp with time zone, | |
| 525 | + "category_slugs" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 526 | + "news_type" text, | |
| 527 | + "image_url" text, | |
| 528 | + "fetched_at" timestamp with time zone NOT NULL | |
| 529 | +); | |
| 530 | +--> statement-breakpoint | |
| 531 | +CREATE TABLE "price_observations" ( | |
| 532 | + "id" text PRIMARY KEY NOT NULL, | |
| 533 | + "asset_id" text NOT NULL, | |
| 534 | + "variant_id" text, | |
| 535 | + "source_id" text NOT NULL, | |
| 536 | + "connector_id" text NOT NULL, | |
| 537 | + "raw_record_id" text, | |
| 538 | + "source_url" text NOT NULL, | |
| 539 | + "price_kind" text NOT NULL, | |
| 540 | + "price" numeric(18, 4) NOT NULL, | |
| 541 | + "currency" text NOT NULL, | |
| 542 | + "price_usd" numeric(18, 4) NOT NULL, | |
| 543 | + "observation_date" date NOT NULL, | |
| 544 | + "sample_size" integer, | |
| 545 | + "dedupe_key" text NOT NULL, | |
| 546 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 547 | +); | |
| 548 | +--> statement-breakpoint | |
| 549 | +CREATE TABLE "sales" ( | |
| 550 | + "id" text PRIMARY KEY NOT NULL, | |
| 551 | + "asset_id" text NOT NULL, | |
| 552 | + "variant_id" text, | |
| 553 | + "source_id" text NOT NULL, | |
| 554 | + "connector_id" text NOT NULL, | |
| 555 | + "raw_record_id" text, | |
| 556 | + "normalized_record_id" text, | |
| 557 | + "source_url" text NOT NULL, | |
| 558 | + "external_id" text, | |
| 559 | + "sale_type" text DEFAULT 'unknown' NOT NULL, | |
| 560 | + "sale_date" timestamp with time zone NOT NULL, | |
| 561 | + "price" numeric(18, 4) NOT NULL, | |
| 562 | + "currency" text NOT NULL, | |
| 563 | + "price_usd" numeric(18, 4) NOT NULL, | |
| 564 | + "fx_rate" real, | |
| 565 | + "fx_date" date, | |
| 566 | + "buyer_premium_included" boolean, | |
| 567 | + "quantity" integer DEFAULT 1 NOT NULL, | |
| 568 | + "is_bundle" boolean DEFAULT false NOT NULL, | |
| 569 | + "condition" text, | |
| 570 | + "grader" text, | |
| 571 | + "grade" text, | |
| 572 | + "certification_number" text, | |
| 573 | + "location" text, | |
| 574 | + "auction_house" text, | |
| 575 | + "lot_number" text, | |
| 576 | + "image_urls" jsonb DEFAULT '[]'::jsonb NOT NULL, | |
| 577 | + "raw_title" text NOT NULL, | |
| 578 | + "confidence" numeric(8, 6) DEFAULT 0.8 NOT NULL, | |
| 579 | + "data_quality" real DEFAULT 0 NOT NULL, | |
| 580 | + "status" text DEFAULT 'valid' NOT NULL, | |
| 581 | + "flags" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 582 | + "dedupe_key" text NOT NULL, | |
| 583 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 584 | +); | |
| 585 | +--> statement-breakpoint | |
| 586 | +CREATE TABLE "benchmarks" ( | |
| 587 | + "ticker" text NOT NULL, | |
| 588 | + "date" date NOT NULL, | |
| 589 | + "value" real NOT NULL, | |
| 590 | + "source" text NOT NULL, | |
| 591 | + CONSTRAINT "benchmarks_ticker_date_pk" PRIMARY KEY("ticker","date") | |
| 592 | +); | |
| 593 | +--> statement-breakpoint | |
| 594 | +CREATE TABLE "category_snapshots" ( | |
| 595 | + "category_slug" text NOT NULL, | |
| 596 | + "date" date NOT NULL, | |
| 597 | + "index_value" real, | |
| 598 | + "tracked_assets" integer DEFAULT 0 NOT NULL, | |
| 599 | + "assets_with_valuation" integer DEFAULT 0 NOT NULL, | |
| 600 | + "sales" integer DEFAULT 0 NOT NULL, | |
| 601 | + "volume_usd" numeric(18, 4), | |
| 602 | + "median_sale_usd" numeric(18, 4), | |
| 603 | + "active_listings" integer DEFAULT 0 NOT NULL, | |
| 604 | + "market_cap_est_usd" numeric(18, 4), | |
| 605 | + "liquidity_score" real, | |
| 606 | + "change_1d" numeric(8, 6), | |
| 607 | + "change_7d" numeric(8, 6), | |
| 608 | + "change_30d" numeric(8, 6), | |
| 609 | + "change_1y" numeric(8, 6), | |
| 610 | + CONSTRAINT "category_snapshots_category_slug_date_pk" PRIMARY KEY("category_slug","date") | |
| 611 | +); | |
| 612 | +--> statement-breakpoint | |
| 613 | +CREATE TABLE "correlations" ( | |
| 614 | + "a" text NOT NULL, | |
| 615 | + "b" text NOT NULL, | |
| 616 | + "window_days" integer NOT NULL, | |
| 617 | + "coefficient" real NOT NULL, | |
| 618 | + "observations" integer NOT NULL, | |
| 619 | + "computed_at" timestamp with time zone NOT NULL, | |
| 620 | + CONSTRAINT "correlations_a_b_window_days_pk" PRIMARY KEY("a","b","window_days") | |
| 621 | +); | |
| 622 | +--> statement-breakpoint | |
| 623 | +CREATE TABLE "index_constituents" ( | |
| 624 | + "index_id" text NOT NULL, | |
| 625 | + "asset_id" text NOT NULL, | |
| 626 | + "variant_id" text DEFAULT '' NOT NULL, | |
| 627 | + "weight" real DEFAULT 1 NOT NULL, | |
| 628 | + "added_at" date NOT NULL, | |
| 629 | + "removed_at" date, | |
| 630 | + "reason" text, | |
| 631 | + CONSTRAINT "index_constituents_index_id_asset_id_variant_id_added_at_pk" PRIMARY KEY("index_id","asset_id","variant_id","added_at") | |
| 632 | +); | |
| 633 | +--> statement-breakpoint | |
| 634 | +CREATE TABLE "index_values" ( | |
| 635 | + "index_id" text NOT NULL, | |
| 636 | + "date" date NOT NULL, | |
| 637 | + "value" real NOT NULL, | |
| 638 | + "constituents_count" integer DEFAULT 0 NOT NULL, | |
| 639 | + "transactions" integer DEFAULT 0 NOT NULL, | |
| 640 | + "volume_usd" numeric(18, 4), | |
| 641 | + "median_sale_usd" numeric(18, 4), | |
| 642 | + "avg_sale_usd" numeric(18, 4), | |
| 643 | + "market_cap_est_usd" numeric(18, 4), | |
| 644 | + "market_cap_confidence" text, | |
| 645 | + "liquidity_score" real, | |
| 646 | + "momentum" real, | |
| 647 | + "breadth" integer, | |
| 648 | + "tracked_assets" integer, | |
| 649 | + "coverage" real, | |
| 650 | + CONSTRAINT "index_values_index_id_date_pk" PRIMARY KEY("index_id","date") | |
| 651 | +); | |
| 652 | +--> statement-breakpoint | |
| 653 | +CREATE TABLE "indices" ( | |
| 654 | + "id" text PRIMARY KEY NOT NULL, | |
| 655 | + "ticker" text NOT NULL, | |
| 656 | + "name" text NOT NULL, | |
| 657 | + "description" text, | |
| 658 | + "category_slugs" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 659 | + "family_slugs" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 660 | + "parent_ticker" text, | |
| 661 | + "methodology" text DEFAULT 'chain_linked_equal_weight_v1' NOT NULL, | |
| 662 | + "weighting" text DEFAULT 'equal' NOT NULL, | |
| 663 | + "base_date" date NOT NULL, | |
| 664 | + "base_value" real DEFAULT 1000 NOT NULL, | |
| 665 | + "min_constituents" integer DEFAULT 10 NOT NULL, | |
| 666 | + "active" boolean DEFAULT true NOT NULL, | |
| 667 | + "is_flagship" boolean DEFAULT false NOT NULL, | |
| 668 | + "color" text, | |
| 669 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL, | |
| 670 | + CONSTRAINT "indices_ticker_unique" UNIQUE("ticker") | |
| 671 | +); | |
| 672 | +--> statement-breakpoint | |
| 673 | +CREATE TABLE "price_snapshots" ( | |
| 674 | + "asset_id" text NOT NULL, | |
| 675 | + "variant_id" text DEFAULT '' NOT NULL, | |
| 676 | + "date" date NOT NULL, | |
| 677 | + "riv_usd" numeric(18, 4), | |
| 678 | + "latest_sale_usd" numeric(18, 4), | |
| 679 | + "median_usd" numeric(18, 4), | |
| 680 | + "sales_count" integer DEFAULT 0 NOT NULL, | |
| 681 | + "volume_usd" numeric(18, 4), | |
| 682 | + "listings_count" integer DEFAULT 0 NOT NULL, | |
| 683 | + "min_ask_usd" numeric(18, 4), | |
| 684 | + "observation_usd" numeric(18, 4), | |
| 685 | + CONSTRAINT "price_snapshots_asset_id_variant_id_date_pk" PRIMARY KEY("asset_id","variant_id","date") | |
| 686 | +); | |
| 687 | +--> statement-breakpoint | |
| 688 | +CREATE TABLE "radar_findings" ( | |
| 689 | + "id" text PRIMARY KEY NOT NULL, | |
| 690 | + "asset_id" text NOT NULL, | |
| 691 | + "kind" text NOT NULL, | |
| 692 | + "score" real NOT NULL, | |
| 693 | + "evidence" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 694 | + "entity_type" text, | |
| 695 | + "entity_id" text, | |
| 696 | + "detected_at" timestamp with time zone NOT NULL, | |
| 697 | + "expires_at" timestamp with time zone | |
| 698 | +); | |
| 699 | +--> statement-breakpoint | |
| 700 | +CREATE TABLE "valuations" ( | |
| 701 | + "id" text PRIMARY KEY NOT NULL, | |
| 702 | + "asset_id" text NOT NULL, | |
| 703 | + "variant_id" text, | |
| 704 | + "computed_at" timestamp with time zone NOT NULL, | |
| 705 | + "riv_usd" numeric(18, 4), | |
| 706 | + "low_usd" numeric(18, 4), | |
| 707 | + "high_usd" numeric(18, 4), | |
| 708 | + "confidence" numeric(8, 6) DEFAULT 0 NOT NULL, | |
| 709 | + "confidence_label" text DEFAULT 'insufficient' NOT NULL, | |
| 710 | + "sample_size" integer DEFAULT 0 NOT NULL, | |
| 711 | + "window_days" integer DEFAULT 365 NOT NULL, | |
| 712 | + "methods" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 713 | + "sales_used" text[] DEFAULT '{}'::text[] NOT NULL, | |
| 714 | + "observations_used" integer DEFAULT 0 NOT NULL, | |
| 715 | + "method" text DEFAULT 'ensemble_v1' NOT NULL, | |
| 716 | + "notes" text[] DEFAULT '{}'::text[] NOT NULL | |
| 717 | +); | |
| 718 | +--> statement-breakpoint | |
| 719 | +CREATE TABLE "alert_events" ( | |
| 720 | + "id" text PRIMARY KEY NOT NULL, | |
| 721 | + "alert_id" text NOT NULL, | |
| 722 | + "user_id" text NOT NULL, | |
| 723 | + "message" text NOT NULL, | |
| 724 | + "payload" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 725 | + "read_at" timestamp with time zone, | |
| 726 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 727 | +); | |
| 728 | +--> statement-breakpoint | |
| 729 | +CREATE TABLE "alerts" ( | |
| 730 | + "id" text PRIMARY KEY NOT NULL, | |
| 731 | + "user_id" text NOT NULL, | |
| 732 | + "alert_type" text NOT NULL, | |
| 733 | + "target_type" text NOT NULL, | |
| 734 | + "target_id" text NOT NULL, | |
| 735 | + "threshold" numeric(18, 4), | |
| 736 | + "currency" text, | |
| 737 | + "params" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 738 | + "channel" text DEFAULT 'inapp' NOT NULL, | |
| 739 | + "active" boolean DEFAULT true NOT NULL, | |
| 740 | + "last_triggered_at" timestamp with time zone, | |
| 741 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 742 | +); | |
| 743 | +--> statement-breakpoint | |
| 744 | +CREATE TABLE "api_keys" ( | |
| 745 | + "id" text PRIMARY KEY NOT NULL, | |
| 746 | + "user_id" text, | |
| 747 | + "name" text NOT NULL, | |
| 748 | + "prefix" text NOT NULL, | |
| 749 | + "key_hash" text NOT NULL, | |
| 750 | + "tier" text DEFAULT 'free' NOT NULL, | |
| 751 | + "rate_limit_per_minute" integer DEFAULT 60 NOT NULL, | |
| 752 | + "daily_quota" integer DEFAULT 1000 NOT NULL, | |
| 753 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL, | |
| 754 | + "last_used_at" timestamp with time zone, | |
| 755 | + "revoked_at" timestamp with time zone, | |
| 756 | + CONSTRAINT "api_keys_key_hash_unique" UNIQUE("key_hash") | |
| 757 | +); | |
| 758 | +--> statement-breakpoint | |
| 759 | +CREATE TABLE "api_usage" ( | |
| 760 | + "key_id" text NOT NULL, | |
| 761 | + "date" date NOT NULL, | |
| 762 | + "endpoint" text NOT NULL, | |
| 763 | + "count" integer DEFAULT 0 NOT NULL, | |
| 764 | + "latency_ms_avg" real, | |
| 765 | + CONSTRAINT "api_usage_key_id_date_endpoint_pk" PRIMARY KEY("key_id","date","endpoint") | |
| 766 | +); | |
| 767 | +--> statement-breakpoint | |
| 768 | +CREATE TABLE "asset_views" ( | |
| 769 | + "asset_id" text NOT NULL, | |
| 770 | + "date" date NOT NULL, | |
| 771 | + "views" integer DEFAULT 0 NOT NULL, | |
| 772 | + CONSTRAINT "asset_views_asset_id_date_pk" PRIMARY KEY("asset_id","date") | |
| 773 | +); | |
| 774 | +--> statement-breakpoint | |
| 775 | +CREATE TABLE "collection_items" ( | |
| 776 | + "id" text PRIMARY KEY NOT NULL, | |
| 777 | + "collection_id" text NOT NULL, | |
| 778 | + "asset_id" text NOT NULL, | |
| 779 | + "variant_id" text, | |
| 780 | + "quantity" integer DEFAULT 1 NOT NULL, | |
| 781 | + "acquired_at" date, | |
| 782 | + "purchase_price" numeric(18, 4), | |
| 783 | + "purchase_currency" text, | |
| 784 | + "purchase_price_usd" numeric(18, 4), | |
| 785 | + "source" text, | |
| 786 | + "grader" text, | |
| 787 | + "grade" text, | |
| 788 | + "certification_number" text, | |
| 789 | + "serial" text, | |
| 790 | + "photos" jsonb DEFAULT '[]'::jsonb NOT NULL, | |
| 791 | + "notes" text, | |
| 792 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL, | |
| 793 | + "updated_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 794 | +); | |
| 795 | +--> statement-breakpoint | |
| 796 | +CREATE TABLE "collection_snapshots" ( | |
| 797 | + "collection_id" text NOT NULL, | |
| 798 | + "date" date NOT NULL, | |
| 799 | + "value_usd" numeric(18, 4) NOT NULL, | |
| 800 | + "cost_basis_usd" numeric(18, 4) NOT NULL, | |
| 801 | + "items" integer NOT NULL, | |
| 802 | + CONSTRAINT "collection_snapshots_collection_id_date_pk" PRIMARY KEY("collection_id","date") | |
| 803 | +); | |
| 804 | +--> statement-breakpoint | |
| 805 | +CREATE TABLE "collections" ( | |
| 806 | + "id" text PRIMARY KEY NOT NULL, | |
| 807 | + "user_id" text NOT NULL, | |
| 808 | + "name" text NOT NULL, | |
| 809 | + "description" text, | |
| 810 | + "is_public" boolean DEFAULT false NOT NULL, | |
| 811 | + "public_slug" text, | |
| 812 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL, | |
| 813 | + "updated_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 814 | +); | |
| 815 | +--> statement-breakpoint | |
| 816 | +CREATE TABLE "search_log" ( | |
| 817 | + "id" text PRIMARY KEY NOT NULL, | |
| 818 | + "query" text NOT NULL, | |
| 819 | + "normalized" text NOT NULL, | |
| 820 | + "results" integer NOT NULL, | |
| 821 | + "user_id" text, | |
| 822 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 823 | +); | |
| 824 | +--> statement-breakpoint | |
| 825 | +CREATE TABLE "sessions" ( | |
| 826 | + "id" text PRIMARY KEY NOT NULL, | |
| 827 | + "user_id" text NOT NULL, | |
| 828 | + "expires_at" timestamp with time zone NOT NULL, | |
| 829 | + "user_agent" text, | |
| 830 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 831 | +); | |
| 832 | +--> statement-breakpoint | |
| 833 | +CREATE TABLE "users" ( | |
| 834 | + "id" text PRIMARY KEY NOT NULL, | |
| 835 | + "email" text NOT NULL, | |
| 836 | + "email_verified_at" timestamp with time zone, | |
| 837 | + "password_hash" text, | |
| 838 | + "name" text, | |
| 839 | + "role" text DEFAULT 'user' NOT NULL, | |
| 840 | + "display_currency" text DEFAULT 'USD' NOT NULL, | |
| 841 | + "providers" jsonb DEFAULT '[]'::jsonb NOT NULL, | |
| 842 | + "preferences" jsonb DEFAULT '{}'::jsonb NOT NULL, | |
| 843 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL, | |
| 844 | + "last_login_at" timestamp with time zone, | |
| 845 | + CONSTRAINT "users_email_unique" UNIQUE("email") | |
| 846 | +); | |
| 847 | +--> statement-breakpoint | |
| 848 | +CREATE TABLE "watchlist_items" ( | |
| 849 | + "id" text PRIMARY KEY NOT NULL, | |
| 850 | + "watchlist_id" text NOT NULL, | |
| 851 | + "target_type" text NOT NULL, | |
| 852 | + "target_id" text NOT NULL, | |
| 853 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 854 | +); | |
| 855 | +--> statement-breakpoint | |
| 856 | +CREATE TABLE "watchlists" ( | |
| 857 | + "id" text PRIMARY KEY NOT NULL, | |
| 858 | + "user_id" text NOT NULL, | |
| 859 | + "name" text DEFAULT 'Watchlist' NOT NULL, | |
| 860 | + "created_at" timestamp with time zone DEFAULT now() NOT NULL | |
| 861 | +); | |
| 862 | +--> statement-breakpoint | |
| 863 | +CREATE INDEX "brands_name_idx" ON "brands" USING btree ("name");--> statement-breakpoint | |
| 864 | +CREATE INDEX "categories_parent_idx" ON "categories" USING btree ("parent_slug");--> statement-breakpoint | |
| 865 | +CREATE INDEX "categories_family_idx" ON "categories" USING btree ("family_slug");--> statement-breakpoint | |
| 866 | +CREATE INDEX "sets_category_idx" ON "sets" USING btree ("category_slug");--> statement-breakpoint | |
| 867 | +CREATE UNIQUE INDEX "sets_category_code_uq" ON "sets" USING btree ("category_slug","code");--> statement-breakpoint | |
| 868 | +CREATE INDEX "connector_runs_connector_started_idx" ON "connector_runs" USING btree ("connector_id","started_at");--> statement-breakpoint | |
| 869 | +CREATE INDEX "costs_occurred_idx" ON "costs" USING btree ("occurred_at");--> statement-breakpoint | |
| 870 | +CREATE INDEX "costs_connector_idx" ON "costs" USING btree ("connector_id");--> statement-breakpoint | |
| 871 | +CREATE INDEX "crawl_state_next_idx" ON "crawl_state" USING btree ("connector_id","next_fetch_at");--> statement-breakpoint | |
| 872 | +CREATE INDEX "audit_entity_idx" ON "audit_log" USING btree ("entity_type","entity_id");--> statement-breakpoint | |
| 873 | +CREATE INDEX "events_type_created_idx" ON "events" USING btree ("type","created_at");--> statement-breakpoint | |
| 874 | +CREATE INDEX "events_entity_idx" ON "events" USING btree ("entity_type","entity_id");--> statement-breakpoint | |
| 875 | +CREATE INDEX "normalized_records_status_idx" ON "normalized_records" USING btree ("status","created_at");--> statement-breakpoint | |
| 876 | +CREATE INDEX "normalized_records_asset_idx" ON "normalized_records" USING btree ("asset_id");--> statement-breakpoint | |
| 877 | +CREATE UNIQUE INDEX "normalized_records_raw_uq" ON "normalized_records" USING btree ("raw_record_id");--> statement-breakpoint | |
| 878 | +CREATE UNIQUE INDEX "raw_records_connector_hash_uq" ON "raw_records" USING btree ("connector_id","content_hash");--> statement-breakpoint | |
| 879 | +CREATE INDEX "raw_records_connector_fetched_idx" ON "raw_records" USING btree ("connector_id","fetched_at");--> statement-breakpoint | |
| 880 | +CREATE INDEX "raw_records_unprocessed_idx" ON "raw_records" USING btree ("processed_at");--> statement-breakpoint | |
| 881 | +CREATE INDEX "raw_records_external_idx" ON "raw_records" USING btree ("connector_id","external_id");--> statement-breakpoint | |
| 882 | +CREATE INDEX "asset_stats_riv_idx" ON "asset_stats" USING btree ("riv_usd");--> statement-breakpoint | |
| 883 | +CREATE INDEX "asset_stats_trending_idx" ON "asset_stats" USING btree ("trending_score");--> statement-breakpoint | |
| 884 | +CREATE INDEX "asset_stats_liquidity_idx" ON "asset_stats" USING btree ("liquidity_score");--> statement-breakpoint | |
| 885 | +CREATE UNIQUE INDEX "asset_variants_uq" ON "asset_variants" USING btree ("asset_id","variant_key");--> statement-breakpoint | |
| 886 | +CREATE INDEX "asset_variants_asset_idx" ON "asset_variants" USING btree ("asset_id");--> statement-breakpoint | |
| 887 | +CREATE UNIQUE INDEX "assets_canonical_key_uq" ON "assets" USING btree ("canonical_key");--> statement-breakpoint | |
| 888 | +CREATE UNIQUE INDEX "assets_slug_uq" ON "assets" USING btree ("slug");--> statement-breakpoint | |
| 889 | +CREATE INDEX "assets_category_idx" ON "assets" USING btree ("category_slug");--> statement-breakpoint | |
| 890 | +CREATE INDEX "assets_family_idx" ON "assets" USING btree ("family_slug");--> statement-breakpoint | |
| 891 | +CREATE INDEX "assets_set_idx" ON "assets" USING btree ("set_slug");--> statement-breakpoint | |
| 892 | +CREATE INDEX "assets_search_gin" ON "assets" USING gin ("search");--> statement-breakpoint | |
| 893 | +CREATE INDEX "assets_title_trgm" ON "assets" USING gin ("title" gin_trgm_ops);--> statement-breakpoint | |
| 894 | +CREATE INDEX "assets_identifiers_gin" ON "assets" USING gin ("identifiers");--> statement-breakpoint | |
| 895 | +CREATE UNIQUE INDEX "grade_premiums_uq" ON "grade_premiums" USING btree ("category_slug","grader","grade");--> statement-breakpoint | |
| 896 | +CREATE INDEX "images_asset_idx" ON "images" USING btree ("asset_id");--> statement-breakpoint | |
| 897 | +CREATE INDEX "images_phash_idx" ON "images" USING btree ("phash");--> statement-breakpoint | |
| 898 | +CREATE UNIQUE INDEX "images_url_uq" ON "images" USING btree ("url");--> statement-breakpoint | |
| 899 | +CREATE UNIQUE INDEX "population_reports_uq" ON "population_reports" USING btree ("asset_id","grader","report_date");--> statement-breakpoint | |
| 900 | +CREATE UNIQUE INDEX "auction_lots_url_uq" ON "auction_lots" USING btree ("url");--> statement-breakpoint | |
| 901 | +CREATE INDEX "auction_lots_auction_idx" ON "auction_lots" USING btree ("auction_id");--> statement-breakpoint | |
| 902 | +CREATE INDEX "auction_lots_asset_idx" ON "auction_lots" USING btree ("asset_id");--> statement-breakpoint | |
| 903 | +CREATE INDEX "auction_lots_ends_idx" ON "auction_lots" USING btree ("ends_at");--> statement-breakpoint | |
| 904 | +CREATE UNIQUE INDEX "auctions_url_uq" ON "auctions" USING btree ("url");--> statement-breakpoint | |
| 905 | +CREATE INDEX "auctions_ends_idx" ON "auctions" USING btree ("ends_at");--> statement-breakpoint | |
| 906 | +CREATE UNIQUE INDEX "fx_rates_uq" ON "fx_rates" USING btree ("date","base","quote");--> statement-breakpoint | |
| 907 | +CREATE INDEX "listing_events_listing_idx" ON "listing_events" USING btree ("listing_id","occurred_at");--> statement-breakpoint | |
| 908 | +CREATE UNIQUE INDEX "listings_source_external_uq" ON "listings" USING btree ("source_id","external_id");--> statement-breakpoint | |
| 909 | +CREATE INDEX "listings_asset_avail_idx" ON "listings" USING btree ("asset_id","availability");--> statement-breakpoint | |
| 910 | +CREATE INDEX "listings_avail_price_idx" ON "listings" USING btree ("availability","price_usd");--> statement-breakpoint | |
| 911 | +CREATE INDEX "listings_ends_idx" ON "listings" USING btree ("ends_at");--> statement-breakpoint | |
| 912 | +CREATE INDEX "listings_last_seen_idx" ON "listings" USING btree ("last_seen_at");--> statement-breakpoint | |
| 913 | +CREATE UNIQUE INDEX "news_url_uq" ON "news" USING btree ("url");--> statement-breakpoint | |
| 914 | +CREATE INDEX "news_published_idx" ON "news" USING btree ("published_at");--> statement-breakpoint | |
| 915 | +CREATE UNIQUE INDEX "price_observations_dedupe_uq" ON "price_observations" USING btree ("dedupe_key");--> statement-breakpoint | |
| 916 | +CREATE INDEX "price_observations_asset_date_idx" ON "price_observations" USING btree ("asset_id","observation_date");--> statement-breakpoint | |
| 917 | +CREATE UNIQUE INDEX "sales_dedupe_uq" ON "sales" USING btree ("dedupe_key");--> statement-breakpoint | |
| 918 | +CREATE INDEX "sales_asset_date_idx" ON "sales" USING btree ("asset_id","sale_date");--> statement-breakpoint | |
| 919 | +CREATE INDEX "sales_variant_date_idx" ON "sales" USING btree ("variant_id","sale_date");--> statement-breakpoint | |
| 920 | +CREATE INDEX "sales_source_idx" ON "sales" USING btree ("source_id","sale_date");--> statement-breakpoint | |
| 921 | +CREATE INDEX "sales_date_idx" ON "sales" USING btree ("sale_date");--> statement-breakpoint | |
| 922 | +CREATE INDEX "sales_price_idx" ON "sales" USING btree ("price_usd");--> statement-breakpoint | |
| 923 | +CREATE INDEX "index_constituents_asset_idx" ON "index_constituents" USING btree ("asset_id");--> statement-breakpoint | |
| 924 | +CREATE INDEX "price_snapshots_date_idx" ON "price_snapshots" USING btree ("date");--> statement-breakpoint | |
| 925 | +CREATE INDEX "radar_kind_idx" ON "radar_findings" USING btree ("kind","detected_at");--> statement-breakpoint | |
| 926 | +CREATE UNIQUE INDEX "radar_entity_uq" ON "radar_findings" USING btree ("kind","entity_type","entity_id");--> statement-breakpoint | |
| 927 | +CREATE INDEX "valuations_asset_idx" ON "valuations" USING btree ("asset_id","computed_at");--> statement-breakpoint | |
| 928 | +CREATE INDEX "valuations_variant_idx" ON "valuations" USING btree ("variant_id","computed_at");--> statement-breakpoint | |
| 929 | +CREATE INDEX "alert_events_user_idx" ON "alert_events" USING btree ("user_id","created_at");--> statement-breakpoint | |
| 930 | +CREATE INDEX "alerts_user_idx" ON "alerts" USING btree ("user_id");--> statement-breakpoint | |
| 931 | +CREATE INDEX "alerts_target_idx" ON "alerts" USING btree ("target_type","target_id","active");--> statement-breakpoint | |
| 932 | +CREATE INDEX "api_keys_user_idx" ON "api_keys" USING btree ("user_id");--> statement-breakpoint | |
| 933 | +CREATE INDEX "collection_items_collection_idx" ON "collection_items" USING btree ("collection_id");--> statement-breakpoint | |
| 934 | +CREATE INDEX "collection_items_asset_idx" ON "collection_items" USING btree ("asset_id");--> statement-breakpoint | |
| 935 | +CREATE INDEX "collections_user_idx" ON "collections" USING btree ("user_id");--> statement-breakpoint | |
| 936 | +CREATE UNIQUE INDEX "collections_public_slug_uq" ON "collections" USING btree ("public_slug");--> statement-breakpoint | |
| 937 | +CREATE INDEX "search_log_created_idx" ON "search_log" USING btree ("created_at");--> statement-breakpoint | |
| 938 | +CREATE INDEX "search_log_normalized_idx" ON "search_log" USING btree ("normalized");--> statement-breakpoint | |
| 939 | +CREATE INDEX "sessions_user_idx" ON "sessions" USING btree ("user_id");--> statement-breakpoint | |
| 940 | +CREATE UNIQUE INDEX "watchlist_items_uq" ON "watchlist_items" USING btree ("watchlist_id","target_type","target_id");--> statement-breakpoint | |
| 941 | +CREATE INDEX "watchlists_user_idx" ON "watchlists" USING btree ("user_id"); | |
| \ No newline at end of file | ||
added
packages/database/migrations/meta/0000_snapshot.json
+6579 −0
@@ -0,0 +1,6579 @@ | ||
| 1 | +{ | |
| 2 | + "id": "5a9ca0fc-7e8f-4e45-90e0-6c16a3a6a052", | |
| 3 | + "prevId": "00000000-0000-0000-0000-000000000000", | |
| 4 | + "version": "7", | |
| 5 | + "dialect": "postgresql", | |
| 6 | + "tables": { | |
| 7 | + "public.brands": { | |
| 8 | + "name": "brands", | |
| 9 | + "schema": "", | |
| 10 | + "columns": { | |
| 11 | + "slug": { | |
| 12 | + "name": "slug", | |
| 13 | + "type": "text", | |
| 14 | + "primaryKey": true, | |
| 15 | + "notNull": true | |
| 16 | + }, | |
| 17 | + "name": { | |
| 18 | + "name": "name", | |
| 19 | + "type": "text", | |
| 20 | + "primaryKey": false, | |
| 21 | + "notNull": true | |
| 22 | + }, | |
| 23 | + "category_slugs": { | |
| 24 | + "name": "category_slugs", | |
| 25 | + "type": "text[]", | |
| 26 | + "primaryKey": false, | |
| 27 | + "notNull": true, | |
| 28 | + "default": "'{}'::text[]" | |
| 29 | + }, | |
| 30 | + "country": { | |
| 31 | + "name": "country", | |
| 32 | + "type": "text", | |
| 33 | + "primaryKey": false, | |
| 34 | + "notNull": false | |
| 35 | + }, | |
| 36 | + "founded_year": { | |
| 37 | + "name": "founded_year", | |
| 38 | + "type": "integer", | |
| 39 | + "primaryKey": false, | |
| 40 | + "notNull": false | |
| 41 | + }, | |
| 42 | + "metadata": { | |
| 43 | + "name": "metadata", | |
| 44 | + "type": "jsonb", | |
| 45 | + "primaryKey": false, | |
| 46 | + "notNull": true, | |
| 47 | + "default": "'{}'::jsonb" | |
| 48 | + }, | |
| 49 | + "created_at": { | |
| 50 | + "name": "created_at", | |
| 51 | + "type": "timestamp with time zone", | |
| 52 | + "primaryKey": false, | |
| 53 | + "notNull": true, | |
| 54 | + "default": "now()" | |
| 55 | + } | |
| 56 | + }, | |
| 57 | + "indexes": { | |
| 58 | + "brands_name_idx": { | |
| 59 | + "name": "brands_name_idx", | |
| 60 | + "columns": [ | |
| 61 | + { | |
| 62 | + "expression": "name", | |
| 63 | + "isExpression": false, | |
| 64 | + "asc": true, | |
| 65 | + "nulls": "last" | |
| 66 | + } | |
| 67 | + ], | |
| 68 | + "isUnique": false, | |
| 69 | + "concurrently": false, | |
| 70 | + "method": "btree", | |
| 71 | + "with": {} | |
| 72 | + } | |
| 73 | + }, | |
| 74 | + "foreignKeys": {}, | |
| 75 | + "compositePrimaryKeys": {}, | |
| 76 | + "uniqueConstraints": {}, | |
| 77 | + "policies": {}, | |
| 78 | + "checkConstraints": {}, | |
| 79 | + "isRLSEnabled": false | |
| 80 | + }, | |
| 81 | + "public.categories": { | |
| 82 | + "name": "categories", | |
| 83 | + "schema": "", | |
| 84 | + "columns": { | |
| 85 | + "slug": { | |
| 86 | + "name": "slug", | |
| 87 | + "type": "text", | |
| 88 | + "primaryKey": true, | |
| 89 | + "notNull": true | |
| 90 | + }, | |
| 91 | + "parent_slug": { | |
| 92 | + "name": "parent_slug", | |
| 93 | + "type": "text", | |
| 94 | + "primaryKey": false, | |
| 95 | + "notNull": false | |
| 96 | + }, | |
| 97 | + "family_slug": { | |
| 98 | + "name": "family_slug", | |
| 99 | + "type": "text", | |
| 100 | + "primaryKey": false, | |
| 101 | + "notNull": true | |
| 102 | + }, | |
| 103 | + "name": { | |
| 104 | + "name": "name", | |
| 105 | + "type": "text", | |
| 106 | + "primaryKey": false, | |
| 107 | + "notNull": true | |
| 108 | + }, | |
| 109 | + "short_name": { | |
| 110 | + "name": "short_name", | |
| 111 | + "type": "text", | |
| 112 | + "primaryKey": false, | |
| 113 | + "notNull": false | |
| 114 | + }, | |
| 115 | + "description": { | |
| 116 | + "name": "description", | |
| 117 | + "type": "text", | |
| 118 | + "primaryKey": false, | |
| 119 | + "notNull": false | |
| 120 | + }, | |
| 121 | + "level": { | |
| 122 | + "name": "level", | |
| 123 | + "type": "integer", | |
| 124 | + "primaryKey": false, | |
| 125 | + "notNull": true, | |
| 126 | + "default": 0 | |
| 127 | + }, | |
| 128 | + "phase": { | |
| 129 | + "name": "phase", | |
| 130 | + "type": "integer", | |
| 131 | + "primaryKey": false, | |
| 132 | + "notNull": true, | |
| 133 | + "default": 3 | |
| 134 | + }, | |
| 135 | + "active": { | |
| 136 | + "name": "active", | |
| 137 | + "type": "boolean", | |
| 138 | + "primaryKey": false, | |
| 139 | + "notNull": true, | |
| 140 | + "default": true | |
| 141 | + }, | |
| 142 | + "condition_scale": { | |
| 143 | + "name": "condition_scale", | |
| 144 | + "type": "text", | |
| 145 | + "primaryKey": false, | |
| 146 | + "notNull": false | |
| 147 | + }, | |
| 148 | + "graders": { | |
| 149 | + "name": "graders", | |
| 150 | + "type": "text[]", | |
| 151 | + "primaryKey": false, | |
| 152 | + "notNull": true, | |
| 153 | + "default": "'{}'::text[]" | |
| 154 | + }, | |
| 155 | + "index_ticker": { | |
| 156 | + "name": "index_ticker", | |
| 157 | + "type": "text", | |
| 158 | + "primaryKey": false, | |
| 159 | + "notNull": false | |
| 160 | + }, | |
| 161 | + "attribute_schema": { | |
| 162 | + "name": "attribute_schema", | |
| 163 | + "type": "jsonb", | |
| 164 | + "primaryKey": false, | |
| 165 | + "notNull": true, | |
| 166 | + "default": "'{}'::jsonb" | |
| 167 | + }, | |
| 168 | + "sort_order": { | |
| 169 | + "name": "sort_order", | |
| 170 | + "type": "integer", | |
| 171 | + "primaryKey": false, | |
| 172 | + "notNull": true, | |
| 173 | + "default": 0 | |
| 174 | + }, | |
| 175 | + "compliance_flags": { | |
| 176 | + "name": "compliance_flags", | |
| 177 | + "type": "text[]", | |
| 178 | + "primaryKey": false, | |
| 179 | + "notNull": true, | |
| 180 | + "default": "'{}'::text[]" | |
| 181 | + }, | |
| 182 | + "icon": { | |
| 183 | + "name": "icon", | |
| 184 | + "type": "text", | |
| 185 | + "primaryKey": false, | |
| 186 | + "notNull": false | |
| 187 | + }, | |
| 188 | + "created_at": { | |
| 189 | + "name": "created_at", | |
| 190 | + "type": "timestamp with time zone", | |
| 191 | + "primaryKey": false, | |
| 192 | + "notNull": true, | |
| 193 | + "default": "now()" | |
| 194 | + }, | |
| 195 | + "updated_at": { | |
| 196 | + "name": "updated_at", | |
| 197 | + "type": "timestamp with time zone", | |
| 198 | + "primaryKey": false, | |
| 199 | + "notNull": true, | |
| 200 | + "default": "now()" | |
| 201 | + } | |
| 202 | + }, | |
| 203 | + "indexes": { | |
| 204 | + "categories_parent_idx": { | |
| 205 | + "name": "categories_parent_idx", | |
| 206 | + "columns": [ | |
| 207 | + { | |
| 208 | + "expression": "parent_slug", | |
| 209 | + "isExpression": false, | |
| 210 | + "asc": true, | |
| 211 | + "nulls": "last" | |
| 212 | + } | |
| 213 | + ], | |
| 214 | + "isUnique": false, | |
| 215 | + "concurrently": false, | |
| 216 | + "method": "btree", | |
| 217 | + "with": {} | |
| 218 | + }, | |
| 219 | + "categories_family_idx": { | |
| 220 | + "name": "categories_family_idx", | |
| 221 | + "columns": [ | |
| 222 | + { | |
| 223 | + "expression": "family_slug", | |
| 224 | + "isExpression": false, | |
| 225 | + "asc": true, | |
| 226 | + "nulls": "last" | |
| 227 | + } | |
| 228 | + ], | |
| 229 | + "isUnique": false, | |
| 230 | + "concurrently": false, | |
| 231 | + "method": "btree", | |
| 232 | + "with": {} | |
| 233 | + } | |
| 234 | + }, | |
| 235 | + "foreignKeys": {}, | |
| 236 | + "compositePrimaryKeys": {}, | |
| 237 | + "uniqueConstraints": {}, | |
| 238 | + "policies": {}, | |
| 239 | + "checkConstraints": {}, | |
| 240 | + "isRLSEnabled": false | |
| 241 | + }, | |
| 242 | + "public.franchises": { | |
| 243 | + "name": "franchises", | |
| 244 | + "schema": "", | |
| 245 | + "columns": { | |
| 246 | + "slug": { | |
| 247 | + "name": "slug", | |
| 248 | + "type": "text", | |
| 249 | + "primaryKey": true, | |
| 250 | + "notNull": true | |
| 251 | + }, | |
| 252 | + "name": { | |
| 253 | + "name": "name", | |
| 254 | + "type": "text", | |
| 255 | + "primaryKey": false, | |
| 256 | + "notNull": true | |
| 257 | + }, | |
| 258 | + "owner": { | |
| 259 | + "name": "owner", | |
| 260 | + "type": "text", | |
| 261 | + "primaryKey": false, | |
| 262 | + "notNull": false | |
| 263 | + }, | |
| 264 | + "category_slugs": { | |
| 265 | + "name": "category_slugs", | |
| 266 | + "type": "text[]", | |
| 267 | + "primaryKey": false, | |
| 268 | + "notNull": true, | |
| 269 | + "default": "'{}'::text[]" | |
| 270 | + }, | |
| 271 | + "metadata": { | |
| 272 | + "name": "metadata", | |
| 273 | + "type": "jsonb", | |
| 274 | + "primaryKey": false, | |
| 275 | + "notNull": true, | |
| 276 | + "default": "'{}'::jsonb" | |
| 277 | + }, | |
| 278 | + "created_at": { | |
| 279 | + "name": "created_at", | |
| 280 | + "type": "timestamp with time zone", | |
| 281 | + "primaryKey": false, | |
| 282 | + "notNull": true, | |
| 283 | + "default": "now()" | |
| 284 | + } | |
| 285 | + }, | |
| 286 | + "indexes": {}, | |
| 287 | + "foreignKeys": {}, | |
| 288 | + "compositePrimaryKeys": {}, | |
| 289 | + "uniqueConstraints": {}, | |
| 290 | + "policies": {}, | |
| 291 | + "checkConstraints": {}, | |
| 292 | + "isRLSEnabled": false | |
| 293 | + }, | |
| 294 | + "public.graders": { | |
| 295 | + "name": "graders", | |
| 296 | + "schema": "", | |
| 297 | + "columns": { | |
| 298 | + "slug": { | |
| 299 | + "name": "slug", | |
| 300 | + "type": "text", | |
| 301 | + "primaryKey": true, | |
| 302 | + "notNull": true | |
| 303 | + }, | |
| 304 | + "name": { | |
| 305 | + "name": "name", | |
| 306 | + "type": "text", | |
| 307 | + "primaryKey": false, | |
| 308 | + "notNull": true | |
| 309 | + }, | |
| 310 | + "category_slugs": { | |
| 311 | + "name": "category_slugs", | |
| 312 | + "type": "text[]", | |
| 313 | + "primaryKey": false, | |
| 314 | + "notNull": true, | |
| 315 | + "default": "'{}'::text[]" | |
| 316 | + }, | |
| 317 | + "scale": { | |
| 318 | + "name": "scale", | |
| 319 | + "type": "jsonb", | |
| 320 | + "primaryKey": false, | |
| 321 | + "notNull": true, | |
| 322 | + "default": "'{}'::jsonb" | |
| 323 | + }, | |
| 324 | + "population_url": { | |
| 325 | + "name": "population_url", | |
| 326 | + "type": "text", | |
| 327 | + "primaryKey": false, | |
| 328 | + "notNull": false | |
| 329 | + }, | |
| 330 | + "verify_url": { | |
| 331 | + "name": "verify_url", | |
| 332 | + "type": "text", | |
| 333 | + "primaryKey": false, | |
| 334 | + "notNull": false | |
| 335 | + }, | |
| 336 | + "active": { | |
| 337 | + "name": "active", | |
| 338 | + "type": "boolean", | |
| 339 | + "primaryKey": false, | |
| 340 | + "notNull": true, | |
| 341 | + "default": true | |
| 342 | + } | |
| 343 | + }, | |
| 344 | + "indexes": {}, | |
| 345 | + "foreignKeys": {}, | |
| 346 | + "compositePrimaryKeys": {}, | |
| 347 | + "uniqueConstraints": {}, | |
| 348 | + "policies": {}, | |
| 349 | + "checkConstraints": {}, | |
| 350 | + "isRLSEnabled": false | |
| 351 | + }, | |
| 352 | + "public.sets": { | |
| 353 | + "name": "sets", | |
| 354 | + "schema": "", | |
| 355 | + "columns": { | |
| 356 | + "slug": { | |
| 357 | + "name": "slug", | |
| 358 | + "type": "text", | |
| 359 | + "primaryKey": true, | |
| 360 | + "notNull": true | |
| 361 | + }, | |
| 362 | + "name": { | |
| 363 | + "name": "name", | |
| 364 | + "type": "text", | |
| 365 | + "primaryKey": false, | |
| 366 | + "notNull": true | |
| 367 | + }, | |
| 368 | + "code": { | |
| 369 | + "name": "code", | |
| 370 | + "type": "text", | |
| 371 | + "primaryKey": false, | |
| 372 | + "notNull": false | |
| 373 | + }, | |
| 374 | + "category_slug": { | |
| 375 | + "name": "category_slug", | |
| 376 | + "type": "text", | |
| 377 | + "primaryKey": false, | |
| 378 | + "notNull": true | |
| 379 | + }, | |
| 380 | + "franchise_slug": { | |
| 381 | + "name": "franchise_slug", | |
| 382 | + "type": "text", | |
| 383 | + "primaryKey": false, | |
| 384 | + "notNull": false | |
| 385 | + }, | |
| 386 | + "brand_slug": { | |
| 387 | + "name": "brand_slug", | |
| 388 | + "type": "text", | |
| 389 | + "primaryKey": false, | |
| 390 | + "notNull": false | |
| 391 | + }, | |
| 392 | + "release_year": { | |
| 393 | + "name": "release_year", | |
| 394 | + "type": "integer", | |
| 395 | + "primaryKey": false, | |
| 396 | + "notNull": false | |
| 397 | + }, | |
| 398 | + "release_date": { | |
| 399 | + "name": "release_date", | |
| 400 | + "type": "text", | |
| 401 | + "primaryKey": false, | |
| 402 | + "notNull": false | |
| 403 | + }, | |
| 404 | + "language": { | |
| 405 | + "name": "language", | |
| 406 | + "type": "text", | |
| 407 | + "primaryKey": false, | |
| 408 | + "notNull": false | |
| 409 | + }, | |
| 410 | + "total_items": { | |
| 411 | + "name": "total_items", | |
| 412 | + "type": "integer", | |
| 413 | + "primaryKey": false, | |
| 414 | + "notNull": false | |
| 415 | + }, | |
| 416 | + "identifiers": { | |
| 417 | + "name": "identifiers", | |
| 418 | + "type": "jsonb", | |
| 419 | + "primaryKey": false, | |
| 420 | + "notNull": true, | |
| 421 | + "default": "'{}'::jsonb" | |
| 422 | + }, | |
| 423 | + "metadata": { | |
| 424 | + "name": "metadata", | |
| 425 | + "type": "jsonb", | |
| 426 | + "primaryKey": false, | |
| 427 | + "notNull": true, | |
| 428 | + "default": "'{}'::jsonb" | |
| 429 | + }, | |
| 430 | + "created_at": { | |
| 431 | + "name": "created_at", | |
| 432 | + "type": "timestamp with time zone", | |
| 433 | + "primaryKey": false, | |
| 434 | + "notNull": true, | |
| 435 | + "default": "now()" | |
| 436 | + } | |
| 437 | + }, | |
| 438 | + "indexes": { | |
| 439 | + "sets_category_idx": { | |
| 440 | + "name": "sets_category_idx", | |
| 441 | + "columns": [ | |
| 442 | + { | |
| 443 | + "expression": "category_slug", | |
| 444 | + "isExpression": false, | |
| 445 | + "asc": true, | |
| 446 | + "nulls": "last" | |
| 447 | + } | |
| 448 | + ], | |
| 449 | + "isUnique": false, | |
| 450 | + "concurrently": false, | |
| 451 | + "method": "btree", | |
| 452 | + "with": {} | |
| 453 | + }, | |
| 454 | + "sets_category_code_uq": { | |
| 455 | + "name": "sets_category_code_uq", | |
| 456 | + "columns": [ | |
| 457 | + { | |
| 458 | + "expression": "category_slug", | |
| 459 | + "isExpression": false, | |
| 460 | + "asc": true, | |
| 461 | + "nulls": "last" | |
| 462 | + }, | |
| 463 | + { | |
| 464 | + "expression": "code", | |
| 465 | + "isExpression": false, | |
| 466 | + "asc": true, | |
| 467 | + "nulls": "last" | |
| 468 | + } | |
| 469 | + ], | |
| 470 | + "isUnique": true, | |
| 471 | + "concurrently": false, | |
| 472 | + "method": "btree", | |
| 473 | + "with": {} | |
| 474 | + } | |
| 475 | + }, | |
| 476 | + "foreignKeys": {}, | |
| 477 | + "compositePrimaryKeys": {}, | |
| 478 | + "uniqueConstraints": {}, | |
| 479 | + "policies": {}, | |
| 480 | + "checkConstraints": {}, | |
| 481 | + "isRLSEnabled": false | |
| 482 | + }, | |
| 483 | + "public.taxonomy_proposals": { | |
| 484 | + "name": "taxonomy_proposals", | |
| 485 | + "schema": "", | |
| 486 | + "columns": { | |
| 487 | + "id": { | |
| 488 | + "name": "id", | |
| 489 | + "type": "text", | |
| 490 | + "primaryKey": true, | |
| 491 | + "notNull": true | |
| 492 | + }, | |
| 493 | + "proposed_slug": { | |
| 494 | + "name": "proposed_slug", | |
| 495 | + "type": "text", | |
| 496 | + "primaryKey": false, | |
| 497 | + "notNull": true | |
| 498 | + }, | |
| 499 | + "name": { | |
| 500 | + "name": "name", | |
| 501 | + "type": "text", | |
| 502 | + "primaryKey": false, | |
| 503 | + "notNull": true | |
| 504 | + }, | |
| 505 | + "parent_slug": { | |
| 506 | + "name": "parent_slug", | |
| 507 | + "type": "text", | |
| 508 | + "primaryKey": false, | |
| 509 | + "notNull": false | |
| 510 | + }, | |
| 511 | + "evidence": { | |
| 512 | + "name": "evidence", | |
| 513 | + "type": "jsonb", | |
| 514 | + "primaryKey": false, | |
| 515 | + "notNull": true, | |
| 516 | + "default": "'{}'::jsonb" | |
| 517 | + }, | |
| 518 | + "volume_estimate": { | |
| 519 | + "name": "volume_estimate", | |
| 520 | + "type": "integer", | |
| 521 | + "primaryKey": false, | |
| 522 | + "notNull": false | |
| 523 | + }, | |
| 524 | + "status": { | |
| 525 | + "name": "status", | |
| 526 | + "type": "text", | |
| 527 | + "primaryKey": false, | |
| 528 | + "notNull": true, | |
| 529 | + "default": "'pending'" | |
| 530 | + }, | |
| 531 | + "decided_by": { | |
| 532 | + "name": "decided_by", | |
| 533 | + "type": "text", | |
| 534 | + "primaryKey": false, | |
| 535 | + "notNull": false | |
| 536 | + }, | |
| 537 | + "decided_at": { | |
| 538 | + "name": "decided_at", | |
| 539 | + "type": "text", | |
| 540 | + "primaryKey": false, | |
| 541 | + "notNull": false | |
| 542 | + }, | |
| 543 | + "created_at": { | |
| 544 | + "name": "created_at", | |
| 545 | + "type": "timestamp with time zone", | |
| 546 | + "primaryKey": false, | |
| 547 | + "notNull": true, | |
| 548 | + "default": "now()" | |
| 549 | + } | |
| 550 | + }, | |
| 551 | + "indexes": {}, | |
| 552 | + "foreignKeys": {}, | |
| 553 | + "compositePrimaryKeys": {}, | |
| 554 | + "uniqueConstraints": {}, | |
| 555 | + "policies": {}, | |
| 556 | + "checkConstraints": {}, | |
| 557 | + "isRLSEnabled": false | |
| 558 | + }, | |
| 559 | + "public.connector_health": { | |
| 560 | + "name": "connector_health", | |
| 561 | + "schema": "", | |
| 562 | + "columns": { | |
| 563 | + "connector_id": { | |
| 564 | + "name": "connector_id", | |
| 565 | + "type": "text", | |
| 566 | + "primaryKey": true, | |
| 567 | + "notNull": true | |
| 568 | + }, | |
| 569 | + "computed_at": { | |
| 570 | + "name": "computed_at", | |
| 571 | + "type": "timestamp with time zone", | |
| 572 | + "primaryKey": false, | |
| 573 | + "notNull": true | |
| 574 | + }, | |
| 575 | + "status": { | |
| 576 | + "name": "status", | |
| 577 | + "type": "text", | |
| 578 | + "primaryKey": false, | |
| 579 | + "notNull": true | |
| 580 | + }, | |
| 581 | + "health": { | |
| 582 | + "name": "health", | |
| 583 | + "type": "jsonb", | |
| 584 | + "primaryKey": false, | |
| 585 | + "notNull": true, | |
| 586 | + "default": "'{}'::jsonb" | |
| 587 | + } | |
| 588 | + }, | |
| 589 | + "indexes": {}, | |
| 590 | + "foreignKeys": {}, | |
| 591 | + "compositePrimaryKeys": {}, | |
| 592 | + "uniqueConstraints": {}, | |
| 593 | + "policies": {}, | |
| 594 | + "checkConstraints": {}, | |
| 595 | + "isRLSEnabled": false | |
| 596 | + }, | |
| 597 | + "public.connector_runs": { | |
| 598 | + "name": "connector_runs", | |
| 599 | + "schema": "", | |
| 600 | + "columns": { | |
| 601 | + "id": { | |
| 602 | + "name": "id", | |
| 603 | + "type": "text", | |
| 604 | + "primaryKey": true, | |
| 605 | + "notNull": true | |
| 606 | + }, | |
| 607 | + "connector_id": { | |
| 608 | + "name": "connector_id", | |
| 609 | + "type": "text", | |
| 610 | + "primaryKey": false, | |
| 611 | + "notNull": true | |
| 612 | + }, | |
| 613 | + "trigger": { | |
| 614 | + "name": "trigger", | |
| 615 | + "type": "text", | |
| 616 | + "primaryKey": false, | |
| 617 | + "notNull": true, | |
| 618 | + "default": "'schedule'" | |
| 619 | + }, | |
| 620 | + "started_at": { | |
| 621 | + "name": "started_at", | |
| 622 | + "type": "timestamp with time zone", | |
| 623 | + "primaryKey": false, | |
| 624 | + "notNull": true | |
| 625 | + }, | |
| 626 | + "finished_at": { | |
| 627 | + "name": "finished_at", | |
| 628 | + "type": "timestamp with time zone", | |
| 629 | + "primaryKey": false, | |
| 630 | + "notNull": false | |
| 631 | + }, | |
| 632 | + "status": { | |
| 633 | + "name": "status", | |
| 634 | + "type": "text", | |
| 635 | + "primaryKey": false, | |
| 636 | + "notNull": true, | |
| 637 | + "default": "'running'" | |
| 638 | + }, | |
| 639 | + "pages_attempted": { | |
| 640 | + "name": "pages_attempted", | |
| 641 | + "type": "integer", | |
| 642 | + "primaryKey": false, | |
| 643 | + "notNull": true, | |
| 644 | + "default": 0 | |
| 645 | + }, | |
| 646 | + "pages_success": { | |
| 647 | + "name": "pages_success", | |
| 648 | + "type": "integer", | |
| 649 | + "primaryKey": false, | |
| 650 | + "notNull": true, | |
| 651 | + "default": 0 | |
| 652 | + }, | |
| 653 | + "records_raw": { | |
| 654 | + "name": "records_raw", | |
| 655 | + "type": "integer", | |
| 656 | + "primaryKey": false, | |
| 657 | + "notNull": true, | |
| 658 | + "default": 0 | |
| 659 | + }, | |
| 660 | + "records_normalized": { | |
| 661 | + "name": "records_normalized", | |
| 662 | + "type": "integer", | |
| 663 | + "primaryKey": false, | |
| 664 | + "notNull": true, | |
| 665 | + "default": 0 | |
| 666 | + }, | |
| 667 | + "records_duplicate": { | |
| 668 | + "name": "records_duplicate", | |
| 669 | + "type": "integer", | |
| 670 | + "primaryKey": false, | |
| 671 | + "notNull": true, | |
| 672 | + "default": 0 | |
| 673 | + }, | |
| 674 | + "records_rejected": { | |
| 675 | + "name": "records_rejected", | |
| 676 | + "type": "integer", | |
| 677 | + "primaryKey": false, | |
| 678 | + "notNull": true, | |
| 679 | + "default": 0 | |
| 680 | + }, | |
| 681 | + "engine_stats": { | |
| 682 | + "name": "engine_stats", | |
| 683 | + "type": "jsonb", | |
| 684 | + "primaryKey": false, | |
| 685 | + "notNull": true, | |
| 686 | + "default": "'{}'::jsonb" | |
| 687 | + }, | |
| 688 | + "anomalies": { | |
| 689 | + "name": "anomalies", | |
| 690 | + "type": "jsonb", | |
| 691 | + "primaryKey": false, | |
| 692 | + "notNull": true, | |
| 693 | + "default": "'[]'::jsonb" | |
| 694 | + }, | |
| 695 | + "error": { | |
| 696 | + "name": "error", | |
| 697 | + "type": "text", | |
| 698 | + "primaryKey": false, | |
| 699 | + "notNull": false | |
| 700 | + }, | |
| 701 | + "cost_credits": { | |
| 702 | + "name": "cost_credits", | |
| 703 | + "type": "real", | |
| 704 | + "primaryKey": false, | |
| 705 | + "notNull": true, | |
| 706 | + "default": 0 | |
| 707 | + }, | |
| 708 | + "cost_usd_est": { | |
| 709 | + "name": "cost_usd_est", | |
| 710 | + "type": "real", | |
| 711 | + "primaryKey": false, | |
| 712 | + "notNull": true, | |
| 713 | + "default": 0 | |
| 714 | + }, | |
| 715 | + "cursor": { | |
| 716 | + "name": "cursor", | |
| 717 | + "type": "jsonb", | |
| 718 | + "primaryKey": false, | |
| 719 | + "notNull": true, | |
| 720 | + "default": "'{}'::jsonb" | |
| 721 | + } | |
| 722 | + }, | |
| 723 | + "indexes": { | |
| 724 | + "connector_runs_connector_started_idx": { | |
| 725 | + "name": "connector_runs_connector_started_idx", | |
| 726 | + "columns": [ | |
| 727 | + { | |
| 728 | + "expression": "connector_id", | |
| 729 | + "isExpression": false, | |
| 730 | + "asc": true, | |
| 731 | + "nulls": "last" | |
| 732 | + }, | |
| 733 | + { | |
| 734 | + "expression": "started_at", | |
| 735 | + "isExpression": false, | |
| 736 | + "asc": true, | |
| 737 | + "nulls": "last" | |
| 738 | + } | |
| 739 | + ], | |
| 740 | + "isUnique": false, | |
| 741 | + "concurrently": false, | |
| 742 | + "method": "btree", | |
| 743 | + "with": {} | |
| 744 | + } | |
| 745 | + }, | |
| 746 | + "foreignKeys": {}, | |
| 747 | + "compositePrimaryKeys": {}, | |
| 748 | + "uniqueConstraints": {}, | |
| 749 | + "policies": {}, | |
| 750 | + "checkConstraints": {}, | |
| 751 | + "isRLSEnabled": false | |
| 752 | + }, | |
| 753 | + "public.connectors": { | |
| 754 | + "name": "connectors", | |
| 755 | + "schema": "", | |
| 756 | + "columns": { | |
| 757 | + "id": { | |
| 758 | + "name": "id", | |
| 759 | + "type": "text", | |
| 760 | + "primaryKey": true, | |
| 761 | + "notNull": true | |
| 762 | + }, | |
| 763 | + "source_id": { | |
| 764 | + "name": "source_id", | |
| 765 | + "type": "text", | |
| 766 | + "primaryKey": false, | |
| 767 | + "notNull": true | |
| 768 | + }, | |
| 769 | + "display_name": { | |
| 770 | + "name": "display_name", | |
| 771 | + "type": "text", | |
| 772 | + "primaryKey": false, | |
| 773 | + "notNull": true | |
| 774 | + }, | |
| 775 | + "engine_priority": { | |
| 776 | + "name": "engine_priority", | |
| 777 | + "type": "text[]", | |
| 778 | + "primaryKey": false, | |
| 779 | + "notNull": true, | |
| 780 | + "default": "'{}'::text[]" | |
| 781 | + }, | |
| 782 | + "categories": { | |
| 783 | + "name": "categories", | |
| 784 | + "type": "text[]", | |
| 785 | + "primaryKey": false, | |
| 786 | + "notNull": true, | |
| 787 | + "default": "'{}'::text[]" | |
| 788 | + }, | |
| 789 | + "regions": { | |
| 790 | + "name": "regions", | |
| 791 | + "type": "text[]", | |
| 792 | + "primaryKey": false, | |
| 793 | + "notNull": true, | |
| 794 | + "default": "'{}'::text[]" | |
| 795 | + }, | |
| 796 | + "languages": { | |
| 797 | + "name": "languages", | |
| 798 | + "type": "text[]", | |
| 799 | + "primaryKey": false, | |
| 800 | + "notNull": true, | |
| 801 | + "default": "'{}'::text[]" | |
| 802 | + }, | |
| 803 | + "currency": { | |
| 804 | + "name": "currency", | |
| 805 | + "type": "text[]", | |
| 806 | + "primaryKey": false, | |
| 807 | + "notNull": true, | |
| 808 | + "default": "'{}'::text[]" | |
| 809 | + }, | |
| 810 | + "supports_listings": { | |
| 811 | + "name": "supports_listings", | |
| 812 | + "type": "boolean", | |
| 813 | + "primaryKey": false, | |
| 814 | + "notNull": true, | |
| 815 | + "default": false | |
| 816 | + }, | |
| 817 | + "supports_sold": { | |
| 818 | + "name": "supports_sold", | |
| 819 | + "type": "boolean", | |
| 820 | + "primaryKey": false, | |
| 821 | + "notNull": true, | |
| 822 | + "default": false | |
| 823 | + }, | |
| 824 | + "supports_auctions": { | |
| 825 | + "name": "supports_auctions", | |
| 826 | + "type": "boolean", | |
| 827 | + "primaryKey": false, | |
| 828 | + "notNull": true, | |
| 829 | + "default": false | |
| 830 | + }, | |
| 831 | + "supports_images": { | |
| 832 | + "name": "supports_images", | |
| 833 | + "type": "boolean", | |
| 834 | + "primaryKey": false, | |
| 835 | + "notNull": true, | |
| 836 | + "default": true | |
| 837 | + }, | |
| 838 | + "supports_catalog": { | |
| 839 | + "name": "supports_catalog", | |
| 840 | + "type": "boolean", | |
| 841 | + "primaryKey": false, | |
| 842 | + "notNull": true, | |
| 843 | + "default": false | |
| 844 | + }, | |
| 845 | + "supports_population": { | |
| 846 | + "name": "supports_population", | |
| 847 | + "type": "boolean", | |
| 848 | + "primaryKey": false, | |
| 849 | + "notNull": true, | |
| 850 | + "default": false | |
| 851 | + }, | |
| 852 | + "refresh_frequency_minutes": { | |
| 853 | + "name": "refresh_frequency_minutes", | |
| 854 | + "type": "integer", | |
| 855 | + "primaryKey": false, | |
| 856 | + "notNull": true, | |
| 857 | + "default": 1440 | |
| 858 | + }, | |
| 859 | + "priority": { | |
| 860 | + "name": "priority", | |
| 861 | + "type": "text", | |
| 862 | + "primaryKey": false, | |
| 863 | + "notNull": true, | |
| 864 | + "default": "'medium'" | |
| 865 | + }, | |
| 866 | + "status": { | |
| 867 | + "name": "status", | |
| 868 | + "type": "text", | |
| 869 | + "primaryKey": false, | |
| 870 | + "notNull": true, | |
| 871 | + "default": "'active'" | |
| 872 | + }, | |
| 873 | + "schema_version": { | |
| 874 | + "name": "schema_version", | |
| 875 | + "type": "text", | |
| 876 | + "primaryKey": false, | |
| 877 | + "notNull": true, | |
| 878 | + "default": "'1.0'" | |
| 879 | + }, | |
| 880 | + "connector_version": { | |
| 881 | + "name": "connector_version", | |
| 882 | + "type": "text", | |
| 883 | + "primaryKey": false, | |
| 884 | + "notNull": true, | |
| 885 | + "default": "'1.0.0'" | |
| 886 | + }, | |
| 887 | + "config": { | |
| 888 | + "name": "config", | |
| 889 | + "type": "jsonb", | |
| 890 | + "primaryKey": false, | |
| 891 | + "notNull": true, | |
| 892 | + "default": "'{}'::jsonb" | |
| 893 | + }, | |
| 894 | + "last_run_at": { | |
| 895 | + "name": "last_run_at", | |
| 896 | + "type": "timestamp with time zone", | |
| 897 | + "primaryKey": false, | |
| 898 | + "notNull": false | |
| 899 | + }, | |
| 900 | + "last_success_at": { | |
| 901 | + "name": "last_success_at", | |
| 902 | + "type": "timestamp with time zone", | |
| 903 | + "primaryKey": false, | |
| 904 | + "notNull": false | |
| 905 | + }, | |
| 906 | + "next_run_at": { | |
| 907 | + "name": "next_run_at", | |
| 908 | + "type": "timestamp with time zone", | |
| 909 | + "primaryKey": false, | |
| 910 | + "notNull": false | |
| 911 | + }, | |
| 912 | + "created_at": { | |
| 913 | + "name": "created_at", | |
| 914 | + "type": "timestamp with time zone", | |
| 915 | + "primaryKey": false, | |
| 916 | + "notNull": true, | |
| 917 | + "default": "now()" | |
| 918 | + }, | |
| 919 | + "updated_at": { | |
| 920 | + "name": "updated_at", | |
| 921 | + "type": "timestamp with time zone", | |
| 922 | + "primaryKey": false, | |
| 923 | + "notNull": true, | |
| 924 | + "default": "now()" | |
| 925 | + } | |
| 926 | + }, | |
| 927 | + "indexes": {}, | |
| 928 | + "foreignKeys": {}, | |
| 929 | + "compositePrimaryKeys": {}, | |
| 930 | + "uniqueConstraints": {}, | |
| 931 | + "policies": {}, | |
| 932 | + "checkConstraints": {}, | |
| 933 | + "isRLSEnabled": false | |
| 934 | + }, | |
| 935 | + "public.costs": { | |
| 936 | + "name": "costs", | |
| 937 | + "schema": "", | |
| 938 | + "columns": { | |
| 939 | + "id": { | |
| 940 | + "name": "id", | |
| 941 | + "type": "text", | |
| 942 | + "primaryKey": true, | |
| 943 | + "notNull": true | |
| 944 | + }, | |
| 945 | + "occurred_at": { | |
| 946 | + "name": "occurred_at", | |
| 947 | + "type": "timestamp with time zone", | |
| 948 | + "primaryKey": false, | |
| 949 | + "notNull": true | |
| 950 | + }, | |
| 951 | + "kind": { | |
| 952 | + "name": "kind", | |
| 953 | + "type": "text", | |
| 954 | + "primaryKey": false, | |
| 955 | + "notNull": true | |
| 956 | + }, | |
| 957 | + "provider": { | |
| 958 | + "name": "provider", | |
| 959 | + "type": "text", | |
| 960 | + "primaryKey": false, | |
| 961 | + "notNull": false | |
| 962 | + }, | |
| 963 | + "connector_id": { | |
| 964 | + "name": "connector_id", | |
| 965 | + "type": "text", | |
| 966 | + "primaryKey": false, | |
| 967 | + "notNull": false | |
| 968 | + }, | |
| 969 | + "category_slug": { | |
| 970 | + "name": "category_slug", | |
| 971 | + "type": "text", | |
| 972 | + "primaryKey": false, | |
| 973 | + "notNull": false | |
| 974 | + }, | |
| 975 | + "endpoint": { | |
| 976 | + "name": "endpoint", | |
| 977 | + "type": "text", | |
| 978 | + "primaryKey": false, | |
| 979 | + "notNull": false | |
| 980 | + }, | |
| 981 | + "user_id": { | |
| 982 | + "name": "user_id", | |
| 983 | + "type": "text", | |
| 984 | + "primaryKey": false, | |
| 985 | + "notNull": false | |
| 986 | + }, | |
| 987 | + "units": { | |
| 988 | + "name": "units", | |
| 989 | + "type": "real", | |
| 990 | + "primaryKey": false, | |
| 991 | + "notNull": true, | |
| 992 | + "default": 1 | |
| 993 | + }, | |
| 994 | + "credits": { | |
| 995 | + "name": "credits", | |
| 996 | + "type": "real", | |
| 997 | + "primaryKey": false, | |
| 998 | + "notNull": true, | |
| 999 | + "default": 0 | |
| 1000 | + }, | |
| 1001 | + "usd_est": { | |
| 1002 | + "name": "usd_est", | |
| 1003 | + "type": "real", | |
| 1004 | + "primaryKey": false, | |
| 1005 | + "notNull": true, | |
| 1006 | + "default": 0 | |
| 1007 | + }, | |
| 1008 | + "metadata": { | |
| 1009 | + "name": "metadata", | |
| 1010 | + "type": "jsonb", | |
| 1011 | + "primaryKey": false, | |
| 1012 | + "notNull": true, | |
| 1013 | + "default": "'{}'::jsonb" | |
| 1014 | + } | |
| 1015 | + }, | |
| 1016 | + "indexes": { | |
| 1017 | + "costs_occurred_idx": { | |
| 1018 | + "name": "costs_occurred_idx", | |
| 1019 | + "columns": [ | |
| 1020 | + { | |
| 1021 | + "expression": "occurred_at", | |
| 1022 | + "isExpression": false, | |
| 1023 | + "asc": true, | |
| 1024 | + "nulls": "last" | |
| 1025 | + } | |
| 1026 | + ], | |
| 1027 | + "isUnique": false, | |
| 1028 | + "concurrently": false, | |
| 1029 | + "method": "btree", | |
| 1030 | + "with": {} | |
| 1031 | + }, | |
| 1032 | + "costs_connector_idx": { | |
| 1033 | + "name": "costs_connector_idx", | |
| 1034 | + "columns": [ | |
| 1035 | + { | |
| 1036 | + "expression": "connector_id", | |
| 1037 | + "isExpression": false, | |
| 1038 | + "asc": true, | |
| 1039 | + "nulls": "last" | |
| 1040 | + } | |
| 1041 | + ], | |
| 1042 | + "isUnique": false, | |
| 1043 | + "concurrently": false, | |
| 1044 | + "method": "btree", | |
| 1045 | + "with": {} | |
| 1046 | + } | |
| 1047 | + }, | |
| 1048 | + "foreignKeys": {}, | |
| 1049 | + "compositePrimaryKeys": {}, | |
| 1050 | + "uniqueConstraints": {}, | |
| 1051 | + "policies": {}, | |
| 1052 | + "checkConstraints": {}, | |
| 1053 | + "isRLSEnabled": false | |
| 1054 | + }, | |
| 1055 | + "public.crawl_state": { | |
| 1056 | + "name": "crawl_state", | |
| 1057 | + "schema": "", | |
| 1058 | + "columns": { | |
| 1059 | + "url_hash": { | |
| 1060 | + "name": "url_hash", | |
| 1061 | + "type": "text", | |
| 1062 | + "primaryKey": true, | |
| 1063 | + "notNull": true | |
| 1064 | + }, | |
| 1065 | + "connector_id": { | |
| 1066 | + "name": "connector_id", | |
| 1067 | + "type": "text", | |
| 1068 | + "primaryKey": false, | |
| 1069 | + "notNull": true | |
| 1070 | + }, | |
| 1071 | + "url": { | |
| 1072 | + "name": "url", | |
| 1073 | + "type": "text", | |
| 1074 | + "primaryKey": false, | |
| 1075 | + "notNull": true | |
| 1076 | + }, | |
| 1077 | + "etag": { | |
| 1078 | + "name": "etag", | |
| 1079 | + "type": "text", | |
| 1080 | + "primaryKey": false, | |
| 1081 | + "notNull": false | |
| 1082 | + }, | |
| 1083 | + "last_modified": { | |
| 1084 | + "name": "last_modified", | |
| 1085 | + "type": "text", | |
| 1086 | + "primaryKey": false, | |
| 1087 | + "notNull": false | |
| 1088 | + }, | |
| 1089 | + "content_hash": { | |
| 1090 | + "name": "content_hash", | |
| 1091 | + "type": "text", | |
| 1092 | + "primaryKey": false, | |
| 1093 | + "notNull": false | |
| 1094 | + }, | |
| 1095 | + "last_fetched_at": { | |
| 1096 | + "name": "last_fetched_at", | |
| 1097 | + "type": "timestamp with time zone", | |
| 1098 | + "primaryKey": false, | |
| 1099 | + "notNull": false | |
| 1100 | + }, | |
| 1101 | + "last_changed_at": { | |
| 1102 | + "name": "last_changed_at", | |
| 1103 | + "type": "timestamp with time zone", | |
| 1104 | + "primaryKey": false, | |
| 1105 | + "notNull": false | |
| 1106 | + }, | |
| 1107 | + "fetch_count": { | |
| 1108 | + "name": "fetch_count", | |
| 1109 | + "type": "integer", | |
| 1110 | + "primaryKey": false, | |
| 1111 | + "notNull": true, | |
| 1112 | + "default": 0 | |
| 1113 | + }, | |
| 1114 | + "change_count": { | |
| 1115 | + "name": "change_count", | |
| 1116 | + "type": "integer", | |
| 1117 | + "primaryKey": false, | |
| 1118 | + "notNull": true, | |
| 1119 | + "default": 0 | |
| 1120 | + }, | |
| 1121 | + "change_interval_hours": { | |
| 1122 | + "name": "change_interval_hours", | |
| 1123 | + "type": "real", | |
| 1124 | + "primaryKey": false, | |
| 1125 | + "notNull": false | |
| 1126 | + }, | |
| 1127 | + "next_fetch_at": { | |
| 1128 | + "name": "next_fetch_at", | |
| 1129 | + "type": "timestamp with time zone", | |
| 1130 | + "primaryKey": false, | |
| 1131 | + "notNull": false | |
| 1132 | + }, | |
| 1133 | + "last_status": { | |
| 1134 | + "name": "last_status", | |
| 1135 | + "type": "integer", | |
| 1136 | + "primaryKey": false, | |
| 1137 | + "notNull": false | |
| 1138 | + }, | |
| 1139 | + "failures": { | |
| 1140 | + "name": "failures", | |
| 1141 | + "type": "integer", | |
| 1142 | + "primaryKey": false, | |
| 1143 | + "notNull": true, | |
| 1144 | + "default": 0 | |
| 1145 | + } | |
| 1146 | + }, | |
| 1147 | + "indexes": { | |
| 1148 | + "crawl_state_next_idx": { | |
| 1149 | + "name": "crawl_state_next_idx", | |
| 1150 | + "columns": [ | |
| 1151 | + { | |
| 1152 | + "expression": "connector_id", | |
| 1153 | + "isExpression": false, | |
| 1154 | + "asc": true, | |
| 1155 | + "nulls": "last" | |
| 1156 | + }, | |
| 1157 | + { | |
| 1158 | + "expression": "next_fetch_at", | |
| 1159 | + "isExpression": false, | |
| 1160 | + "asc": true, | |
| 1161 | + "nulls": "last" | |
| 1162 | + } | |
| 1163 | + ], | |
| 1164 | + "isUnique": false, | |
| 1165 | + "concurrently": false, | |
| 1166 | + "method": "btree", | |
| 1167 | + "with": {} | |
| 1168 | + } | |
| 1169 | + }, | |
| 1170 | + "foreignKeys": {}, | |
| 1171 | + "compositePrimaryKeys": {}, | |
| 1172 | + "uniqueConstraints": {}, | |
| 1173 | + "policies": {}, | |
| 1174 | + "checkConstraints": {}, | |
| 1175 | + "isRLSEnabled": false | |
| 1176 | + }, | |
| 1177 | + "public.sources": { | |
| 1178 | + "name": "sources", | |
| 1179 | + "schema": "", | |
| 1180 | + "columns": { | |
| 1181 | + "id": { | |
| 1182 | + "name": "id", | |
| 1183 | + "type": "text", | |
| 1184 | + "primaryKey": true, | |
| 1185 | + "notNull": true | |
| 1186 | + }, | |
| 1187 | + "name": { | |
| 1188 | + "name": "name", | |
| 1189 | + "type": "text", | |
| 1190 | + "primaryKey": false, | |
| 1191 | + "notNull": true | |
| 1192 | + }, | |
| 1193 | + "source_type": { | |
| 1194 | + "name": "source_type", | |
| 1195 | + "type": "text", | |
| 1196 | + "primaryKey": false, | |
| 1197 | + "notNull": true | |
| 1198 | + }, | |
| 1199 | + "url": { | |
| 1200 | + "name": "url", | |
| 1201 | + "type": "text", | |
| 1202 | + "primaryKey": false, | |
| 1203 | + "notNull": false | |
| 1204 | + }, | |
| 1205 | + "countries": { | |
| 1206 | + "name": "countries", | |
| 1207 | + "type": "text[]", | |
| 1208 | + "primaryKey": false, | |
| 1209 | + "notNull": true, | |
| 1210 | + "default": "'{}'::text[]" | |
| 1211 | + }, | |
| 1212 | + "languages": { | |
| 1213 | + "name": "languages", | |
| 1214 | + "type": "text[]", | |
| 1215 | + "primaryKey": false, | |
| 1216 | + "notNull": true, | |
| 1217 | + "default": "'{}'::text[]" | |
| 1218 | + }, | |
| 1219 | + "currencies": { | |
| 1220 | + "name": "currencies", | |
| 1221 | + "type": "text[]", | |
| 1222 | + "primaryKey": false, | |
| 1223 | + "notNull": true, | |
| 1224 | + "default": "'{}'::text[]" | |
| 1225 | + }, | |
| 1226 | + "trust_score": { | |
| 1227 | + "name": "trust_score", | |
| 1228 | + "type": "numeric(8, 6)", | |
| 1229 | + "primaryKey": false, | |
| 1230 | + "notNull": true, | |
| 1231 | + "default": 0.5 | |
| 1232 | + }, | |
| 1233 | + "trust_factors": { | |
| 1234 | + "name": "trust_factors", | |
| 1235 | + "type": "jsonb", | |
| 1236 | + "primaryKey": false, | |
| 1237 | + "notNull": true, | |
| 1238 | + "default": "'{}'::jsonb" | |
| 1239 | + }, | |
| 1240 | + "attribution_required": { | |
| 1241 | + "name": "attribution_required", | |
| 1242 | + "type": "boolean", | |
| 1243 | + "primaryKey": false, | |
| 1244 | + "notNull": true, | |
| 1245 | + "default": true | |
| 1246 | + }, | |
| 1247 | + "terms_url": { | |
| 1248 | + "name": "terms_url", | |
| 1249 | + "type": "text", | |
| 1250 | + "primaryKey": false, | |
| 1251 | + "notNull": false | |
| 1252 | + }, | |
| 1253 | + "active": { | |
| 1254 | + "name": "active", | |
| 1255 | + "type": "boolean", | |
| 1256 | + "primaryKey": false, | |
| 1257 | + "notNull": true, | |
| 1258 | + "default": true | |
| 1259 | + }, | |
| 1260 | + "created_at": { | |
| 1261 | + "name": "created_at", | |
| 1262 | + "type": "timestamp with time zone", | |
| 1263 | + "primaryKey": false, | |
| 1264 | + "notNull": true, | |
| 1265 | + "default": "now()" | |
| 1266 | + }, | |
| 1267 | + "updated_at": { | |
| 1268 | + "name": "updated_at", | |
| 1269 | + "type": "timestamp with time zone", | |
| 1270 | + "primaryKey": false, | |
| 1271 | + "notNull": true, | |
| 1272 | + "default": "now()" | |
| 1273 | + } | |
| 1274 | + }, | |
| 1275 | + "indexes": {}, | |
| 1276 | + "foreignKeys": {}, | |
| 1277 | + "compositePrimaryKeys": {}, | |
| 1278 | + "uniqueConstraints": {}, | |
| 1279 | + "policies": {}, | |
| 1280 | + "checkConstraints": {}, | |
| 1281 | + "isRLSEnabled": false | |
| 1282 | + }, | |
| 1283 | + "public.audit_log": { | |
| 1284 | + "name": "audit_log", | |
| 1285 | + "schema": "", | |
| 1286 | + "columns": { | |
| 1287 | + "id": { | |
| 1288 | + "name": "id", | |
| 1289 | + "type": "text", | |
| 1290 | + "primaryKey": true, | |
| 1291 | + "notNull": true | |
| 1292 | + }, | |
| 1293 | + "entity_type": { | |
| 1294 | + "name": "entity_type", | |
| 1295 | + "type": "text", | |
| 1296 | + "primaryKey": false, | |
| 1297 | + "notNull": true | |
| 1298 | + }, | |
| 1299 | + "entity_id": { | |
| 1300 | + "name": "entity_id", | |
| 1301 | + "type": "text", | |
| 1302 | + "primaryKey": false, | |
| 1303 | + "notNull": true | |
| 1304 | + }, | |
| 1305 | + "action": { | |
| 1306 | + "name": "action", | |
| 1307 | + "type": "text", | |
| 1308 | + "primaryKey": false, | |
| 1309 | + "notNull": true | |
| 1310 | + }, | |
| 1311 | + "reason": { | |
| 1312 | + "name": "reason", | |
| 1313 | + "type": "text", | |
| 1314 | + "primaryKey": false, | |
| 1315 | + "notNull": true | |
| 1316 | + }, | |
| 1317 | + "actor": { | |
| 1318 | + "name": "actor", | |
| 1319 | + "type": "text", | |
| 1320 | + "primaryKey": false, | |
| 1321 | + "notNull": true, | |
| 1322 | + "default": "'system'" | |
| 1323 | + }, | |
| 1324 | + "details": { | |
| 1325 | + "name": "details", | |
| 1326 | + "type": "jsonb", | |
| 1327 | + "primaryKey": false, | |
| 1328 | + "notNull": true, | |
| 1329 | + "default": "'{}'::jsonb" | |
| 1330 | + }, | |
| 1331 | + "created_at": { | |
| 1332 | + "name": "created_at", | |
| 1333 | + "type": "timestamp with time zone", | |
| 1334 | + "primaryKey": false, | |
| 1335 | + "notNull": true, | |
| 1336 | + "default": "now()" | |
| 1337 | + } | |
| 1338 | + }, | |
| 1339 | + "indexes": { | |
| 1340 | + "audit_entity_idx": { | |
| 1341 | + "name": "audit_entity_idx", | |
| 1342 | + "columns": [ | |
| 1343 | + { | |
| 1344 | + "expression": "entity_type", | |
| 1345 | + "isExpression": false, | |
| 1346 | + "asc": true, | |
| 1347 | + "nulls": "last" | |
| 1348 | + }, | |
| 1349 | + { | |
| 1350 | + "expression": "entity_id", | |
| 1351 | + "isExpression": false, | |
| 1352 | + "asc": true, | |
| 1353 | + "nulls": "last" | |
| 1354 | + } | |
| 1355 | + ], | |
| 1356 | + "isUnique": false, | |
| 1357 | + "concurrently": false, | |
| 1358 | + "method": "btree", | |
| 1359 | + "with": {} | |
| 1360 | + } | |
| 1361 | + }, | |
| 1362 | + "foreignKeys": {}, | |
| 1363 | + "compositePrimaryKeys": {}, | |
| 1364 | + "uniqueConstraints": {}, | |
| 1365 | + "policies": {}, | |
| 1366 | + "checkConstraints": {}, | |
| 1367 | + "isRLSEnabled": false | |
| 1368 | + }, | |
| 1369 | + "public.events": { | |
| 1370 | + "name": "events", | |
| 1371 | + "schema": "", | |
| 1372 | + "columns": { | |
| 1373 | + "id": { | |
| 1374 | + "name": "id", | |
| 1375 | + "type": "text", | |
| 1376 | + "primaryKey": true, | |
| 1377 | + "notNull": true | |
| 1378 | + }, | |
| 1379 | + "type": { | |
| 1380 | + "name": "type", | |
| 1381 | + "type": "text", | |
| 1382 | + "primaryKey": false, | |
| 1383 | + "notNull": true | |
| 1384 | + }, | |
| 1385 | + "entity_type": { | |
| 1386 | + "name": "entity_type", | |
| 1387 | + "type": "text", | |
| 1388 | + "primaryKey": false, | |
| 1389 | + "notNull": false | |
| 1390 | + }, | |
| 1391 | + "entity_id": { | |
| 1392 | + "name": "entity_id", | |
| 1393 | + "type": "text", | |
| 1394 | + "primaryKey": false, | |
| 1395 | + "notNull": false | |
| 1396 | + }, | |
| 1397 | + "payload": { | |
| 1398 | + "name": "payload", | |
| 1399 | + "type": "jsonb", | |
| 1400 | + "primaryKey": false, | |
| 1401 | + "notNull": true, | |
| 1402 | + "default": "'{}'::jsonb" | |
| 1403 | + }, | |
| 1404 | + "created_at": { | |
| 1405 | + "name": "created_at", | |
| 1406 | + "type": "timestamp with time zone", | |
| 1407 | + "primaryKey": false, | |
| 1408 | + "notNull": true, | |
| 1409 | + "default": "now()" | |
| 1410 | + } | |
| 1411 | + }, | |
| 1412 | + "indexes": { | |
| 1413 | + "events_type_created_idx": { | |
| 1414 | + "name": "events_type_created_idx", | |
| 1415 | + "columns": [ | |
| 1416 | + { | |
| 1417 | + "expression": "type", | |
| 1418 | + "isExpression": false, | |
| 1419 | + "asc": true, | |
| 1420 | + "nulls": "last" | |
| 1421 | + }, | |
| 1422 | + { | |
| 1423 | + "expression": "created_at", | |
| 1424 | + "isExpression": false, | |
| 1425 | + "asc": true, | |
| 1426 | + "nulls": "last" | |
| 1427 | + } | |
| 1428 | + ], | |
| 1429 | + "isUnique": false, | |
| 1430 | + "concurrently": false, | |
| 1431 | + "method": "btree", | |
| 1432 | + "with": {} | |
| 1433 | + }, | |
| 1434 | + "events_entity_idx": { | |
| 1435 | + "name": "events_entity_idx", | |
| 1436 | + "columns": [ | |
| 1437 | + { | |
| 1438 | + "expression": "entity_type", | |
| 1439 | + "isExpression": false, | |
| 1440 | + "asc": true, | |
| 1441 | + "nulls": "last" | |
| 1442 | + }, | |
| 1443 | + { | |
| 1444 | + "expression": "entity_id", | |
| 1445 | + "isExpression": false, | |
| 1446 | + "asc": true, | |
| 1447 | + "nulls": "last" | |
| 1448 | + } | |
| 1449 | + ], | |
| 1450 | + "isUnique": false, | |
| 1451 | + "concurrently": false, | |
| 1452 | + "method": "btree", | |
| 1453 | + "with": {} | |
| 1454 | + } | |
| 1455 | + }, | |
| 1456 | + "foreignKeys": {}, | |
| 1457 | + "compositePrimaryKeys": {}, | |
| 1458 | + "uniqueConstraints": {}, | |
| 1459 | + "policies": {}, | |
| 1460 | + "checkConstraints": {}, | |
| 1461 | + "isRLSEnabled": false | |
| 1462 | + }, | |
| 1463 | + "public.normalized_records": { | |
| 1464 | + "name": "normalized_records", | |
| 1465 | + "schema": "", | |
| 1466 | + "columns": { | |
| 1467 | + "id": { | |
| 1468 | + "name": "id", | |
| 1469 | + "type": "text", | |
| 1470 | + "primaryKey": true, | |
| 1471 | + "notNull": true | |
| 1472 | + }, | |
| 1473 | + "raw_record_id": { | |
| 1474 | + "name": "raw_record_id", | |
| 1475 | + "type": "text", | |
| 1476 | + "primaryKey": false, | |
| 1477 | + "notNull": true | |
| 1478 | + }, | |
| 1479 | + "connector_id": { | |
| 1480 | + "name": "connector_id", | |
| 1481 | + "type": "text", | |
| 1482 | + "primaryKey": false, | |
| 1483 | + "notNull": true | |
| 1484 | + }, | |
| 1485 | + "source_id": { | |
| 1486 | + "name": "source_id", | |
| 1487 | + "type": "text", | |
| 1488 | + "primaryKey": false, | |
| 1489 | + "notNull": true | |
| 1490 | + }, | |
| 1491 | + "kind": { | |
| 1492 | + "name": "kind", | |
| 1493 | + "type": "text", | |
| 1494 | + "primaryKey": false, | |
| 1495 | + "notNull": true | |
| 1496 | + }, | |
| 1497 | + "payload": { | |
| 1498 | + "name": "payload", | |
| 1499 | + "type": "jsonb", | |
| 1500 | + "primaryKey": false, | |
| 1501 | + "notNull": true | |
| 1502 | + }, | |
| 1503 | + "asset_id": { | |
| 1504 | + "name": "asset_id", | |
| 1505 | + "type": "text", | |
| 1506 | + "primaryKey": false, | |
| 1507 | + "notNull": false | |
| 1508 | + }, | |
| 1509 | + "variant_id": { | |
| 1510 | + "name": "variant_id", | |
| 1511 | + "type": "text", | |
| 1512 | + "primaryKey": false, | |
| 1513 | + "notNull": false | |
| 1514 | + }, | |
| 1515 | + "match_method": { | |
| 1516 | + "name": "match_method", | |
| 1517 | + "type": "text", | |
| 1518 | + "primaryKey": false, | |
| 1519 | + "notNull": false | |
| 1520 | + }, | |
| 1521 | + "match_confidence": { | |
| 1522 | + "name": "match_confidence", | |
| 1523 | + "type": "numeric(8, 6)", | |
| 1524 | + "primaryKey": false, | |
| 1525 | + "notNull": false | |
| 1526 | + }, | |
| 1527 | + "status": { | |
| 1528 | + "name": "status", | |
| 1529 | + "type": "text", | |
| 1530 | + "primaryKey": false, | |
| 1531 | + "notNull": true, | |
| 1532 | + "default": "'pending'" | |
| 1533 | + }, | |
| 1534 | + "reject_reason": { | |
| 1535 | + "name": "reject_reason", | |
| 1536 | + "type": "text", | |
| 1537 | + "primaryKey": false, | |
| 1538 | + "notNull": false | |
| 1539 | + }, | |
| 1540 | + "target_id": { | |
| 1541 | + "name": "target_id", | |
| 1542 | + "type": "text", | |
| 1543 | + "primaryKey": false, | |
| 1544 | + "notNull": false | |
| 1545 | + }, | |
| 1546 | + "created_at": { | |
| 1547 | + "name": "created_at", | |
| 1548 | + "type": "timestamp with time zone", | |
| 1549 | + "primaryKey": false, | |
| 1550 | + "notNull": true, | |
| 1551 | + "default": "now()" | |
| 1552 | + }, | |
| 1553 | + "processed_at": { | |
| 1554 | + "name": "processed_at", | |
| 1555 | + "type": "timestamp with time zone", | |
| 1556 | + "primaryKey": false, | |
| 1557 | + "notNull": false | |
| 1558 | + } | |
| 1559 | + }, | |
| 1560 | + "indexes": { | |
| 1561 | + "normalized_records_status_idx": { | |
| 1562 | + "name": "normalized_records_status_idx", | |
| 1563 | + "columns": [ | |
| 1564 | + { | |
| 1565 | + "expression": "status", | |
| 1566 | + "isExpression": false, | |
| 1567 | + "asc": true, | |
| 1568 | + "nulls": "last" | |
| 1569 | + }, | |
| 1570 | + { | |
| 1571 | + "expression": "created_at", | |
| 1572 | + "isExpression": false, | |
| 1573 | + "asc": true, | |
| 1574 | + "nulls": "last" | |
| 1575 | + } | |
| 1576 | + ], | |
| 1577 | + "isUnique": false, | |
| 1578 | + "concurrently": false, | |
| 1579 | + "method": "btree", | |
| 1580 | + "with": {} | |
| 1581 | + }, | |
| 1582 | + "normalized_records_asset_idx": { | |
| 1583 | + "name": "normalized_records_asset_idx", | |
| 1584 | + "columns": [ | |
| 1585 | + { | |
| 1586 | + "expression": "asset_id", | |
| 1587 | + "isExpression": false, | |
| 1588 | + "asc": true, | |
| 1589 | + "nulls": "last" | |
| 1590 | + } | |
| 1591 | + ], | |
| 1592 | + "isUnique": false, | |
| 1593 | + "concurrently": false, | |
| 1594 | + "method": "btree", | |
| 1595 | + "with": {} | |
| 1596 | + }, | |
| 1597 | + "normalized_records_raw_uq": { | |
| 1598 | + "name": "normalized_records_raw_uq", | |
| 1599 | + "columns": [ | |
| 1600 | + { | |
| 1601 | + "expression": "raw_record_id", | |
| 1602 | + "isExpression": false, | |
| 1603 | + "asc": true, | |
| 1604 | + "nulls": "last" | |
| 1605 | + } | |
| 1606 | + ], | |
| 1607 | + "isUnique": true, | |
| 1608 | + "concurrently": false, | |
| 1609 | + "method": "btree", | |
| 1610 | + "with": {} | |
| 1611 | + } | |
| 1612 | + }, | |
| 1613 | + "foreignKeys": {}, | |
| 1614 | + "compositePrimaryKeys": {}, | |
| 1615 | + "uniqueConstraints": {}, | |
| 1616 | + "policies": {}, | |
| 1617 | + "checkConstraints": {}, | |
| 1618 | + "isRLSEnabled": false | |
| 1619 | + }, | |
| 1620 | + "public.raw_records": { | |
| 1621 | + "name": "raw_records", | |
| 1622 | + "schema": "", | |
| 1623 | + "columns": { | |
| 1624 | + "id": { | |
| 1625 | + "name": "id", | |
| 1626 | + "type": "text", | |
| 1627 | + "primaryKey": true, | |
| 1628 | + "notNull": true | |
| 1629 | + }, | |
| 1630 | + "connector_id": { | |
| 1631 | + "name": "connector_id", | |
| 1632 | + "type": "text", | |
| 1633 | + "primaryKey": false, | |
| 1634 | + "notNull": true | |
| 1635 | + }, | |
| 1636 | + "source_id": { | |
| 1637 | + "name": "source_id", | |
| 1638 | + "type": "text", | |
| 1639 | + "primaryKey": false, | |
| 1640 | + "notNull": true | |
| 1641 | + }, | |
| 1642 | + "run_id": { | |
| 1643 | + "name": "run_id", | |
| 1644 | + "type": "text", | |
| 1645 | + "primaryKey": false, | |
| 1646 | + "notNull": false | |
| 1647 | + }, | |
| 1648 | + "engine": { | |
| 1649 | + "name": "engine", | |
| 1650 | + "type": "text", | |
| 1651 | + "primaryKey": false, | |
| 1652 | + "notNull": true | |
| 1653 | + }, | |
| 1654 | + "url": { | |
| 1655 | + "name": "url", | |
| 1656 | + "type": "text", | |
| 1657 | + "primaryKey": false, | |
| 1658 | + "notNull": true | |
| 1659 | + }, | |
| 1660 | + "external_id": { | |
| 1661 | + "name": "external_id", | |
| 1662 | + "type": "text", | |
| 1663 | + "primaryKey": false, | |
| 1664 | + "notNull": false | |
| 1665 | + }, | |
| 1666 | + "kind": { | |
| 1667 | + "name": "kind", | |
| 1668 | + "type": "text", | |
| 1669 | + "primaryKey": false, | |
| 1670 | + "notNull": true | |
| 1671 | + }, | |
| 1672 | + "fetched_at": { | |
| 1673 | + "name": "fetched_at", | |
| 1674 | + "type": "timestamp with time zone", | |
| 1675 | + "primaryKey": false, | |
| 1676 | + "notNull": true | |
| 1677 | + }, | |
| 1678 | + "content_hash": { | |
| 1679 | + "name": "content_hash", | |
| 1680 | + "type": "text", | |
| 1681 | + "primaryKey": false, | |
| 1682 | + "notNull": true | |
| 1683 | + }, | |
| 1684 | + "http_status": { | |
| 1685 | + "name": "http_status", | |
| 1686 | + "type": "integer", | |
| 1687 | + "primaryKey": false, | |
| 1688 | + "notNull": false | |
| 1689 | + }, | |
| 1690 | + "payload": { | |
| 1691 | + "name": "payload", | |
| 1692 | + "type": "jsonb", | |
| 1693 | + "primaryKey": false, | |
| 1694 | + "notNull": true | |
| 1695 | + }, | |
| 1696 | + "snapshot_ref": { | |
| 1697 | + "name": "snapshot_ref", | |
| 1698 | + "type": "text", | |
| 1699 | + "primaryKey": false, | |
| 1700 | + "notNull": false | |
| 1701 | + }, | |
| 1702 | + "parser_version": { | |
| 1703 | + "name": "parser_version", | |
| 1704 | + "type": "text", | |
| 1705 | + "primaryKey": false, | |
| 1706 | + "notNull": true | |
| 1707 | + }, | |
| 1708 | + "connector_version": { | |
| 1709 | + "name": "connector_version", | |
| 1710 | + "type": "text", | |
| 1711 | + "primaryKey": false, | |
| 1712 | + "notNull": true | |
| 1713 | + }, | |
| 1714 | + "processed_at": { | |
| 1715 | + "name": "processed_at", | |
| 1716 | + "type": "timestamp with time zone", | |
| 1717 | + "primaryKey": false, | |
| 1718 | + "notNull": false | |
| 1719 | + }, | |
| 1720 | + "process_error": { | |
| 1721 | + "name": "process_error", | |
| 1722 | + "type": "text", | |
| 1723 | + "primaryKey": false, | |
| 1724 | + "notNull": false | |
| 1725 | + }, | |
| 1726 | + "created_at": { | |
| 1727 | + "name": "created_at", | |
| 1728 | + "type": "timestamp with time zone", | |
| 1729 | + "primaryKey": false, | |
| 1730 | + "notNull": true, | |
| 1731 | + "default": "now()" | |
| 1732 | + } | |
| 1733 | + }, | |
| 1734 | + "indexes": { | |
| 1735 | + "raw_records_connector_hash_uq": { | |
| 1736 | + "name": "raw_records_connector_hash_uq", | |
| 1737 | + "columns": [ | |
| 1738 | + { | |
| 1739 | + "expression": "connector_id", | |
| 1740 | + "isExpression": false, | |
| 1741 | + "asc": true, | |
| 1742 | + "nulls": "last" | |
| 1743 | + }, | |
| 1744 | + { | |
| 1745 | + "expression": "content_hash", | |
| 1746 | + "isExpression": false, | |
| 1747 | + "asc": true, | |
| 1748 | + "nulls": "last" | |
| 1749 | + } | |
| 1750 | + ], | |
| 1751 | + "isUnique": true, | |
| 1752 | + "concurrently": false, | |
| 1753 | + "method": "btree", | |
| 1754 | + "with": {} | |
| 1755 | + }, | |
| 1756 | + "raw_records_connector_fetched_idx": { | |
| 1757 | + "name": "raw_records_connector_fetched_idx", | |
| 1758 | + "columns": [ | |
| 1759 | + { | |
| 1760 | + "expression": "connector_id", | |
| 1761 | + "isExpression": false, | |
| 1762 | + "asc": true, | |
| 1763 | + "nulls": "last" | |
| 1764 | + }, | |
| 1765 | + { | |
| 1766 | + "expression": "fetched_at", | |
| 1767 | + "isExpression": false, | |
| 1768 | + "asc": true, | |
| 1769 | + "nulls": "last" | |
| 1770 | + } | |
| 1771 | + ], | |
| 1772 | + "isUnique": false, | |
| 1773 | + "concurrently": false, | |
| 1774 | + "method": "btree", | |
| 1775 | + "with": {} | |
| 1776 | + }, | |
| 1777 | + "raw_records_unprocessed_idx": { | |
| 1778 | + "name": "raw_records_unprocessed_idx", | |
| 1779 | + "columns": [ | |
| 1780 | + { | |
| 1781 | + "expression": "processed_at", | |
| 1782 | + "isExpression": false, | |
| 1783 | + "asc": true, | |
| 1784 | + "nulls": "last" | |
| 1785 | + } | |
| 1786 | + ], | |
| 1787 | + "isUnique": false, | |
| 1788 | + "concurrently": false, | |
| 1789 | + "method": "btree", | |
| 1790 | + "with": {} | |
| 1791 | + }, | |
| 1792 | + "raw_records_external_idx": { | |
| 1793 | + "name": "raw_records_external_idx", | |
| 1794 | + "columns": [ | |
| 1795 | + { | |
| 1796 | + "expression": "connector_id", | |
| 1797 | + "isExpression": false, | |
| 1798 | + "asc": true, | |
| 1799 | + "nulls": "last" | |
| 1800 | + }, | |
| 1801 | + { | |
| 1802 | + "expression": "external_id", | |
| 1803 | + "isExpression": false, | |
| 1804 | + "asc": true, | |
| 1805 | + "nulls": "last" | |
| 1806 | + } | |
| 1807 | + ], | |
| 1808 | + "isUnique": false, | |
| 1809 | + "concurrently": false, | |
| 1810 | + "method": "btree", | |
| 1811 | + "with": {} | |
| 1812 | + } | |
| 1813 | + }, | |
| 1814 | + "foreignKeys": {}, | |
| 1815 | + "compositePrimaryKeys": {}, | |
| 1816 | + "uniqueConstraints": {}, | |
| 1817 | + "policies": {}, | |
| 1818 | + "checkConstraints": {}, | |
| 1819 | + "isRLSEnabled": false | |
| 1820 | + }, | |
| 1821 | + "public.asset_embeddings": { | |
| 1822 | + "name": "asset_embeddings", | |
| 1823 | + "schema": "", | |
| 1824 | + "columns": { | |
| 1825 | + "asset_id": { | |
| 1826 | + "name": "asset_id", | |
| 1827 | + "type": "text", | |
| 1828 | + "primaryKey": true, | |
| 1829 | + "notNull": true | |
| 1830 | + }, | |
| 1831 | + "model": { | |
| 1832 | + "name": "model", | |
| 1833 | + "type": "text", | |
| 1834 | + "primaryKey": false, | |
| 1835 | + "notNull": true | |
| 1836 | + }, | |
| 1837 | + "embedding": { | |
| 1838 | + "name": "embedding", | |
| 1839 | + "type": "vector(1536)", | |
| 1840 | + "primaryKey": false, | |
| 1841 | + "notNull": true | |
| 1842 | + }, | |
| 1843 | + "updated_at": { | |
| 1844 | + "name": "updated_at", | |
| 1845 | + "type": "timestamp with time zone", | |
| 1846 | + "primaryKey": false, | |
| 1847 | + "notNull": true, | |
| 1848 | + "default": "now()" | |
| 1849 | + } | |
| 1850 | + }, | |
| 1851 | + "indexes": {}, | |
| 1852 | + "foreignKeys": {}, | |
| 1853 | + "compositePrimaryKeys": {}, | |
| 1854 | + "uniqueConstraints": {}, | |
| 1855 | + "policies": {}, | |
| 1856 | + "checkConstraints": {}, | |
| 1857 | + "isRLSEnabled": false | |
| 1858 | + }, | |
| 1859 | + "public.asset_stats": { | |
| 1860 | + "name": "asset_stats", | |
| 1861 | + "schema": "", | |
| 1862 | + "columns": { | |
| 1863 | + "asset_id": { | |
| 1864 | + "name": "asset_id", | |
| 1865 | + "type": "text", | |
| 1866 | + "primaryKey": true, | |
| 1867 | + "notNull": true | |
| 1868 | + }, | |
| 1869 | + "riv_usd": { | |
| 1870 | + "name": "riv_usd", | |
| 1871 | + "type": "numeric(18, 4)", | |
| 1872 | + "primaryKey": false, | |
| 1873 | + "notNull": false | |
| 1874 | + }, | |
| 1875 | + "riv_low_usd": { | |
| 1876 | + "name": "riv_low_usd", | |
| 1877 | + "type": "numeric(18, 4)", | |
| 1878 | + "primaryKey": false, | |
| 1879 | + "notNull": false | |
| 1880 | + }, | |
| 1881 | + "riv_high_usd": { | |
| 1882 | + "name": "riv_high_usd", | |
| 1883 | + "type": "numeric(18, 4)", | |
| 1884 | + "primaryKey": false, | |
| 1885 | + "notNull": false | |
| 1886 | + }, | |
| 1887 | + "riv_confidence": { | |
| 1888 | + "name": "riv_confidence", | |
| 1889 | + "type": "numeric(8, 6)", | |
| 1890 | + "primaryKey": false, | |
| 1891 | + "notNull": false | |
| 1892 | + }, | |
| 1893 | + "riv_sample_size": { | |
| 1894 | + "name": "riv_sample_size", | |
| 1895 | + "type": "integer", | |
| 1896 | + "primaryKey": false, | |
| 1897 | + "notNull": true, | |
| 1898 | + "default": 0 | |
| 1899 | + }, | |
| 1900 | + "riv_variant_id": { | |
| 1901 | + "name": "riv_variant_id", | |
| 1902 | + "type": "text", | |
| 1903 | + "primaryKey": false, | |
| 1904 | + "notNull": false | |
| 1905 | + }, | |
| 1906 | + "latest_sale_usd": { | |
| 1907 | + "name": "latest_sale_usd", | |
| 1908 | + "type": "numeric(18, 4)", | |
| 1909 | + "primaryKey": false, | |
| 1910 | + "notNull": false | |
| 1911 | + }, | |
| 1912 | + "latest_sale_at": { | |
| 1913 | + "name": "latest_sale_at", | |
| 1914 | + "type": "timestamp with time zone", | |
| 1915 | + "primaryKey": false, | |
| 1916 | + "notNull": false | |
| 1917 | + }, | |
| 1918 | + "change_1d": { | |
| 1919 | + "name": "change_1d", | |
| 1920 | + "type": "numeric(8, 6)", | |
| 1921 | + "primaryKey": false, | |
| 1922 | + "notNull": false | |
| 1923 | + }, | |
| 1924 | + "change_7d": { | |
| 1925 | + "name": "change_7d", | |
| 1926 | + "type": "numeric(8, 6)", | |
| 1927 | + "primaryKey": false, | |
| 1928 | + "notNull": false | |
| 1929 | + }, | |
| 1930 | + "change_30d": { | |
| 1931 | + "name": "change_30d", | |
| 1932 | + "type": "numeric(8, 6)", | |
| 1933 | + "primaryKey": false, | |
| 1934 | + "notNull": false | |
| 1935 | + }, | |
| 1936 | + "change_90d": { | |
| 1937 | + "name": "change_90d", | |
| 1938 | + "type": "numeric(8, 6)", | |
| 1939 | + "primaryKey": false, | |
| 1940 | + "notNull": false | |
| 1941 | + }, | |
| 1942 | + "change_1y": { | |
| 1943 | + "name": "change_1y", | |
| 1944 | + "type": "numeric(8, 6)", | |
| 1945 | + "primaryKey": false, | |
| 1946 | + "notNull": false | |
| 1947 | + }, | |
| 1948 | + "ath_usd": { | |
| 1949 | + "name": "ath_usd", | |
| 1950 | + "type": "numeric(18, 4)", | |
| 1951 | + "primaryKey": false, | |
| 1952 | + "notNull": false | |
| 1953 | + }, | |
| 1954 | + "ath_at": { | |
| 1955 | + "name": "ath_at", | |
| 1956 | + "type": "timestamp with time zone", | |
| 1957 | + "primaryKey": false, | |
| 1958 | + "notNull": false | |
| 1959 | + }, | |
| 1960 | + "atl_usd": { | |
| 1961 | + "name": "atl_usd", | |
| 1962 | + "type": "numeric(18, 4)", | |
| 1963 | + "primaryKey": false, | |
| 1964 | + "notNull": false | |
| 1965 | + }, | |
| 1966 | + "atl_at": { | |
| 1967 | + "name": "atl_at", | |
| 1968 | + "type": "timestamp with time zone", | |
| 1969 | + "primaryKey": false, | |
| 1970 | + "notNull": false | |
| 1971 | + }, | |
| 1972 | + "sales_count": { | |
| 1973 | + "name": "sales_count", | |
| 1974 | + "type": "integer", | |
| 1975 | + "primaryKey": false, | |
| 1976 | + "notNull": true, | |
| 1977 | + "default": 0 | |
| 1978 | + }, | |
| 1979 | + "sales_30d": { | |
| 1980 | + "name": "sales_30d", | |
| 1981 | + "type": "integer", | |
| 1982 | + "primaryKey": false, | |
| 1983 | + "notNull": true, | |
| 1984 | + "default": 0 | |
| 1985 | + }, | |
| 1986 | + "sales_1y": { | |
| 1987 | + "name": "sales_1y", | |
| 1988 | + "type": "integer", | |
| 1989 | + "primaryKey": false, | |
| 1990 | + "notNull": true, | |
| 1991 | + "default": 0 | |
| 1992 | + }, | |
| 1993 | + "volume_30d_usd": { | |
| 1994 | + "name": "volume_30d_usd", | |
| 1995 | + "type": "numeric(18, 4)", | |
| 1996 | + "primaryKey": false, | |
| 1997 | + "notNull": false | |
| 1998 | + }, | |
| 1999 | + "active_listings": { | |
| 2000 | + "name": "active_listings", | |
| 2001 | + "type": "integer", | |
| 2002 | + "primaryKey": false, | |
| 2003 | + "notNull": true, | |
| 2004 | + "default": 0 | |
| 2005 | + }, | |
| 2006 | + "min_ask_usd": { | |
| 2007 | + "name": "min_ask_usd", | |
| 2008 | + "type": "numeric(18, 4)", | |
| 2009 | + "primaryKey": false, | |
| 2010 | + "notNull": false | |
| 2011 | + }, | |
| 2012 | + "observations_count": { | |
| 2013 | + "name": "observations_count", | |
| 2014 | + "type": "integer", | |
| 2015 | + "primaryKey": false, | |
| 2016 | + "notNull": true, | |
| 2017 | + "default": 0 | |
| 2018 | + }, | |
| 2019 | + "sources_count": { | |
| 2020 | + "name": "sources_count", | |
| 2021 | + "type": "integer", | |
| 2022 | + "primaryKey": false, | |
| 2023 | + "notNull": true, | |
| 2024 | + "default": 0 | |
| 2025 | + }, | |
| 2026 | + "liquidity_score": { | |
| 2027 | + "name": "liquidity_score", | |
| 2028 | + "type": "real", | |
| 2029 | + "primaryKey": false, | |
| 2030 | + "notNull": false | |
| 2031 | + }, | |
| 2032 | + "rarity_score": { | |
| 2033 | + "name": "rarity_score", | |
| 2034 | + "type": "real", | |
| 2035 | + "primaryKey": false, | |
| 2036 | + "notNull": false | |
| 2037 | + }, | |
| 2038 | + "momentum_7d": { | |
| 2039 | + "name": "momentum_7d", | |
| 2040 | + "type": "real", | |
| 2041 | + "primaryKey": false, | |
| 2042 | + "notNull": false | |
| 2043 | + }, | |
| 2044 | + "momentum_30d": { | |
| 2045 | + "name": "momentum_30d", | |
| 2046 | + "type": "real", | |
| 2047 | + "primaryKey": false, | |
| 2048 | + "notNull": false | |
| 2049 | + }, | |
| 2050 | + "momentum_90d": { | |
| 2051 | + "name": "momentum_90d", | |
| 2052 | + "type": "real", | |
| 2053 | + "primaryKey": false, | |
| 2054 | + "notNull": false | |
| 2055 | + }, | |
| 2056 | + "momentum_1y": { | |
| 2057 | + "name": "momentum_1y", | |
| 2058 | + "type": "real", | |
| 2059 | + "primaryKey": false, | |
| 2060 | + "notNull": false | |
| 2061 | + }, | |
| 2062 | + "trending_score": { | |
| 2063 | + "name": "trending_score", | |
| 2064 | + "type": "real", | |
| 2065 | + "primaryKey": false, | |
| 2066 | + "notNull": false | |
| 2067 | + }, | |
| 2068 | + "value_opportunity": { | |
| 2069 | + "name": "value_opportunity", | |
| 2070 | + "type": "real", | |
| 2071 | + "primaryKey": false, | |
| 2072 | + "notNull": false | |
| 2073 | + }, | |
| 2074 | + "data_quality": { | |
| 2075 | + "name": "data_quality", | |
| 2076 | + "type": "real", | |
| 2077 | + "primaryKey": false, | |
| 2078 | + "notNull": false | |
| 2079 | + }, | |
| 2080 | + "watchers": { | |
| 2081 | + "name": "watchers", | |
| 2082 | + "type": "integer", | |
| 2083 | + "primaryKey": false, | |
| 2084 | + "notNull": true, | |
| 2085 | + "default": 0 | |
| 2086 | + }, | |
| 2087 | + "views_30d": { | |
| 2088 | + "name": "views_30d", | |
| 2089 | + "type": "integer", | |
| 2090 | + "primaryKey": false, | |
| 2091 | + "notNull": true, | |
| 2092 | + "default": 0 | |
| 2093 | + }, | |
| 2094 | + "updated_at": { | |
| 2095 | + "name": "updated_at", | |
| 2096 | + "type": "timestamp with time zone", | |
| 2097 | + "primaryKey": false, | |
| 2098 | + "notNull": true, | |
| 2099 | + "default": "now()" | |
| 2100 | + } | |
| 2101 | + }, | |
| 2102 | + "indexes": { | |
| 2103 | + "asset_stats_riv_idx": { | |
| 2104 | + "name": "asset_stats_riv_idx", | |
| 2105 | + "columns": [ | |
| 2106 | + { | |
| 2107 | + "expression": "riv_usd", | |
| 2108 | + "isExpression": false, | |
| 2109 | + "asc": true, | |
| 2110 | + "nulls": "last" | |
| 2111 | + } | |
| 2112 | + ], | |
| 2113 | + "isUnique": false, | |
| 2114 | + "concurrently": false, | |
| 2115 | + "method": "btree", | |
| 2116 | + "with": {} | |
| 2117 | + }, | |
| 2118 | + "asset_stats_trending_idx": { | |
| 2119 | + "name": "asset_stats_trending_idx", | |
| 2120 | + "columns": [ | |
| 2121 | + { | |
| 2122 | + "expression": "trending_score", | |
| 2123 | + "isExpression": false, | |
| 2124 | + "asc": true, | |
| 2125 | + "nulls": "last" | |
| 2126 | + } | |
| 2127 | + ], | |
| 2128 | + "isUnique": false, | |
| 2129 | + "concurrently": false, | |
| 2130 | + "method": "btree", | |
| 2131 | + "with": {} | |
| 2132 | + }, | |
| 2133 | + "asset_stats_liquidity_idx": { | |
| 2134 | + "name": "asset_stats_liquidity_idx", | |
| 2135 | + "columns": [ | |
| 2136 | + { | |
| 2137 | + "expression": "liquidity_score", | |
| 2138 | + "isExpression": false, | |
| 2139 | + "asc": true, | |
| 2140 | + "nulls": "last" | |
| 2141 | + } | |
| 2142 | + ], | |
| 2143 | + "isUnique": false, | |
| 2144 | + "concurrently": false, | |
| 2145 | + "method": "btree", | |
| 2146 | + "with": {} | |
| 2147 | + } | |
| 2148 | + }, | |
| 2149 | + "foreignKeys": {}, | |
| 2150 | + "compositePrimaryKeys": {}, | |
| 2151 | + "uniqueConstraints": {}, | |
| 2152 | + "policies": {}, | |
| 2153 | + "checkConstraints": {}, | |
| 2154 | + "isRLSEnabled": false | |
| 2155 | + }, | |
| 2156 | + "public.asset_variants": { | |
| 2157 | + "name": "asset_variants", | |
| 2158 | + "schema": "", | |
| 2159 | + "columns": { | |
| 2160 | + "id": { | |
| 2161 | + "name": "id", | |
| 2162 | + "type": "text", | |
| 2163 | + "primaryKey": true, | |
| 2164 | + "notNull": true | |
| 2165 | + }, | |
| 2166 | + "asset_id": { | |
| 2167 | + "name": "asset_id", | |
| 2168 | + "type": "text", | |
| 2169 | + "primaryKey": false, | |
| 2170 | + "notNull": true | |
| 2171 | + }, | |
| 2172 | + "variant_key": { | |
| 2173 | + "name": "variant_key", | |
| 2174 | + "type": "text", | |
| 2175 | + "primaryKey": false, | |
| 2176 | + "notNull": true | |
| 2177 | + }, | |
| 2178 | + "grader": { | |
| 2179 | + "name": "grader", | |
| 2180 | + "type": "text", | |
| 2181 | + "primaryKey": false, | |
| 2182 | + "notNull": false | |
| 2183 | + }, | |
| 2184 | + "grade": { | |
| 2185 | + "name": "grade", | |
| 2186 | + "type": "text", | |
| 2187 | + "primaryKey": false, | |
| 2188 | + "notNull": false | |
| 2189 | + }, | |
| 2190 | + "qualifier": { | |
| 2191 | + "name": "qualifier", | |
| 2192 | + "type": "text", | |
| 2193 | + "primaryKey": false, | |
| 2194 | + "notNull": false | |
| 2195 | + }, | |
| 2196 | + "condition": { | |
| 2197 | + "name": "condition", | |
| 2198 | + "type": "text", | |
| 2199 | + "primaryKey": false, | |
| 2200 | + "notNull": false | |
| 2201 | + }, | |
| 2202 | + "completeness": { | |
| 2203 | + "name": "completeness", | |
| 2204 | + "type": "text", | |
| 2205 | + "primaryKey": false, | |
| 2206 | + "notNull": false | |
| 2207 | + }, | |
| 2208 | + "size_label": { | |
| 2209 | + "name": "size_label", | |
| 2210 | + "type": "text", | |
| 2211 | + "primaryKey": false, | |
| 2212 | + "notNull": false | |
| 2213 | + }, | |
| 2214 | + "label": { | |
| 2215 | + "name": "label", | |
| 2216 | + "type": "text", | |
| 2217 | + "primaryKey": false, | |
| 2218 | + "notNull": true | |
| 2219 | + }, | |
| 2220 | + "is_default": { | |
| 2221 | + "name": "is_default", | |
| 2222 | + "type": "boolean", | |
| 2223 | + "primaryKey": false, | |
| 2224 | + "notNull": true, | |
| 2225 | + "default": false | |
| 2226 | + }, | |
| 2227 | + "created_at": { | |
| 2228 | + "name": "created_at", | |
| 2229 | + "type": "timestamp with time zone", | |
| 2230 | + "primaryKey": false, | |
| 2231 | + "notNull": true, | |
| 2232 | + "default": "now()" | |
| 2233 | + } | |
| 2234 | + }, | |
| 2235 | + "indexes": { | |
| 2236 | + "asset_variants_uq": { | |
| 2237 | + "name": "asset_variants_uq", | |
| 2238 | + "columns": [ | |
| 2239 | + { | |
| 2240 | + "expression": "asset_id", | |
| 2241 | + "isExpression": false, | |
| 2242 | + "asc": true, | |
| 2243 | + "nulls": "last" | |
| 2244 | + }, | |
| 2245 | + { | |
| 2246 | + "expression": "variant_key", | |
| 2247 | + "isExpression": false, | |
| 2248 | + "asc": true, | |
| 2249 | + "nulls": "last" | |
| 2250 | + } | |
| 2251 | + ], | |
| 2252 | + "isUnique": true, | |
| 2253 | + "concurrently": false, | |
| 2254 | + "method": "btree", | |
| 2255 | + "with": {} | |
| 2256 | + }, | |
| 2257 | + "asset_variants_asset_idx": { | |
| 2258 | + "name": "asset_variants_asset_idx", | |
| 2259 | + "columns": [ | |
| 2260 | + { | |
| 2261 | + "expression": "asset_id", | |
| 2262 | + "isExpression": false, | |
| 2263 | + "asc": true, | |
| 2264 | + "nulls": "last" | |
| 2265 | + } | |
| 2266 | + ], | |
| 2267 | + "isUnique": false, | |
| 2268 | + "concurrently": false, | |
| 2269 | + "method": "btree", | |
| 2270 | + "with": {} | |
| 2271 | + } | |
| 2272 | + }, | |
| 2273 | + "foreignKeys": {}, | |
| 2274 | + "compositePrimaryKeys": {}, | |
| 2275 | + "uniqueConstraints": {}, | |
| 2276 | + "policies": {}, | |
| 2277 | + "checkConstraints": {}, | |
| 2278 | + "isRLSEnabled": false | |
| 2279 | + }, | |
| 2280 | + "public.assets": { | |
| 2281 | + "name": "assets", | |
| 2282 | + "schema": "", | |
| 2283 | + "columns": { | |
| 2284 | + "id": { | |
| 2285 | + "name": "id", | |
| 2286 | + "type": "text", | |
| 2287 | + "primaryKey": true, | |
| 2288 | + "notNull": true | |
| 2289 | + }, | |
| 2290 | + "slug": { | |
| 2291 | + "name": "slug", | |
| 2292 | + "type": "text", | |
| 2293 | + "primaryKey": false, | |
| 2294 | + "notNull": true | |
| 2295 | + }, | |
| 2296 | + "canonical_key": { | |
| 2297 | + "name": "canonical_key", | |
| 2298 | + "type": "text", | |
| 2299 | + "primaryKey": false, | |
| 2300 | + "notNull": true | |
| 2301 | + }, | |
| 2302 | + "category_slug": { | |
| 2303 | + "name": "category_slug", | |
| 2304 | + "type": "text", | |
| 2305 | + "primaryKey": false, | |
| 2306 | + "notNull": true | |
| 2307 | + }, | |
| 2308 | + "subcategory_slug": { | |
| 2309 | + "name": "subcategory_slug", | |
| 2310 | + "type": "text", | |
| 2311 | + "primaryKey": false, | |
| 2312 | + "notNull": false | |
| 2313 | + }, | |
| 2314 | + "family_slug": { | |
| 2315 | + "name": "family_slug", | |
| 2316 | + "type": "text", | |
| 2317 | + "primaryKey": false, | |
| 2318 | + "notNull": true | |
| 2319 | + }, | |
| 2320 | + "franchise": { | |
| 2321 | + "name": "franchise", | |
| 2322 | + "type": "text", | |
| 2323 | + "primaryKey": false, | |
| 2324 | + "notNull": false | |
| 2325 | + }, | |
| 2326 | + "brand": { | |
| 2327 | + "name": "brand", | |
| 2328 | + "type": "text", | |
| 2329 | + "primaryKey": false, | |
| 2330 | + "notNull": false | |
| 2331 | + }, | |
| 2332 | + "series": { | |
| 2333 | + "name": "series", | |
| 2334 | + "type": "text", | |
| 2335 | + "primaryKey": false, | |
| 2336 | + "notNull": false | |
| 2337 | + }, | |
| 2338 | + "set_slug": { | |
| 2339 | + "name": "set_slug", | |
| 2340 | + "type": "text", | |
| 2341 | + "primaryKey": false, | |
| 2342 | + "notNull": false | |
| 2343 | + }, | |
| 2344 | + "set_name": { | |
| 2345 | + "name": "set_name", | |
| 2346 | + "type": "text", | |
| 2347 | + "primaryKey": false, | |
| 2348 | + "notNull": false | |
| 2349 | + }, | |
| 2350 | + "set_code": { | |
| 2351 | + "name": "set_code", | |
| 2352 | + "type": "text", | |
| 2353 | + "primaryKey": false, | |
| 2354 | + "notNull": false | |
| 2355 | + }, | |
| 2356 | + "name": { | |
| 2357 | + "name": "name", | |
| 2358 | + "type": "text", | |
| 2359 | + "primaryKey": false, | |
| 2360 | + "notNull": true | |
| 2361 | + }, | |
| 2362 | + "title": { | |
| 2363 | + "name": "title", | |
| 2364 | + "type": "text", | |
| 2365 | + "primaryKey": false, | |
| 2366 | + "notNull": true | |
| 2367 | + }, | |
| 2368 | + "model": { | |
| 2369 | + "name": "model", | |
| 2370 | + "type": "text", | |
| 2371 | + "primaryKey": false, | |
| 2372 | + "notNull": false | |
| 2373 | + }, | |
| 2374 | + "reference": { | |
| 2375 | + "name": "reference", | |
| 2376 | + "type": "text", | |
| 2377 | + "primaryKey": false, | |
| 2378 | + "notNull": false | |
| 2379 | + }, | |
| 2380 | + "number": { | |
| 2381 | + "name": "number", | |
| 2382 | + "type": "text", | |
| 2383 | + "primaryKey": false, | |
| 2384 | + "notNull": false | |
| 2385 | + }, | |
| 2386 | + "year": { | |
| 2387 | + "name": "year", | |
| 2388 | + "type": "integer", | |
| 2389 | + "primaryKey": false, | |
| 2390 | + "notNull": false | |
| 2391 | + }, | |
| 2392 | + "edition": { | |
| 2393 | + "name": "edition", | |
| 2394 | + "type": "text", | |
| 2395 | + "primaryKey": false, | |
| 2396 | + "notNull": false | |
| 2397 | + }, | |
| 2398 | + "variant": { | |
| 2399 | + "name": "variant", | |
| 2400 | + "type": "text", | |
| 2401 | + "primaryKey": false, | |
| 2402 | + "notNull": false | |
| 2403 | + }, | |
| 2404 | + "language": { | |
| 2405 | + "name": "language", | |
| 2406 | + "type": "text", | |
| 2407 | + "primaryKey": false, | |
| 2408 | + "notNull": false | |
| 2409 | + }, | |
| 2410 | + "region": { | |
| 2411 | + "name": "region", | |
| 2412 | + "type": "text", | |
| 2413 | + "primaryKey": false, | |
| 2414 | + "notNull": false | |
| 2415 | + }, | |
| 2416 | + "country": { | |
| 2417 | + "name": "country", | |
| 2418 | + "type": "text", | |
| 2419 | + "primaryKey": false, | |
| 2420 | + "notNull": false | |
| 2421 | + }, | |
| 2422 | + "material": { | |
| 2423 | + "name": "material", | |
| 2424 | + "type": "text", | |
| 2425 | + "primaryKey": false, | |
| 2426 | + "notNull": false | |
| 2427 | + }, | |
| 2428 | + "size": { | |
| 2429 | + "name": "size", | |
| 2430 | + "type": "text", | |
| 2431 | + "primaryKey": false, | |
| 2432 | + "notNull": false | |
| 2433 | + }, | |
| 2434 | + "color": { | |
| 2435 | + "name": "color", | |
| 2436 | + "type": "text", | |
| 2437 | + "primaryKey": false, | |
| 2438 | + "notNull": false | |
| 2439 | + }, | |
| 2440 | + "rarity": { | |
| 2441 | + "name": "rarity", | |
| 2442 | + "type": "text", | |
| 2443 | + "primaryKey": false, | |
| 2444 | + "notNull": false | |
| 2445 | + }, | |
| 2446 | + "production_quantity": { | |
| 2447 | + "name": "production_quantity", | |
| 2448 | + "type": "integer", | |
| 2449 | + "primaryKey": false, | |
| 2450 | + "notNull": false | |
| 2451 | + }, | |
| 2452 | + "original_msrp": { | |
| 2453 | + "name": "original_msrp", | |
| 2454 | + "type": "numeric(18, 4)", | |
| 2455 | + "primaryKey": false, | |
| 2456 | + "notNull": false | |
| 2457 | + }, | |
| 2458 | + "original_msrp_currency": { | |
| 2459 | + "name": "original_msrp_currency", | |
| 2460 | + "type": "text", | |
| 2461 | + "primaryKey": false, | |
| 2462 | + "notNull": false | |
| 2463 | + }, | |
| 2464 | + "release_date": { | |
| 2465 | + "name": "release_date", | |
| 2466 | + "type": "text", | |
| 2467 | + "primaryKey": false, | |
| 2468 | + "notNull": false | |
| 2469 | + }, | |
| 2470 | + "description": { | |
| 2471 | + "name": "description", | |
| 2472 | + "type": "text", | |
| 2473 | + "primaryKey": false, | |
| 2474 | + "notNull": false | |
| 2475 | + }, | |
| 2476 | + "hero_image_url": { | |
| 2477 | + "name": "hero_image_url", | |
| 2478 | + "type": "text", | |
| 2479 | + "primaryKey": false, | |
| 2480 | + "notNull": false | |
| 2481 | + }, | |
| 2482 | + "identifiers": { | |
| 2483 | + "name": "identifiers", | |
| 2484 | + "type": "jsonb", | |
| 2485 | + "primaryKey": false, | |
| 2486 | + "notNull": true, | |
| 2487 | + "default": "'{}'::jsonb" | |
| 2488 | + }, | |
| 2489 | + "metadata": { | |
| 2490 | + "name": "metadata", | |
| 2491 | + "type": "jsonb", | |
| 2492 | + "primaryKey": false, | |
| 2493 | + "notNull": true, | |
| 2494 | + "default": "'{}'::jsonb" | |
| 2495 | + }, | |
| 2496 | + "merged_from": { | |
| 2497 | + "name": "merged_from", | |
| 2498 | + "type": "text[]", | |
| 2499 | + "primaryKey": false, | |
| 2500 | + "notNull": true, | |
| 2501 | + "default": "'{}'::text[]" | |
| 2502 | + }, | |
| 2503 | + "data_quality": { | |
| 2504 | + "name": "data_quality", | |
| 2505 | + "type": "real", | |
| 2506 | + "primaryKey": false, | |
| 2507 | + "notNull": true, | |
| 2508 | + "default": 0 | |
| 2509 | + }, | |
| 2510 | + "verified": { | |
| 2511 | + "name": "verified", | |
| 2512 | + "type": "boolean", | |
| 2513 | + "primaryKey": false, | |
| 2514 | + "notNull": true, | |
| 2515 | + "default": false | |
| 2516 | + }, | |
| 2517 | + "search": { | |
| 2518 | + "name": "search", | |
| 2519 | + "type": "tsvector", | |
| 2520 | + "primaryKey": false, | |
| 2521 | + "notNull": false, | |
| 2522 | + "generated": { | |
| 2523 | + "as": "setweight(to_tsvector('simple', coalesce(name, '')), 'A') || setweight(to_tsvector('simple', coalesce(set_name, '') || ' ' || coalesce(number, '') || ' ' || coalesce(variant, '') || ' ' || coalesce(edition, '')), 'B') || setweight(to_tsvector('simple', coalesce(brand, '') || ' ' || coalesce(franchise, '') || ' ' || coalesce(reference, '') || ' ' || coalesce(model, '') || ' ' || coalesce(year::text, '') || ' ' || coalesce(category_slug, '')), 'C')", | |
| 2524 | + "type": "stored" | |
| 2525 | + } | |
| 2526 | + }, | |
| 2527 | + "created_at": { | |
| 2528 | + "name": "created_at", | |
| 2529 | + "type": "timestamp with time zone", | |
| 2530 | + "primaryKey": false, | |
| 2531 | + "notNull": true, | |
| 2532 | + "default": "now()" | |
| 2533 | + }, | |
| 2534 | + "updated_at": { | |
| 2535 | + "name": "updated_at", | |
| 2536 | + "type": "timestamp with time zone", | |
| 2537 | + "primaryKey": false, | |
| 2538 | + "notNull": true, | |
| 2539 | + "default": "now()" | |
| 2540 | + } | |
| 2541 | + }, | |
| 2542 | + "indexes": { | |
| 2543 | + "assets_canonical_key_uq": { | |
| 2544 | + "name": "assets_canonical_key_uq", | |
| 2545 | + "columns": [ | |
| 2546 | + { | |
| 2547 | + "expression": "canonical_key", | |
| 2548 | + "isExpression": false, | |
| 2549 | + "asc": true, | |
| 2550 | + "nulls": "last" | |
| 2551 | + } | |
| 2552 | + ], | |
| 2553 | + "isUnique": true, | |
| 2554 | + "concurrently": false, | |
| 2555 | + "method": "btree", | |
| 2556 | + "with": {} | |
| 2557 | + }, | |
| 2558 | + "assets_slug_uq": { | |
| 2559 | + "name": "assets_slug_uq", | |
| 2560 | + "columns": [ | |
| 2561 | + { | |
| 2562 | + "expression": "slug", | |
| 2563 | + "isExpression": false, | |
| 2564 | + "asc": true, | |
| 2565 | + "nulls": "last" | |
| 2566 | + } | |
| 2567 | + ], | |
| 2568 | + "isUnique": true, | |
| 2569 | + "concurrently": false, | |
| 2570 | + "method": "btree", | |
| 2571 | + "with": {} | |
| 2572 | + }, | |
| 2573 | + "assets_category_idx": { | |
| 2574 | + "name": "assets_category_idx", | |
| 2575 | + "columns": [ | |
| 2576 | + { | |
| 2577 | + "expression": "category_slug", | |
| 2578 | + "isExpression": false, | |
| 2579 | + "asc": true, | |
| 2580 | + "nulls": "last" | |
| 2581 | + } | |
| 2582 | + ], | |
| 2583 | + "isUnique": false, | |
| 2584 | + "concurrently": false, | |
| 2585 | + "method": "btree", | |
| 2586 | + "with": {} | |
| 2587 | + }, | |
| 2588 | + "assets_family_idx": { | |
| 2589 | + "name": "assets_family_idx", | |
| 2590 | + "columns": [ | |
| 2591 | + { | |
| 2592 | + "expression": "family_slug", | |
| 2593 | + "isExpression": false, | |
| 2594 | + "asc": true, | |
| 2595 | + "nulls": "last" | |
| 2596 | + } | |
| 2597 | + ], | |
| 2598 | + "isUnique": false, | |
| 2599 | + "concurrently": false, | |
| 2600 | + "method": "btree", | |
| 2601 | + "with": {} | |
| 2602 | + }, | |
| 2603 | + "assets_set_idx": { | |
| 2604 | + "name": "assets_set_idx", | |
| 2605 | + "columns": [ | |
| 2606 | + { | |
| 2607 | + "expression": "set_slug", | |
| 2608 | + "isExpression": false, | |
| 2609 | + "asc": true, | |
| 2610 | + "nulls": "last" | |
| 2611 | + } | |
| 2612 | + ], | |
| 2613 | + "isUnique": false, | |
| 2614 | + "concurrently": false, | |
| 2615 | + "method": "btree", | |
| 2616 | + "with": {} | |
| 2617 | + }, | |
| 2618 | + "assets_search_gin": { | |
| 2619 | + "name": "assets_search_gin", | |
| 2620 | + "columns": [ | |
| 2621 | + { | |
| 2622 | + "expression": "search", | |
| 2623 | + "isExpression": false, | |
| 2624 | + "asc": true, | |
| 2625 | + "nulls": "last" | |
| 2626 | + } | |
| 2627 | + ], | |
| 2628 | + "isUnique": false, | |
| 2629 | + "concurrently": false, | |
| 2630 | + "method": "gin", | |
| 2631 | + "with": {} | |
| 2632 | + }, | |
| 2633 | + "assets_title_trgm": { | |
| 2634 | + "name": "assets_title_trgm", | |
| 2635 | + "columns": [ | |
| 2636 | + { | |
| 2637 | + "expression": "\"title\" gin_trgm_ops", | |
| 2638 | + "asc": true, | |
| 2639 | + "isExpression": true, | |
| 2640 | + "nulls": "last" | |
| 2641 | + } | |
| 2642 | + ], | |
| 2643 | + "isUnique": false, | |
| 2644 | + "concurrently": false, | |
| 2645 | + "method": "gin", | |
| 2646 | + "with": {} | |
| 2647 | + }, | |
| 2648 | + "assets_identifiers_gin": { | |
| 2649 | + "name": "assets_identifiers_gin", | |
| 2650 | + "columns": [ | |
| 2651 | + { | |
| 2652 | + "expression": "identifiers", | |
| 2653 | + "isExpression": false, | |
| 2654 | + "asc": true, | |
| 2655 | + "nulls": "last" | |
| 2656 | + } | |
| 2657 | + ], | |
| 2658 | + "isUnique": false, | |
| 2659 | + "concurrently": false, | |
| 2660 | + "method": "gin", | |
| 2661 | + "with": {} | |
| 2662 | + } | |
| 2663 | + }, | |
| 2664 | + "foreignKeys": {}, | |
| 2665 | + "compositePrimaryKeys": {}, | |
| 2666 | + "uniqueConstraints": {}, | |
| 2667 | + "policies": {}, | |
| 2668 | + "checkConstraints": {}, | |
| 2669 | + "isRLSEnabled": false | |
| 2670 | + }, | |
| 2671 | + "public.grade_premiums": { | |
| 2672 | + "name": "grade_premiums", | |
| 2673 | + "schema": "", | |
| 2674 | + "columns": { | |
| 2675 | + "id": { | |
| 2676 | + "name": "id", | |
| 2677 | + "type": "text", | |
| 2678 | + "primaryKey": true, | |
| 2679 | + "notNull": true | |
| 2680 | + }, | |
| 2681 | + "category_slug": { | |
| 2682 | + "name": "category_slug", | |
| 2683 | + "type": "text", | |
| 2684 | + "primaryKey": false, | |
| 2685 | + "notNull": true | |
| 2686 | + }, | |
| 2687 | + "grader": { | |
| 2688 | + "name": "grader", | |
| 2689 | + "type": "text", | |
| 2690 | + "primaryKey": false, | |
| 2691 | + "notNull": true | |
| 2692 | + }, | |
| 2693 | + "grade": { | |
| 2694 | + "name": "grade", | |
| 2695 | + "type": "text", | |
| 2696 | + "primaryKey": false, | |
| 2697 | + "notNull": true | |
| 2698 | + }, | |
| 2699 | + "market_multiplier": { | |
| 2700 | + "name": "market_multiplier", | |
| 2701 | + "type": "real", | |
| 2702 | + "primaryKey": false, | |
| 2703 | + "notNull": true | |
| 2704 | + }, | |
| 2705 | + "sample_size": { | |
| 2706 | + "name": "sample_size", | |
| 2707 | + "type": "integer", | |
| 2708 | + "primaryKey": false, | |
| 2709 | + "notNull": true | |
| 2710 | + }, | |
| 2711 | + "computed_at": { | |
| 2712 | + "name": "computed_at", | |
| 2713 | + "type": "timestamp with time zone", | |
| 2714 | + "primaryKey": false, | |
| 2715 | + "notNull": true | |
| 2716 | + } | |
| 2717 | + }, | |
| 2718 | + "indexes": { | |
| 2719 | + "grade_premiums_uq": { | |
| 2720 | + "name": "grade_premiums_uq", | |
| 2721 | + "columns": [ | |
| 2722 | + { | |
| 2723 | + "expression": "category_slug", | |
| 2724 | + "isExpression": false, | |
| 2725 | + "asc": true, | |
| 2726 | + "nulls": "last" | |
| 2727 | + }, | |
| 2728 | + { | |
| 2729 | + "expression": "grader", | |
| 2730 | + "isExpression": false, | |
| 2731 | + "asc": true, | |
| 2732 | + "nulls": "last" | |
| 2733 | + }, | |
| 2734 | + { | |
| 2735 | + "expression": "grade", | |
| 2736 | + "isExpression": false, | |
| 2737 | + "asc": true, | |
| 2738 | + "nulls": "last" | |
| 2739 | + } | |
| 2740 | + ], | |
| 2741 | + "isUnique": true, | |
| 2742 | + "concurrently": false, | |
| 2743 | + "method": "btree", | |
| 2744 | + "with": {} | |
| 2745 | + } | |
| 2746 | + }, | |
| 2747 | + "foreignKeys": {}, | |
| 2748 | + "compositePrimaryKeys": {}, | |
| 2749 | + "uniqueConstraints": {}, | |
| 2750 | + "policies": {}, | |
| 2751 | + "checkConstraints": {}, | |
| 2752 | + "isRLSEnabled": false | |
| 2753 | + }, | |
| 2754 | + "public.images": { | |
| 2755 | + "name": "images", | |
| 2756 | + "schema": "", | |
| 2757 | + "columns": { | |
| 2758 | + "id": { | |
| 2759 | + "name": "id", | |
| 2760 | + "type": "text", | |
| 2761 | + "primaryKey": true, | |
| 2762 | + "notNull": true | |
| 2763 | + }, | |
| 2764 | + "asset_id": { | |
| 2765 | + "name": "asset_id", | |
| 2766 | + "type": "text", | |
| 2767 | + "primaryKey": false, | |
| 2768 | + "notNull": false | |
| 2769 | + }, | |
| 2770 | + "listing_id": { | |
| 2771 | + "name": "listing_id", | |
| 2772 | + "type": "text", | |
| 2773 | + "primaryKey": false, | |
| 2774 | + "notNull": false | |
| 2775 | + }, | |
| 2776 | + "sale_id": { | |
| 2777 | + "name": "sale_id", | |
| 2778 | + "type": "text", | |
| 2779 | + "primaryKey": false, | |
| 2780 | + "notNull": false | |
| 2781 | + }, | |
| 2782 | + "source_id": { | |
| 2783 | + "name": "source_id", | |
| 2784 | + "type": "text", | |
| 2785 | + "primaryKey": false, | |
| 2786 | + "notNull": false | |
| 2787 | + }, | |
| 2788 | + "url": { | |
| 2789 | + "name": "url", | |
| 2790 | + "type": "text", | |
| 2791 | + "primaryKey": false, | |
| 2792 | + "notNull": true | |
| 2793 | + }, | |
| 2794 | + "role": { | |
| 2795 | + "name": "role", | |
| 2796 | + "type": "text", | |
| 2797 | + "primaryKey": false, | |
| 2798 | + "notNull": true, | |
| 2799 | + "default": "'gallery'" | |
| 2800 | + }, | |
| 2801 | + "width": { | |
| 2802 | + "name": "width", | |
| 2803 | + "type": "integer", | |
| 2804 | + "primaryKey": false, | |
| 2805 | + "notNull": false | |
| 2806 | + }, | |
| 2807 | + "height": { | |
| 2808 | + "name": "height", | |
| 2809 | + "type": "integer", | |
| 2810 | + "primaryKey": false, | |
| 2811 | + "notNull": false | |
| 2812 | + }, | |
| 2813 | + "phash": { | |
| 2814 | + "name": "phash", | |
| 2815 | + "type": "text", | |
| 2816 | + "primaryKey": false, | |
| 2817 | + "notNull": false | |
| 2818 | + }, | |
| 2819 | + "embedding": { | |
| 2820 | + "name": "embedding", | |
| 2821 | + "type": "vector(512)", | |
| 2822 | + "primaryKey": false, | |
| 2823 | + "notNull": false | |
| 2824 | + }, | |
| 2825 | + "attribution": { | |
| 2826 | + "name": "attribution", | |
| 2827 | + "type": "text", | |
| 2828 | + "primaryKey": false, | |
| 2829 | + "notNull": false | |
| 2830 | + }, | |
| 2831 | + "created_at": { | |
| 2832 | + "name": "created_at", | |
| 2833 | + "type": "timestamp with time zone", | |
| 2834 | + "primaryKey": false, | |
| 2835 | + "notNull": true, | |
| 2836 | + "default": "now()" | |
| 2837 | + } | |
| 2838 | + }, | |
| 2839 | + "indexes": { | |
| 2840 | + "images_asset_idx": { | |
| 2841 | + "name": "images_asset_idx", | |
| 2842 | + "columns": [ | |
| 2843 | + { | |
| 2844 | + "expression": "asset_id", | |
| 2845 | + "isExpression": false, | |
| 2846 | + "asc": true, | |
| 2847 | + "nulls": "last" | |
| 2848 | + } | |
| 2849 | + ], | |
| 2850 | + "isUnique": false, | |
| 2851 | + "concurrently": false, | |
| 2852 | + "method": "btree", | |
| 2853 | + "with": {} | |
| 2854 | + }, | |
| 2855 | + "images_phash_idx": { | |
| 2856 | + "name": "images_phash_idx", | |
| 2857 | + "columns": [ | |
| 2858 | + { | |
| 2859 | + "expression": "phash", | |
| 2860 | + "isExpression": false, | |
| 2861 | + "asc": true, | |
| 2862 | + "nulls": "last" | |
| 2863 | + } | |
| 2864 | + ], | |
| 2865 | + "isUnique": false, | |
| 2866 | + "concurrently": false, | |
| 2867 | + "method": "btree", | |
| 2868 | + "with": {} | |
| 2869 | + }, | |
| 2870 | + "images_url_uq": { | |
| 2871 | + "name": "images_url_uq", | |
| 2872 | + "columns": [ | |
| 2873 | + { | |
| 2874 | + "expression": "url", | |
| 2875 | + "isExpression": false, | |
| 2876 | + "asc": true, | |
| 2877 | + "nulls": "last" | |
| 2878 | + } | |
| 2879 | + ], | |
| 2880 | + "isUnique": true, | |
| 2881 | + "concurrently": false, | |
| 2882 | + "method": "btree", | |
| 2883 | + "with": {} | |
| 2884 | + } | |
| 2885 | + }, | |
| 2886 | + "foreignKeys": {}, | |
| 2887 | + "compositePrimaryKeys": {}, | |
| 2888 | + "uniqueConstraints": {}, | |
| 2889 | + "policies": {}, | |
| 2890 | + "checkConstraints": {}, | |
| 2891 | + "isRLSEnabled": false | |
| 2892 | + }, | |
| 2893 | + "public.population_reports": { | |
| 2894 | + "name": "population_reports", | |
| 2895 | + "schema": "", | |
| 2896 | + "columns": { | |
| 2897 | + "id": { | |
| 2898 | + "name": "id", | |
| 2899 | + "type": "text", | |
| 2900 | + "primaryKey": true, | |
| 2901 | + "notNull": true | |
| 2902 | + }, | |
| 2903 | + "asset_id": { | |
| 2904 | + "name": "asset_id", | |
| 2905 | + "type": "text", | |
| 2906 | + "primaryKey": false, | |
| 2907 | + "notNull": true | |
| 2908 | + }, | |
| 2909 | + "grader": { | |
| 2910 | + "name": "grader", | |
| 2911 | + "type": "text", | |
| 2912 | + "primaryKey": false, | |
| 2913 | + "notNull": true | |
| 2914 | + }, | |
| 2915 | + "source_id": { | |
| 2916 | + "name": "source_id", | |
| 2917 | + "type": "text", | |
| 2918 | + "primaryKey": false, | |
| 2919 | + "notNull": true | |
| 2920 | + }, | |
| 2921 | + "source_url": { | |
| 2922 | + "name": "source_url", | |
| 2923 | + "type": "text", | |
| 2924 | + "primaryKey": false, | |
| 2925 | + "notNull": false | |
| 2926 | + }, | |
| 2927 | + "report_date": { | |
| 2928 | + "name": "report_date", | |
| 2929 | + "type": "text", | |
| 2930 | + "primaryKey": false, | |
| 2931 | + "notNull": true | |
| 2932 | + }, | |
| 2933 | + "total": { | |
| 2934 | + "name": "total", | |
| 2935 | + "type": "integer", | |
| 2936 | + "primaryKey": false, | |
| 2937 | + "notNull": true | |
| 2938 | + }, | |
| 2939 | + "by_grade": { | |
| 2940 | + "name": "by_grade", | |
| 2941 | + "type": "jsonb", | |
| 2942 | + "primaryKey": false, | |
| 2943 | + "notNull": true | |
| 2944 | + }, | |
| 2945 | + "created_at": { | |
| 2946 | + "name": "created_at", | |
| 2947 | + "type": "timestamp with time zone", | |
| 2948 | + "primaryKey": false, | |
| 2949 | + "notNull": true, | |
| 2950 | + "default": "now()" | |
| 2951 | + } | |
| 2952 | + }, | |
| 2953 | + "indexes": { | |
| 2954 | + "population_reports_uq": { | |
| 2955 | + "name": "population_reports_uq", | |
| 2956 | + "columns": [ | |
| 2957 | + { | |
| 2958 | + "expression": "asset_id", | |
| 2959 | + "isExpression": false, | |
| 2960 | + "asc": true, | |
| 2961 | + "nulls": "last" | |
| 2962 | + }, | |
| 2963 | + { | |
| 2964 | + "expression": "grader", | |
| 2965 | + "isExpression": false, | |
| 2966 | + "asc": true, | |
| 2967 | + "nulls": "last" | |
| 2968 | + }, | |
| 2969 | + { | |
| 2970 | + "expression": "report_date", | |
| 2971 | + "isExpression": false, | |
| 2972 | + "asc": true, | |
| 2973 | + "nulls": "last" | |
| 2974 | + } | |
| 2975 | + ], | |
| 2976 | + "isUnique": true, | |
| 2977 | + "concurrently": false, | |
| 2978 | + "method": "btree", | |
| 2979 | + "with": {} | |
| 2980 | + } | |
| 2981 | + }, | |
| 2982 | + "foreignKeys": {}, | |
| 2983 | + "compositePrimaryKeys": {}, | |
| 2984 | + "uniqueConstraints": {}, | |
| 2985 | + "policies": {}, | |
| 2986 | + "checkConstraints": {}, | |
| 2987 | + "isRLSEnabled": false | |
| 2988 | + }, | |
| 2989 | + "public.variant_stats": { | |
| 2990 | + "name": "variant_stats", | |
| 2991 | + "schema": "", | |
| 2992 | + "columns": { | |
| 2993 | + "variant_id": { | |
| 2994 | + "name": "variant_id", | |
| 2995 | + "type": "text", | |
| 2996 | + "primaryKey": true, | |
| 2997 | + "notNull": true | |
| 2998 | + }, | |
| 2999 | + "asset_id": { | |
| 3000 | + "name": "asset_id", | |
| 3001 | + "type": "text", | |
| 3002 | + "primaryKey": false, | |
| 3003 | + "notNull": true | |
| 3004 | + }, | |
| 3005 | + "riv_usd": { | |
| 3006 | + "name": "riv_usd", | |
| 3007 | + "type": "numeric(18, 4)", | |
| 3008 | + "primaryKey": false, | |
| 3009 | + "notNull": false | |
| 3010 | + }, | |
| 3011 | + "riv_low_usd": { | |
| 3012 | + "name": "riv_low_usd", | |
| 3013 | + "type": "numeric(18, 4)", | |
| 3014 | + "primaryKey": false, | |
| 3015 | + "notNull": false | |
| 3016 | + }, | |
| 3017 | + "riv_high_usd": { | |
| 3018 | + "name": "riv_high_usd", | |
| 3019 | + "type": "numeric(18, 4)", | |
| 3020 | + "primaryKey": false, | |
| 3021 | + "notNull": false | |
| 3022 | + }, | |
| 3023 | + "riv_confidence": { | |
| 3024 | + "name": "riv_confidence", | |
| 3025 | + "type": "numeric(8, 6)", | |
| 3026 | + "primaryKey": false, | |
| 3027 | + "notNull": false | |
| 3028 | + }, | |
| 3029 | + "riv_sample_size": { | |
| 3030 | + "name": "riv_sample_size", | |
| 3031 | + "type": "integer", | |
| 3032 | + "primaryKey": false, | |
| 3033 | + "notNull": true, | |
| 3034 | + "default": 0 | |
| 3035 | + }, | |
| 3036 | + "latest_sale_usd": { | |
| 3037 | + "name": "latest_sale_usd", | |
| 3038 | + "type": "numeric(18, 4)", | |
| 3039 | + "primaryKey": false, | |
| 3040 | + "notNull": false | |
| 3041 | + }, | |
| 3042 | + "latest_sale_at": { | |
| 3043 | + "name": "latest_sale_at", | |
| 3044 | + "type": "timestamp with time zone", | |
| 3045 | + "primaryKey": false, | |
| 3046 | + "notNull": false | |
| 3047 | + }, | |
| 3048 | + "change_30d": { | |
| 3049 | + "name": "change_30d", | |
| 3050 | + "type": "numeric(8, 6)", | |
| 3051 | + "primaryKey": false, | |
| 3052 | + "notNull": false | |
| 3053 | + }, | |
| 3054 | + "change_1y": { | |
| 3055 | + "name": "change_1y", | |
| 3056 | + "type": "numeric(8, 6)", | |
| 3057 | + "primaryKey": false, | |
| 3058 | + "notNull": false | |
| 3059 | + }, | |
| 3060 | + "sales_count": { | |
| 3061 | + "name": "sales_count", | |
| 3062 | + "type": "integer", | |
| 3063 | + "primaryKey": false, | |
| 3064 | + "notNull": true, | |
| 3065 | + "default": 0 | |
| 3066 | + }, | |
| 3067 | + "sales_30d": { | |
| 3068 | + "name": "sales_30d", | |
| 3069 | + "type": "integer", | |
| 3070 | + "primaryKey": false, | |
| 3071 | + "notNull": true, | |
| 3072 | + "default": 0 | |
| 3073 | + }, | |
| 3074 | + "active_listings": { | |
| 3075 | + "name": "active_listings", | |
| 3076 | + "type": "integer", | |
| 3077 | + "primaryKey": false, | |
| 3078 | + "notNull": true, | |
| 3079 | + "default": 0 | |
| 3080 | + }, | |
| 3081 | + "min_ask_usd": { | |
| 3082 | + "name": "min_ask_usd", | |
| 3083 | + "type": "numeric(18, 4)", | |
| 3084 | + "primaryKey": false, | |
| 3085 | + "notNull": false | |
| 3086 | + }, | |
| 3087 | + "liquidity_score": { | |
| 3088 | + "name": "liquidity_score", | |
| 3089 | + "type": "real", | |
| 3090 | + "primaryKey": false, | |
| 3091 | + "notNull": false | |
| 3092 | + }, | |
| 3093 | + "updated_at": { | |
| 3094 | + "name": "updated_at", | |
| 3095 | + "type": "timestamp with time zone", | |
| 3096 | + "primaryKey": false, | |
| 3097 | + "notNull": true, | |
| 3098 | + "default": "now()" | |
| 3099 | + } | |
| 3100 | + }, | |
| 3101 | + "indexes": {}, | |
| 3102 | + "foreignKeys": {}, | |
| 3103 | + "compositePrimaryKeys": {}, | |
| 3104 | + "uniqueConstraints": {}, | |
| 3105 | + "policies": {}, | |
| 3106 | + "checkConstraints": {}, | |
| 3107 | + "isRLSEnabled": false | |
| 3108 | + }, | |
| 3109 | + "public.auction_lots": { | |
| 3110 | + "name": "auction_lots", | |
| 3111 | + "schema": "", | |
| 3112 | + "columns": { | |
| 3113 | + "id": { | |
| 3114 | + "name": "id", | |
| 3115 | + "type": "text", | |
| 3116 | + "primaryKey": true, | |
| 3117 | + "notNull": true | |
| 3118 | + }, | |
| 3119 | + "auction_id": { | |
| 3120 | + "name": "auction_id", | |
| 3121 | + "type": "text", | |
| 3122 | + "primaryKey": false, | |
| 3123 | + "notNull": true | |
| 3124 | + }, | |
| 3125 | + "asset_id": { | |
| 3126 | + "name": "asset_id", | |
| 3127 | + "type": "text", | |
| 3128 | + "primaryKey": false, | |
| 3129 | + "notNull": false | |
| 3130 | + }, | |
| 3131 | + "variant_id": { | |
| 3132 | + "name": "variant_id", | |
| 3133 | + "type": "text", | |
| 3134 | + "primaryKey": false, | |
| 3135 | + "notNull": false | |
| 3136 | + }, | |
| 3137 | + "source_id": { | |
| 3138 | + "name": "source_id", | |
| 3139 | + "type": "text", | |
| 3140 | + "primaryKey": false, | |
| 3141 | + "notNull": true | |
| 3142 | + }, | |
| 3143 | + "lot_number": { | |
| 3144 | + "name": "lot_number", | |
| 3145 | + "type": "text", | |
| 3146 | + "primaryKey": false, | |
| 3147 | + "notNull": false | |
| 3148 | + }, | |
| 3149 | + "title": { | |
| 3150 | + "name": "title", | |
| 3151 | + "type": "text", | |
| 3152 | + "primaryKey": false, | |
| 3153 | + "notNull": true | |
| 3154 | + }, | |
| 3155 | + "url": { | |
| 3156 | + "name": "url", | |
| 3157 | + "type": "text", | |
| 3158 | + "primaryKey": false, | |
| 3159 | + "notNull": true | |
| 3160 | + }, | |
| 3161 | + "estimate_low": { | |
| 3162 | + "name": "estimate_low", | |
| 3163 | + "type": "numeric(18, 4)", | |
| 3164 | + "primaryKey": false, | |
| 3165 | + "notNull": false | |
| 3166 | + }, | |
| 3167 | + "estimate_high": { | |
| 3168 | + "name": "estimate_high", | |
| 3169 | + "type": "numeric(18, 4)", | |
| 3170 | + "primaryKey": false, | |
| 3171 | + "notNull": false | |
| 3172 | + }, | |
| 3173 | + "current_bid": { | |
| 3174 | + "name": "current_bid", | |
| 3175 | + "type": "numeric(18, 4)", | |
| 3176 | + "primaryKey": false, | |
| 3177 | + "notNull": false | |
| 3178 | + }, | |
| 3179 | + "hammer_price": { | |
| 3180 | + "name": "hammer_price", | |
| 3181 | + "type": "numeric(18, 4)", | |
| 3182 | + "primaryKey": false, | |
| 3183 | + "notNull": false | |
| 3184 | + }, | |
| 3185 | + "currency": { | |
| 3186 | + "name": "currency", | |
| 3187 | + "type": "text", | |
| 3188 | + "primaryKey": false, | |
| 3189 | + "notNull": false | |
| 3190 | + }, | |
| 3191 | + "bid_count": { | |
| 3192 | + "name": "bid_count", | |
| 3193 | + "type": "integer", | |
| 3194 | + "primaryKey": false, | |
| 3195 | + "notNull": false | |
| 3196 | + }, | |
| 3197 | + "starts_at": { | |
| 3198 | + "name": "starts_at", | |
| 3199 | + "type": "timestamp with time zone", | |
| 3200 | + "primaryKey": false, | |
| 3201 | + "notNull": false | |
| 3202 | + }, | |
| 3203 | + "ends_at": { | |
| 3204 | + "name": "ends_at", | |
| 3205 | + "type": "timestamp with time zone", | |
| 3206 | + "primaryKey": false, | |
| 3207 | + "notNull": false | |
| 3208 | + }, | |
| 3209 | + "status": { | |
| 3210 | + "name": "status", | |
| 3211 | + "type": "text", | |
| 3212 | + "primaryKey": false, | |
| 3213 | + "notNull": true, | |
| 3214 | + "default": "'upcoming'" | |
| 3215 | + }, | |
| 3216 | + "image_urls": { | |
| 3217 | + "name": "image_urls", | |
| 3218 | + "type": "jsonb", | |
| 3219 | + "primaryKey": false, | |
| 3220 | + "notNull": true, | |
| 3221 | + "default": "'[]'::jsonb" | |
| 3222 | + }, | |
| 3223 | + "grader": { | |
| 3224 | + "name": "grader", | |
| 3225 | + "type": "text", | |
| 3226 | + "primaryKey": false, | |
| 3227 | + "notNull": false | |
| 3228 | + }, | |
| 3229 | + "grade": { | |
| 3230 | + "name": "grade", | |
| 3231 | + "type": "text", | |
| 3232 | + "primaryKey": false, | |
| 3233 | + "notNull": false | |
| 3234 | + }, | |
| 3235 | + "created_at": { | |
| 3236 | + "name": "created_at", | |
| 3237 | + "type": "timestamp with time zone", | |
| 3238 | + "primaryKey": false, | |
| 3239 | + "notNull": true, | |
| 3240 | + "default": "now()" | |
| 3241 | + }, | |
| 3242 | + "updated_at": { | |
| 3243 | + "name": "updated_at", | |
| 3244 | + "type": "timestamp with time zone", | |
| 3245 | + "primaryKey": false, | |
| 3246 | + "notNull": true, | |
| 3247 | + "default": "now()" | |
| 3248 | + } | |
| 3249 | + }, | |
| 3250 | + "indexes": { | |
| 3251 | + "auction_lots_url_uq": { | |
| 3252 | + "name": "auction_lots_url_uq", | |
| 3253 | + "columns": [ | |
| 3254 | + { | |
| 3255 | + "expression": "url", | |
| 3256 | + "isExpression": false, | |
| 3257 | + "asc": true, | |
| 3258 | + "nulls": "last" | |
| 3259 | + } | |
| 3260 | + ], | |
| 3261 | + "isUnique": true, | |
| 3262 | + "concurrently": false, | |
| 3263 | + "method": "btree", | |
| 3264 | + "with": {} | |
| 3265 | + }, | |
| 3266 | + "auction_lots_auction_idx": { | |
| 3267 | + "name": "auction_lots_auction_idx", | |
| 3268 | + "columns": [ | |
| 3269 | + { | |
| 3270 | + "expression": "auction_id", | |
| 3271 | + "isExpression": false, | |
| 3272 | + "asc": true, | |
| 3273 | + "nulls": "last" | |
| 3274 | + } | |
| 3275 | + ], | |
| 3276 | + "isUnique": false, | |
| 3277 | + "concurrently": false, | |
| 3278 | + "method": "btree", | |
| 3279 | + "with": {} | |
| 3280 | + }, | |
| 3281 | + "auction_lots_asset_idx": { | |
| 3282 | + "name": "auction_lots_asset_idx", | |
| 3283 | + "columns": [ | |
| 3284 | + { | |
| 3285 | + "expression": "asset_id", | |
| 3286 | + "isExpression": false, | |
| 3287 | + "asc": true, | |
| 3288 | + "nulls": "last" | |
| 3289 | + } | |
| 3290 | + ], | |
| 3291 | + "isUnique": false, | |
| 3292 | + "concurrently": false, | |
| 3293 | + "method": "btree", | |
| 3294 | + "with": {} | |
| 3295 | + }, | |
| 3296 | + "auction_lots_ends_idx": { | |
| 3297 | + "name": "auction_lots_ends_idx", | |
| 3298 | + "columns": [ | |
| 3299 | + { | |
| 3300 | + "expression": "ends_at", | |
| 3301 | + "isExpression": false, | |
| 3302 | + "asc": true, | |
| 3303 | + "nulls": "last" | |
| 3304 | + } | |
| 3305 | + ], | |
| 3306 | + "isUnique": false, | |
| 3307 | + "concurrently": false, | |
| 3308 | + "method": "btree", | |
| 3309 | + "with": {} | |
| 3310 | + } | |
| 3311 | + }, | |
| 3312 | + "foreignKeys": {}, | |
| 3313 | + "compositePrimaryKeys": {}, | |
| 3314 | + "uniqueConstraints": {}, | |
| 3315 | + "policies": {}, | |
| 3316 | + "checkConstraints": {}, | |
| 3317 | + "isRLSEnabled": false | |
| 3318 | + }, | |
| 3319 | + "public.auctions": { | |
| 3320 | + "name": "auctions", | |
| 3321 | + "schema": "", | |
| 3322 | + "columns": { | |
| 3323 | + "id": { | |
| 3324 | + "name": "id", | |
| 3325 | + "type": "text", | |
| 3326 | + "primaryKey": true, | |
| 3327 | + "notNull": true | |
| 3328 | + }, | |
| 3329 | + "source_id": { | |
| 3330 | + "name": "source_id", | |
| 3331 | + "type": "text", | |
| 3332 | + "primaryKey": false, | |
| 3333 | + "notNull": true | |
| 3334 | + }, | |
| 3335 | + "auction_house": { | |
| 3336 | + "name": "auction_house", | |
| 3337 | + "type": "text", | |
| 3338 | + "primaryKey": false, | |
| 3339 | + "notNull": true | |
| 3340 | + }, | |
| 3341 | + "name": { | |
| 3342 | + "name": "name", | |
| 3343 | + "type": "text", | |
| 3344 | + "primaryKey": false, | |
| 3345 | + "notNull": true | |
| 3346 | + }, | |
| 3347 | + "url": { | |
| 3348 | + "name": "url", | |
| 3349 | + "type": "text", | |
| 3350 | + "primaryKey": false, | |
| 3351 | + "notNull": true | |
| 3352 | + }, | |
| 3353 | + "starts_at": { | |
| 3354 | + "name": "starts_at", | |
| 3355 | + "type": "timestamp with time zone", | |
| 3356 | + "primaryKey": false, | |
| 3357 | + "notNull": false | |
| 3358 | + }, | |
| 3359 | + "ends_at": { | |
| 3360 | + "name": "ends_at", | |
| 3361 | + "type": "timestamp with time zone", | |
| 3362 | + "primaryKey": false, | |
| 3363 | + "notNull": false | |
| 3364 | + }, | |
| 3365 | + "location": { | |
| 3366 | + "name": "location", | |
| 3367 | + "type": "text", | |
| 3368 | + "primaryKey": false, | |
| 3369 | + "notNull": false | |
| 3370 | + }, | |
| 3371 | + "category_slugs": { | |
| 3372 | + "name": "category_slugs", | |
| 3373 | + "type": "text[]", | |
| 3374 | + "primaryKey": false, | |
| 3375 | + "notNull": true, | |
| 3376 | + "default": "'{}'::text[]" | |
| 3377 | + }, | |
| 3378 | + "lot_count": { | |
| 3379 | + "name": "lot_count", | |
| 3380 | + "type": "integer", | |
| 3381 | + "primaryKey": false, | |
| 3382 | + "notNull": false | |
| 3383 | + }, | |
| 3384 | + "status": { | |
| 3385 | + "name": "status", | |
| 3386 | + "type": "text", | |
| 3387 | + "primaryKey": false, | |
| 3388 | + "notNull": true, | |
| 3389 | + "default": "'upcoming'" | |
| 3390 | + }, | |
| 3391 | + "currency": { | |
| 3392 | + "name": "currency", | |
| 3393 | + "type": "text", | |
| 3394 | + "primaryKey": false, | |
| 3395 | + "notNull": false | |
| 3396 | + }, | |
| 3397 | + "created_at": { | |
| 3398 | + "name": "created_at", | |
| 3399 | + "type": "timestamp with time zone", | |
| 3400 | + "primaryKey": false, | |
| 3401 | + "notNull": true, | |
| 3402 | + "default": "now()" | |
| 3403 | + }, | |
| 3404 | + "updated_at": { | |
| 3405 | + "name": "updated_at", | |
| 3406 | + "type": "timestamp with time zone", | |
| 3407 | + "primaryKey": false, | |
| 3408 | + "notNull": true, | |
| 3409 | + "default": "now()" | |
| 3410 | + } | |
| 3411 | + }, | |
| 3412 | + "indexes": { | |
| 3413 | + "auctions_url_uq": { | |
| 3414 | + "name": "auctions_url_uq", | |
| 3415 | + "columns": [ | |
| 3416 | + { | |
| 3417 | + "expression": "url", | |
| 3418 | + "isExpression": false, | |
| 3419 | + "asc": true, | |
| 3420 | + "nulls": "last" | |
| 3421 | + } | |
| 3422 | + ], | |
| 3423 | + "isUnique": true, | |
| 3424 | + "concurrently": false, | |
| 3425 | + "method": "btree", | |
| 3426 | + "with": {} | |
| 3427 | + }, | |
| 3428 | + "auctions_ends_idx": { | |
| 3429 | + "name": "auctions_ends_idx", | |
| 3430 | + "columns": [ | |
| 3431 | + { | |
| 3432 | + "expression": "ends_at", | |
| 3433 | + "isExpression": false, | |
| 3434 | + "asc": true, | |
| 3435 | + "nulls": "last" | |
| 3436 | + } | |
| 3437 | + ], | |
| 3438 | + "isUnique": false, | |
| 3439 | + "concurrently": false, | |
| 3440 | + "method": "btree", | |
| 3441 | + "with": {} | |
| 3442 | + } | |
| 3443 | + }, | |
| 3444 | + "foreignKeys": {}, | |
| 3445 | + "compositePrimaryKeys": {}, | |
| 3446 | + "uniqueConstraints": {}, | |
| 3447 | + "policies": {}, | |
| 3448 | + "checkConstraints": {}, | |
| 3449 | + "isRLSEnabled": false | |
| 3450 | + }, | |
| 3451 | + "public.cross_listing_groups": { | |
| 3452 | + "name": "cross_listing_groups", | |
| 3453 | + "schema": "", | |
| 3454 | + "columns": { | |
| 3455 | + "id": { | |
| 3456 | + "name": "id", | |
| 3457 | + "type": "text", | |
| 3458 | + "primaryKey": true, | |
| 3459 | + "notNull": true | |
| 3460 | + }, | |
| 3461 | + "asset_id": { | |
| 3462 | + "name": "asset_id", | |
| 3463 | + "type": "text", | |
| 3464 | + "primaryKey": false, | |
| 3465 | + "notNull": false | |
| 3466 | + }, | |
| 3467 | + "signals": { | |
| 3468 | + "name": "signals", | |
| 3469 | + "type": "jsonb", | |
| 3470 | + "primaryKey": false, | |
| 3471 | + "notNull": true, | |
| 3472 | + "default": "'{}'::jsonb" | |
| 3473 | + }, | |
| 3474 | + "created_at": { | |
| 3475 | + "name": "created_at", | |
| 3476 | + "type": "timestamp with time zone", | |
| 3477 | + "primaryKey": false, | |
| 3478 | + "notNull": true, | |
| 3479 | + "default": "now()" | |
| 3480 | + } | |
| 3481 | + }, | |
| 3482 | + "indexes": {}, | |
| 3483 | + "foreignKeys": {}, | |
| 3484 | + "compositePrimaryKeys": {}, | |
| 3485 | + "uniqueConstraints": {}, | |
| 3486 | + "policies": {}, | |
| 3487 | + "checkConstraints": {}, | |
| 3488 | + "isRLSEnabled": false | |
| 3489 | + }, | |
| 3490 | + "public.fx_rates": { | |
| 3491 | + "name": "fx_rates", | |
| 3492 | + "schema": "", | |
| 3493 | + "columns": { | |
| 3494 | + "date": { | |
| 3495 | + "name": "date", | |
| 3496 | + "type": "date", | |
| 3497 | + "primaryKey": false, | |
| 3498 | + "notNull": true | |
| 3499 | + }, | |
| 3500 | + "base": { | |
| 3501 | + "name": "base", | |
| 3502 | + "type": "text", | |
| 3503 | + "primaryKey": false, | |
| 3504 | + "notNull": true | |
| 3505 | + }, | |
| 3506 | + "quote": { | |
| 3507 | + "name": "quote", | |
| 3508 | + "type": "text", | |
| 3509 | + "primaryKey": false, | |
| 3510 | + "notNull": true | |
| 3511 | + }, | |
| 3512 | + "rate": { | |
| 3513 | + "name": "rate", | |
| 3514 | + "type": "real", | |
| 3515 | + "primaryKey": false, | |
| 3516 | + "notNull": true | |
| 3517 | + }, | |
| 3518 | + "source": { | |
| 3519 | + "name": "source", | |
| 3520 | + "type": "text", | |
| 3521 | + "primaryKey": false, | |
| 3522 | + "notNull": true, | |
| 3523 | + "default": "'ecb'" | |
| 3524 | + } | |
| 3525 | + }, | |
| 3526 | + "indexes": { | |
| 3527 | + "fx_rates_uq": { | |
| 3528 | + "name": "fx_rates_uq", | |
| 3529 | + "columns": [ | |
| 3530 | + { | |
| 3531 | + "expression": "date", | |
| 3532 | + "isExpression": false, | |
| 3533 | + "asc": true, | |
| 3534 | + "nulls": "last" | |
| 3535 | + }, | |
| 3536 | + { | |
| 3537 | + "expression": "base", | |
| 3538 | + "isExpression": false, | |
| 3539 | + "asc": true, | |
| 3540 | + "nulls": "last" | |
| 3541 | + }, | |
| 3542 | + { | |
| 3543 | + "expression": "quote", | |
| 3544 | + "isExpression": false, | |
| 3545 | + "asc": true, | |
| 3546 | + "nulls": "last" | |
| 3547 | + } | |
| 3548 | + ], | |
| 3549 | + "isUnique": true, | |
| 3550 | + "concurrently": false, | |
| 3551 | + "method": "btree", | |
| 3552 | + "with": {} | |
| 3553 | + } | |
| 3554 | + }, | |
| 3555 | + "foreignKeys": {}, | |
| 3556 | + "compositePrimaryKeys": {}, | |
| 3557 | + "uniqueConstraints": {}, | |
| 3558 | + "policies": {}, | |
| 3559 | + "checkConstraints": {}, | |
| 3560 | + "isRLSEnabled": false | |
| 3561 | + }, | |
| 3562 | + "public.listing_events": { | |
| 3563 | + "name": "listing_events", | |
| 3564 | + "schema": "", | |
| 3565 | + "columns": { | |
| 3566 | + "id": { | |
| 3567 | + "name": "id", | |
| 3568 | + "type": "text", | |
| 3569 | + "primaryKey": true, | |
| 3570 | + "notNull": true | |
| 3571 | + }, | |
| 3572 | + "listing_id": { | |
| 3573 | + "name": "listing_id", | |
| 3574 | + "type": "text", | |
| 3575 | + "primaryKey": false, | |
| 3576 | + "notNull": true | |
| 3577 | + }, | |
| 3578 | + "event_type": { | |
| 3579 | + "name": "event_type", | |
| 3580 | + "type": "text", | |
| 3581 | + "primaryKey": false, | |
| 3582 | + "notNull": true | |
| 3583 | + }, | |
| 3584 | + "old_price": { | |
| 3585 | + "name": "old_price", | |
| 3586 | + "type": "numeric(18, 4)", | |
| 3587 | + "primaryKey": false, | |
| 3588 | + "notNull": false | |
| 3589 | + }, | |
| 3590 | + "new_price": { | |
| 3591 | + "name": "new_price", | |
| 3592 | + "type": "numeric(18, 4)", | |
| 3593 | + "primaryKey": false, | |
| 3594 | + "notNull": false | |
| 3595 | + }, | |
| 3596 | + "currency": { | |
| 3597 | + "name": "currency", | |
| 3598 | + "type": "text", | |
| 3599 | + "primaryKey": false, | |
| 3600 | + "notNull": false | |
| 3601 | + }, | |
| 3602 | + "occurred_at": { | |
| 3603 | + "name": "occurred_at", | |
| 3604 | + "type": "timestamp with time zone", | |
| 3605 | + "primaryKey": false, | |
| 3606 | + "notNull": true | |
| 3607 | + } | |
| 3608 | + }, | |
| 3609 | + "indexes": { | |
| 3610 | + "listing_events_listing_idx": { | |
| 3611 | + "name": "listing_events_listing_idx", | |
| 3612 | + "columns": [ | |
| 3613 | + { | |
| 3614 | + "expression": "listing_id", | |
| 3615 | + "isExpression": false, | |
| 3616 | + "asc": true, | |
| 3617 | + "nulls": "last" | |
| 3618 | + }, | |
| 3619 | + { | |
| 3620 | + "expression": "occurred_at", | |
| 3621 | + "isExpression": false, | |
| 3622 | + "asc": true, | |
| 3623 | + "nulls": "last" | |
| 3624 | + } | |
| 3625 | + ], | |
| 3626 | + "isUnique": false, | |
| 3627 | + "concurrently": false, | |
| 3628 | + "method": "btree", | |
| 3629 | + "with": {} | |
| 3630 | + } | |
| 3631 | + }, | |
| 3632 | + "foreignKeys": {}, | |
| 3633 | + "compositePrimaryKeys": {}, | |
| 3634 | + "uniqueConstraints": {}, | |
| 3635 | + "policies": {}, | |
| 3636 | + "checkConstraints": {}, | |
| 3637 | + "isRLSEnabled": false | |
| 3638 | + }, | |
| 3639 | + "public.listings": { | |
| 3640 | + "name": "listings", | |
| 3641 | + "schema": "", | |
| 3642 | + "columns": { | |
| 3643 | + "id": { | |
| 3644 | + "name": "id", | |
| 3645 | + "type": "text", | |
| 3646 | + "primaryKey": true, | |
| 3647 | + "notNull": true | |
| 3648 | + }, | |
| 3649 | + "asset_id": { | |
| 3650 | + "name": "asset_id", | |
| 3651 | + "type": "text", | |
| 3652 | + "primaryKey": false, | |
| 3653 | + "notNull": true | |
| 3654 | + }, | |
| 3655 | + "variant_id": { | |
| 3656 | + "name": "variant_id", | |
| 3657 | + "type": "text", | |
| 3658 | + "primaryKey": false, | |
| 3659 | + "notNull": false | |
| 3660 | + }, | |
| 3661 | + "source_id": { | |
| 3662 | + "name": "source_id", | |
| 3663 | + "type": "text", | |
| 3664 | + "primaryKey": false, | |
| 3665 | + "notNull": true | |
| 3666 | + }, | |
| 3667 | + "connector_id": { | |
| 3668 | + "name": "connector_id", | |
| 3669 | + "type": "text", | |
| 3670 | + "primaryKey": false, | |
| 3671 | + "notNull": true | |
| 3672 | + }, | |
| 3673 | + "raw_record_id": { | |
| 3674 | + "name": "raw_record_id", | |
| 3675 | + "type": "text", | |
| 3676 | + "primaryKey": false, | |
| 3677 | + "notNull": false | |
| 3678 | + }, | |
| 3679 | + "source_url": { | |
| 3680 | + "name": "source_url", | |
| 3681 | + "type": "text", | |
| 3682 | + "primaryKey": false, | |
| 3683 | + "notNull": true | |
| 3684 | + }, | |
| 3685 | + "external_id": { | |
| 3686 | + "name": "external_id", | |
| 3687 | + "type": "text", | |
| 3688 | + "primaryKey": false, | |
| 3689 | + "notNull": true | |
| 3690 | + }, | |
| 3691 | + "listing_type": { | |
| 3692 | + "name": "listing_type", | |
| 3693 | + "type": "text", | |
| 3694 | + "primaryKey": false, | |
| 3695 | + "notNull": true, | |
| 3696 | + "default": "'unknown'" | |
| 3697 | + }, | |
| 3698 | + "price": { | |
| 3699 | + "name": "price", | |
| 3700 | + "type": "numeric(18, 4)", | |
| 3701 | + "primaryKey": false, | |
| 3702 | + "notNull": false | |
| 3703 | + }, | |
| 3704 | + "currency": { | |
| 3705 | + "name": "currency", | |
| 3706 | + "type": "text", | |
| 3707 | + "primaryKey": false, | |
| 3708 | + "notNull": false | |
| 3709 | + }, | |
| 3710 | + "price_usd": { | |
| 3711 | + "name": "price_usd", | |
| 3712 | + "type": "numeric(18, 4)", | |
| 3713 | + "primaryKey": false, | |
| 3714 | + "notNull": false | |
| 3715 | + }, | |
| 3716 | + "seller": { | |
| 3717 | + "name": "seller", | |
| 3718 | + "type": "text", | |
| 3719 | + "primaryKey": false, | |
| 3720 | + "notNull": false | |
| 3721 | + }, | |
| 3722 | + "seller_reputation": { | |
| 3723 | + "name": "seller_reputation", | |
| 3724 | + "type": "text", | |
| 3725 | + "primaryKey": false, | |
| 3726 | + "notNull": false | |
| 3727 | + }, | |
| 3728 | + "location": { | |
| 3729 | + "name": "location", | |
| 3730 | + "type": "text", | |
| 3731 | + "primaryKey": false, | |
| 3732 | + "notNull": false | |
| 3733 | + }, | |
| 3734 | + "shipping_cost": { | |
| 3735 | + "name": "shipping_cost", | |
| 3736 | + "type": "numeric(18, 4)", | |
| 3737 | + "primaryKey": false, | |
| 3738 | + "notNull": false | |
| 3739 | + }, | |
| 3740 | + "quantity": { | |
| 3741 | + "name": "quantity", | |
| 3742 | + "type": "integer", | |
| 3743 | + "primaryKey": false, | |
| 3744 | + "notNull": false | |
| 3745 | + }, | |
| 3746 | + "condition": { | |
| 3747 | + "name": "condition", | |
| 3748 | + "type": "text", | |
| 3749 | + "primaryKey": false, | |
| 3750 | + "notNull": false | |
| 3751 | + }, | |
| 3752 | + "grader": { | |
| 3753 | + "name": "grader", | |
| 3754 | + "type": "text", | |
| 3755 | + "primaryKey": false, | |
| 3756 | + "notNull": false | |
| 3757 | + }, | |
| 3758 | + "grade": { | |
| 3759 | + "name": "grade", | |
| 3760 | + "type": "text", | |
| 3761 | + "primaryKey": false, | |
| 3762 | + "notNull": false | |
| 3763 | + }, | |
| 3764 | + "certification_number": { | |
| 3765 | + "name": "certification_number", | |
| 3766 | + "type": "text", | |
| 3767 | + "primaryKey": false, | |
| 3768 | + "notNull": false | |
| 3769 | + }, | |
| 3770 | + "image_urls": { | |
| 3771 | + "name": "image_urls", | |
| 3772 | + "type": "jsonb", | |
| 3773 | + "primaryKey": false, | |
| 3774 | + "notNull": true, | |
| 3775 | + "default": "'[]'::jsonb" | |
| 3776 | + }, | |
| 3777 | + "raw_title": { | |
| 3778 | + "name": "raw_title", | |
| 3779 | + "type": "text", | |
| 3780 | + "primaryKey": false, | |
| 3781 | + "notNull": true | |
| 3782 | + }, | |
| 3783 | + "description": { | |
| 3784 | + "name": "description", | |
| 3785 | + "type": "text", | |
| 3786 | + "primaryKey": false, | |
| 3787 | + "notNull": false | |
| 3788 | + }, | |
| 3789 | + "listed_at": { | |
| 3790 | + "name": "listed_at", | |
| 3791 | + "type": "timestamp with time zone", | |
| 3792 | + "primaryKey": false, | |
| 3793 | + "notNull": false | |
| 3794 | + }, | |
| 3795 | + "ends_at": { | |
| 3796 | + "name": "ends_at", | |
| 3797 | + "type": "timestamp with time zone", | |
| 3798 | + "primaryKey": false, | |
| 3799 | + "notNull": false | |
| 3800 | + }, | |
| 3801 | + "availability": { | |
| 3802 | + "name": "availability", | |
| 3803 | + "type": "text", | |
| 3804 | + "primaryKey": false, | |
| 3805 | + "notNull": true, | |
| 3806 | + "default": "'available'" | |
| 3807 | + }, | |
| 3808 | + "bid_count": { | |
| 3809 | + "name": "bid_count", | |
| 3810 | + "type": "integer", | |
| 3811 | + "primaryKey": false, | |
| 3812 | + "notNull": false | |
| 3813 | + }, | |
| 3814 | + "first_seen_at": { | |
| 3815 | + "name": "first_seen_at", | |
| 3816 | + "type": "timestamp with time zone", | |
| 3817 | + "primaryKey": false, | |
| 3818 | + "notNull": true | |
| 3819 | + }, | |
| 3820 | + "last_seen_at": { | |
| 3821 | + "name": "last_seen_at", | |
| 3822 | + "type": "timestamp with time zone", | |
| 3823 | + "primaryKey": false, | |
| 3824 | + "notNull": true | |
| 3825 | + }, | |
| 3826 | + "price_changed_at": { | |
| 3827 | + "name": "price_changed_at", | |
| 3828 | + "type": "timestamp with time zone", | |
| 3829 | + "primaryKey": false, | |
| 3830 | + "notNull": false | |
| 3831 | + }, | |
| 3832 | + "cross_listing_group_id": { | |
| 3833 | + "name": "cross_listing_group_id", | |
| 3834 | + "type": "text", | |
| 3835 | + "primaryKey": false, | |
| 3836 | + "notNull": false | |
| 3837 | + }, | |
| 3838 | + "confidence": { | |
| 3839 | + "name": "confidence", | |
| 3840 | + "type": "numeric(8, 6)", | |
| 3841 | + "primaryKey": false, | |
| 3842 | + "notNull": true, | |
| 3843 | + "default": 0.8 | |
| 3844 | + }, | |
| 3845 | + "data_quality": { | |
| 3846 | + "name": "data_quality", | |
| 3847 | + "type": "real", | |
| 3848 | + "primaryKey": false, | |
| 3849 | + "notNull": true, | |
| 3850 | + "default": 0 | |
| 3851 | + }, | |
| 3852 | + "flags": { | |
| 3853 | + "name": "flags", | |
| 3854 | + "type": "text[]", | |
| 3855 | + "primaryKey": false, | |
| 3856 | + "notNull": true, | |
| 3857 | + "default": "'{}'::text[]" | |
| 3858 | + }, | |
| 3859 | + "discount_to_riv": { | |
| 3860 | + "name": "discount_to_riv", | |
| 3861 | + "type": "numeric(8, 6)", | |
| 3862 | + "primaryKey": false, | |
| 3863 | + "notNull": false | |
| 3864 | + }, | |
| 3865 | + "created_at": { | |
| 3866 | + "name": "created_at", | |
| 3867 | + "type": "timestamp with time zone", | |
| 3868 | + "primaryKey": false, | |
| 3869 | + "notNull": true, | |
| 3870 | + "default": "now()" | |
| 3871 | + }, | |
| 3872 | + "updated_at": { | |
| 3873 | + "name": "updated_at", | |
| 3874 | + "type": "timestamp with time zone", | |
| 3875 | + "primaryKey": false, | |
| 3876 | + "notNull": true, | |
| 3877 | + "default": "now()" | |
| 3878 | + } | |
| 3879 | + }, | |
| 3880 | + "indexes": { | |
| 3881 | + "listings_source_external_uq": { | |
| 3882 | + "name": "listings_source_external_uq", | |
| 3883 | + "columns": [ | |
| 3884 | + { | |
| 3885 | + "expression": "source_id", | |
| 3886 | + "isExpression": false, | |
| 3887 | + "asc": true, | |
| 3888 | + "nulls": "last" | |
| 3889 | + }, | |
| 3890 | + { | |
| 3891 | + "expression": "external_id", | |
| 3892 | + "isExpression": false, | |
| 3893 | + "asc": true, | |
| 3894 | + "nulls": "last" | |
| 3895 | + } | |
| 3896 | + ], | |
| 3897 | + "isUnique": true, | |
| 3898 | + "concurrently": false, | |
| 3899 | + "method": "btree", | |
| 3900 | + "with": {} | |
| 3901 | + }, | |
| 3902 | + "listings_asset_avail_idx": { | |
| 3903 | + "name": "listings_asset_avail_idx", | |
| 3904 | + "columns": [ | |
| 3905 | + { | |
| 3906 | + "expression": "asset_id", | |
| 3907 | + "isExpression": false, | |
| 3908 | + "asc": true, | |
| 3909 | + "nulls": "last" | |
| 3910 | + }, | |
| 3911 | + { | |
| 3912 | + "expression": "availability", | |
| 3913 | + "isExpression": false, | |
| 3914 | + "asc": true, | |
| 3915 | + "nulls": "last" | |
| 3916 | + } | |
| 3917 | + ], | |
| 3918 | + "isUnique": false, | |
| 3919 | + "concurrently": false, | |
| 3920 | + "method": "btree", | |
| 3921 | + "with": {} | |
| 3922 | + }, | |
| 3923 | + "listings_avail_price_idx": { | |
| 3924 | + "name": "listings_avail_price_idx", | |
| 3925 | + "columns": [ | |
| 3926 | + { | |
| 3927 | + "expression": "availability", | |
| 3928 | + "isExpression": false, | |
| 3929 | + "asc": true, | |
| 3930 | + "nulls": "last" | |
| 3931 | + }, | |
| 3932 | + { | |
| 3933 | + "expression": "price_usd", | |
| 3934 | + "isExpression": false, | |
| 3935 | + "asc": true, | |
| 3936 | + "nulls": "last" | |
| 3937 | + } | |
| 3938 | + ], | |
| 3939 | + "isUnique": false, | |
| 3940 | + "concurrently": false, | |
| 3941 | + "method": "btree", | |
| 3942 | + "with": {} | |
| 3943 | + }, | |
| 3944 | + "listings_ends_idx": { | |
| 3945 | + "name": "listings_ends_idx", | |
| 3946 | + "columns": [ | |
| 3947 | + { | |
| 3948 | + "expression": "ends_at", | |
| 3949 | + "isExpression": false, | |
| 3950 | + "asc": true, | |
| 3951 | + "nulls": "last" | |
| 3952 | + } | |
| 3953 | + ], | |
| 3954 | + "isUnique": false, | |
| 3955 | + "concurrently": false, | |
| 3956 | + "method": "btree", | |
| 3957 | + "with": {} | |
| 3958 | + }, | |
| 3959 | + "listings_last_seen_idx": { | |
| 3960 | + "name": "listings_last_seen_idx", | |
| 3961 | + "columns": [ | |
| 3962 | + { | |
| 3963 | + "expression": "last_seen_at", | |
| 3964 | + "isExpression": false, | |
| 3965 | + "asc": true, | |
| 3966 | + "nulls": "last" | |
| 3967 | + } | |
| 3968 | + ], | |
| 3969 | + "isUnique": false, | |
| 3970 | + "concurrently": false, | |
| 3971 | + "method": "btree", | |
| 3972 | + "with": {} | |
| 3973 | + } | |
| 3974 | + }, | |
| 3975 | + "foreignKeys": {}, | |
| 3976 | + "compositePrimaryKeys": {}, | |
| 3977 | + "uniqueConstraints": {}, | |
| 3978 | + "policies": {}, | |
| 3979 | + "checkConstraints": {}, | |
| 3980 | + "isRLSEnabled": false | |
| 3981 | + }, | |
| 3982 | + "public.news": { | |
| 3983 | + "name": "news", | |
| 3984 | + "schema": "", | |
| 3985 | + "columns": { | |
| 3986 | + "id": { | |
| 3987 | + "name": "id", | |
| 3988 | + "type": "text", | |
| 3989 | + "primaryKey": true, | |
| 3990 | + "notNull": true | |
| 3991 | + }, | |
| 3992 | + "source_id": { | |
| 3993 | + "name": "source_id", | |
| 3994 | + "type": "text", | |
| 3995 | + "primaryKey": false, | |
| 3996 | + "notNull": true | |
| 3997 | + }, | |
| 3998 | + "url": { | |
| 3999 | + "name": "url", | |
| 4000 | + "type": "text", | |
| 4001 | + "primaryKey": false, | |
| 4002 | + "notNull": true | |
| 4003 | + }, | |
| 4004 | + "title": { | |
| 4005 | + "name": "title", | |
| 4006 | + "type": "text", | |
| 4007 | + "primaryKey": false, | |
| 4008 | + "notNull": true | |
| 4009 | + }, | |
| 4010 | + "summary": { | |
| 4011 | + "name": "summary", | |
| 4012 | + "type": "text", | |
| 4013 | + "primaryKey": false, | |
| 4014 | + "notNull": false | |
| 4015 | + }, | |
| 4016 | + "ai_summary": { | |
| 4017 | + "name": "ai_summary", | |
| 4018 | + "type": "text", | |
| 4019 | + "primaryKey": false, | |
| 4020 | + "notNull": false | |
| 4021 | + }, | |
| 4022 | + "published_at": { | |
| 4023 | + "name": "published_at", | |
| 4024 | + "type": "timestamp with time zone", | |
| 4025 | + "primaryKey": false, | |
| 4026 | + "notNull": false | |
| 4027 | + }, | |
| 4028 | + "category_slugs": { | |
| 4029 | + "name": "category_slugs", | |
| 4030 | + "type": "text[]", | |
| 4031 | + "primaryKey": false, | |
| 4032 | + "notNull": true, | |
| 4033 | + "default": "'{}'::text[]" | |
| 4034 | + }, | |
| 4035 | + "news_type": { | |
| 4036 | + "name": "news_type", | |
| 4037 | + "type": "text", | |
| 4038 | + "primaryKey": false, | |
| 4039 | + "notNull": false | |
| 4040 | + }, | |
| 4041 | + "image_url": { | |
| 4042 | + "name": "image_url", | |
| 4043 | + "type": "text", | |
| 4044 | + "primaryKey": false, | |
| 4045 | + "notNull": false | |
| 4046 | + }, | |
| 4047 | + "fetched_at": { | |
| 4048 | + "name": "fetched_at", | |
| 4049 | + "type": "timestamp with time zone", | |
| 4050 | + "primaryKey": false, | |
| 4051 | + "notNull": true | |
| 4052 | + } | |
| 4053 | + }, | |
| 4054 | + "indexes": { | |
| 4055 | + "news_url_uq": { | |
| 4056 | + "name": "news_url_uq", | |
| 4057 | + "columns": [ | |
| 4058 | + { | |
| 4059 | + "expression": "url", | |
| 4060 | + "isExpression": false, | |
| 4061 | + "asc": true, | |
| 4062 | + "nulls": "last" | |
| 4063 | + } | |
| 4064 | + ], | |
| 4065 | + "isUnique": true, | |
| 4066 | + "concurrently": false, | |
| 4067 | + "method": "btree", | |
| 4068 | + "with": {} | |
| 4069 | + }, | |
| 4070 | + "news_published_idx": { | |
| 4071 | + "name": "news_published_idx", | |
| 4072 | + "columns": [ | |
| 4073 | + { | |
| 4074 | + "expression": "published_at", | |
| 4075 | + "isExpression": false, | |
| 4076 | + "asc": true, | |
| 4077 | + "nulls": "last" | |
| 4078 | + } | |
| 4079 | + ], | |
| 4080 | + "isUnique": false, | |
| 4081 | + "concurrently": false, | |
| 4082 | + "method": "btree", | |
| 4083 | + "with": {} | |
| 4084 | + } | |
| 4085 | + }, | |
| 4086 | + "foreignKeys": {}, | |
| 4087 | + "compositePrimaryKeys": {}, | |
| 4088 | + "uniqueConstraints": {}, | |
| 4089 | + "policies": {}, | |
| 4090 | + "checkConstraints": {}, | |
| 4091 | + "isRLSEnabled": false | |
| 4092 | + }, | |
| 4093 | + "public.price_observations": { | |
| 4094 | + "name": "price_observations", | |
| 4095 | + "schema": "", | |
| 4096 | + "columns": { | |
| 4097 | + "id": { | |
| 4098 | + "name": "id", | |
| 4099 | + "type": "text", | |
| 4100 | + "primaryKey": true, | |
| 4101 | + "notNull": true | |
| 4102 | + }, | |
| 4103 | + "asset_id": { | |
| 4104 | + "name": "asset_id", | |
| 4105 | + "type": "text", | |
| 4106 | + "primaryKey": false, | |
| 4107 | + "notNull": true | |
| 4108 | + }, | |
| 4109 | + "variant_id": { | |
| 4110 | + "name": "variant_id", | |
| 4111 | + "type": "text", | |
| 4112 | + "primaryKey": false, | |
| 4113 | + "notNull": false | |
| 4114 | + }, | |
| 4115 | + "source_id": { | |
| 4116 | + "name": "source_id", | |
| 4117 | + "type": "text", | |
| 4118 | + "primaryKey": false, | |
| 4119 | + "notNull": true | |
| 4120 | + }, | |
| 4121 | + "connector_id": { | |
| 4122 | + "name": "connector_id", | |
| 4123 | + "type": "text", | |
| 4124 | + "primaryKey": false, | |
| 4125 | + "notNull": true | |
| 4126 | + }, | |
| 4127 | + "raw_record_id": { | |
| 4128 | + "name": "raw_record_id", | |
| 4129 | + "type": "text", | |
| 4130 | + "primaryKey": false, | |
| 4131 | + "notNull": false | |
| 4132 | + }, | |
| 4133 | + "source_url": { | |
| 4134 | + "name": "source_url", | |
| 4135 | + "type": "text", | |
| 4136 | + "primaryKey": false, | |
| 4137 | + "notNull": true | |
| 4138 | + }, | |
| 4139 | + "price_kind": { | |
| 4140 | + "name": "price_kind", | |
| 4141 | + "type": "text", | |
| 4142 | + "primaryKey": false, | |
| 4143 | + "notNull": true | |
| 4144 | + }, | |
| 4145 | + "price": { | |
| 4146 | + "name": "price", | |
| 4147 | + "type": "numeric(18, 4)", | |
| 4148 | + "primaryKey": false, | |
| 4149 | + "notNull": true | |
| 4150 | + }, | |
| 4151 | + "currency": { | |
| 4152 | + "name": "currency", | |
| 4153 | + "type": "text", | |
| 4154 | + "primaryKey": false, | |
| 4155 | + "notNull": true | |
| 4156 | + }, | |
| 4157 | + "price_usd": { | |
| 4158 | + "name": "price_usd", | |
| 4159 | + "type": "numeric(18, 4)", | |
| 4160 | + "primaryKey": false, | |
| 4161 | + "notNull": true | |
| 4162 | + }, | |
| 4163 | + "observation_date": { | |
| 4164 | + "name": "observation_date", | |
| 4165 | + "type": "date", | |
| 4166 | + "primaryKey": false, | |
| 4167 | + "notNull": true | |
| 4168 | + }, | |
| 4169 | + "sample_size": { | |
| 4170 | + "name": "sample_size", | |
| 4171 | + "type": "integer", | |
| 4172 | + "primaryKey": false, | |
| 4173 | + "notNull": false | |
| 4174 | + }, | |
| 4175 | + "dedupe_key": { | |
| 4176 | + "name": "dedupe_key", | |
| 4177 | + "type": "text", | |
| 4178 | + "primaryKey": false, | |
| 4179 | + "notNull": true | |
| 4180 | + }, | |
| 4181 | + "created_at": { | |
| 4182 | + "name": "created_at", | |
| 4183 | + "type": "timestamp with time zone", | |
| 4184 | + "primaryKey": false, | |
| 4185 | + "notNull": true, | |
| 4186 | + "default": "now()" | |
| 4187 | + } | |
| 4188 | + }, | |
| 4189 | + "indexes": { | |
| 4190 | + "price_observations_dedupe_uq": { | |
| 4191 | + "name": "price_observations_dedupe_uq", | |
| 4192 | + "columns": [ | |
| 4193 | + { | |
| 4194 | + "expression": "dedupe_key", | |
| 4195 | + "isExpression": false, | |
| 4196 | + "asc": true, | |
| 4197 | + "nulls": "last" | |
| 4198 | + } | |
| 4199 | + ], | |
| 4200 | + "isUnique": true, | |
| 4201 | + "concurrently": false, | |
| 4202 | + "method": "btree", | |
| 4203 | + "with": {} | |
| 4204 | + }, | |
| 4205 | + "price_observations_asset_date_idx": { | |
| 4206 | + "name": "price_observations_asset_date_idx", | |
| 4207 | + "columns": [ | |
| 4208 | + { | |
| 4209 | + "expression": "asset_id", | |
| 4210 | + "isExpression": false, | |
| 4211 | + "asc": true, | |
| 4212 | + "nulls": "last" | |
| 4213 | + }, | |
| 4214 | + { | |
| 4215 | + "expression": "observation_date", | |
| 4216 | + "isExpression": false, | |
| 4217 | + "asc": true, | |
| 4218 | + "nulls": "last" | |
| 4219 | + } | |
| 4220 | + ], | |
| 4221 | + "isUnique": false, | |
| 4222 | + "concurrently": false, | |
| 4223 | + "method": "btree", | |
| 4224 | + "with": {} | |
| 4225 | + } | |
| 4226 | + }, | |
| 4227 | + "foreignKeys": {}, | |
| 4228 | + "compositePrimaryKeys": {}, | |
| 4229 | + "uniqueConstraints": {}, | |
| 4230 | + "policies": {}, | |
| 4231 | + "checkConstraints": {}, | |
| 4232 | + "isRLSEnabled": false | |
| 4233 | + }, | |
| 4234 | + "public.sales": { | |
| 4235 | + "name": "sales", | |
| 4236 | + "schema": "", | |
| 4237 | + "columns": { | |
| 4238 | + "id": { | |
| 4239 | + "name": "id", | |
| 4240 | + "type": "text", | |
| 4241 | + "primaryKey": true, | |
| 4242 | + "notNull": true | |
| 4243 | + }, | |
| 4244 | + "asset_id": { | |
| 4245 | + "name": "asset_id", | |
| 4246 | + "type": "text", | |
| 4247 | + "primaryKey": false, | |
| 4248 | + "notNull": true | |
| 4249 | + }, | |
| 4250 | + "variant_id": { | |
| 4251 | + "name": "variant_id", | |
| 4252 | + "type": "text", | |
| 4253 | + "primaryKey": false, | |
| 4254 | + "notNull": false | |
| 4255 | + }, | |
| 4256 | + "source_id": { | |
| 4257 | + "name": "source_id", | |
| 4258 | + "type": "text", | |
| 4259 | + "primaryKey": false, | |
| 4260 | + "notNull": true | |
| 4261 | + }, | |
| 4262 | + "connector_id": { | |
| 4263 | + "name": "connector_id", | |
| 4264 | + "type": "text", | |
| 4265 | + "primaryKey": false, | |
| 4266 | + "notNull": true | |
| 4267 | + }, | |
| 4268 | + "raw_record_id": { | |
| 4269 | + "name": "raw_record_id", | |
| 4270 | + "type": "text", | |
| 4271 | + "primaryKey": false, | |
| 4272 | + "notNull": false | |
| 4273 | + }, | |
| 4274 | + "normalized_record_id": { | |
| 4275 | + "name": "normalized_record_id", | |
| 4276 | + "type": "text", | |
| 4277 | + "primaryKey": false, | |
| 4278 | + "notNull": false | |
| 4279 | + }, | |
| 4280 | + "source_url": { | |
| 4281 | + "name": "source_url", | |
| 4282 | + "type": "text", | |
| 4283 | + "primaryKey": false, | |
| 4284 | + "notNull": true | |
| 4285 | + }, | |
| 4286 | + "external_id": { | |
| 4287 | + "name": "external_id", | |
| 4288 | + "type": "text", | |
| 4289 | + "primaryKey": false, | |
| 4290 | + "notNull": false | |
| 4291 | + }, | |
| 4292 | + "sale_type": { | |
| 4293 | + "name": "sale_type", | |
| 4294 | + "type": "text", | |
| 4295 | + "primaryKey": false, | |
| 4296 | + "notNull": true, | |
| 4297 | + "default": "'unknown'" | |
| 4298 | + }, | |
| 4299 | + "sale_date": { | |
| 4300 | + "name": "sale_date", | |
| 4301 | + "type": "timestamp with time zone", | |
| 4302 | + "primaryKey": false, | |
| 4303 | + "notNull": true | |
| 4304 | + }, | |
| 4305 | + "price": { | |
| 4306 | + "name": "price", | |
| 4307 | + "type": "numeric(18, 4)", | |
| 4308 | + "primaryKey": false, | |
| 4309 | + "notNull": true | |
| 4310 | + }, | |
| 4311 | + "currency": { | |
| 4312 | + "name": "currency", | |
| 4313 | + "type": "text", | |
| 4314 | + "primaryKey": false, | |
| 4315 | + "notNull": true | |
| 4316 | + }, | |
| 4317 | + "price_usd": { | |
| 4318 | + "name": "price_usd", | |
| 4319 | + "type": "numeric(18, 4)", | |
| 4320 | + "primaryKey": false, | |
| 4321 | + "notNull": true | |
| 4322 | + }, | |
| 4323 | + "fx_rate": { | |
| 4324 | + "name": "fx_rate", | |
| 4325 | + "type": "real", | |
| 4326 | + "primaryKey": false, | |
| 4327 | + "notNull": false | |
| 4328 | + }, | |
| 4329 | + "fx_date": { | |
| 4330 | + "name": "fx_date", | |
| 4331 | + "type": "date", | |
| 4332 | + "primaryKey": false, | |
| 4333 | + "notNull": false | |
| 4334 | + }, | |
| 4335 | + "buyer_premium_included": { | |
| 4336 | + "name": "buyer_premium_included", | |
| 4337 | + "type": "boolean", | |
| 4338 | + "primaryKey": false, | |
| 4339 | + "notNull": false | |
| 4340 | + }, | |
| 4341 | + "quantity": { | |
| 4342 | + "name": "quantity", | |
| 4343 | + "type": "integer", | |
| 4344 | + "primaryKey": false, | |
| 4345 | + "notNull": true, | |
| 4346 | + "default": 1 | |
| 4347 | + }, | |
| 4348 | + "is_bundle": { | |
| 4349 | + "name": "is_bundle", | |
| 4350 | + "type": "boolean", | |
| 4351 | + "primaryKey": false, | |
| 4352 | + "notNull": true, | |
| 4353 | + "default": false | |
| 4354 | + }, | |
| 4355 | + "condition": { | |
| 4356 | + "name": "condition", | |
| 4357 | + "type": "text", | |
| 4358 | + "primaryKey": false, | |
| 4359 | + "notNull": false | |
| 4360 | + }, | |
| 4361 | + "grader": { | |
| 4362 | + "name": "grader", | |
| 4363 | + "type": "text", | |
| 4364 | + "primaryKey": false, | |
| 4365 | + "notNull": false | |
| 4366 | + }, | |
| 4367 | + "grade": { | |
| 4368 | + "name": "grade", | |
| 4369 | + "type": "text", | |
| 4370 | + "primaryKey": false, | |
| 4371 | + "notNull": false | |
| 4372 | + }, | |
| 4373 | + "certification_number": { | |
| 4374 | + "name": "certification_number", | |
| 4375 | + "type": "text", | |
| 4376 | + "primaryKey": false, | |
| 4377 | + "notNull": false | |
| 4378 | + }, | |
| 4379 | + "location": { | |
| 4380 | + "name": "location", | |
| 4381 | + "type": "text", | |
| 4382 | + "primaryKey": false, | |
| 4383 | + "notNull": false | |
| 4384 | + }, | |
| 4385 | + "auction_house": { | |
| 4386 | + "name": "auction_house", | |
| 4387 | + "type": "text", | |
| 4388 | + "primaryKey": false, | |
| 4389 | + "notNull": false | |
| 4390 | + }, | |
| 4391 | + "lot_number": { | |
| 4392 | + "name": "lot_number", | |
| 4393 | + "type": "text", | |
| 4394 | + "primaryKey": false, | |
| 4395 | + "notNull": false | |
| 4396 | + }, | |
| 4397 | + "image_urls": { | |
| 4398 | + "name": "image_urls", | |
| 4399 | + "type": "jsonb", | |
| 4400 | + "primaryKey": false, | |
| 4401 | + "notNull": true, | |
| 4402 | + "default": "'[]'::jsonb" | |
| 4403 | + }, | |
| 4404 | + "raw_title": { | |
| 4405 | + "name": "raw_title", | |
| 4406 | + "type": "text", | |
| 4407 | + "primaryKey": false, | |
| 4408 | + "notNull": true | |
| 4409 | + }, | |
| 4410 | + "confidence": { | |
| 4411 | + "name": "confidence", | |
| 4412 | + "type": "numeric(8, 6)", | |
| 4413 | + "primaryKey": false, | |
| 4414 | + "notNull": true, | |
| 4415 | + "default": 0.8 | |
| 4416 | + }, | |
| 4417 | + "data_quality": { | |
| 4418 | + "name": "data_quality", | |
| 4419 | + "type": "real", | |
| 4420 | + "primaryKey": false, | |
| 4421 | + "notNull": true, | |
| 4422 | + "default": 0 | |
| 4423 | + }, | |
| 4424 | + "status": { | |
| 4425 | + "name": "status", | |
| 4426 | + "type": "text", | |
| 4427 | + "primaryKey": false, | |
| 4428 | + "notNull": true, | |
| 4429 | + "default": "'valid'" | |
| 4430 | + }, | |
| 4431 | + "flags": { | |
| 4432 | + "name": "flags", | |
| 4433 | + "type": "text[]", | |
| 4434 | + "primaryKey": false, | |
| 4435 | + "notNull": true, | |
| 4436 | + "default": "'{}'::text[]" | |
| 4437 | + }, | |
| 4438 | + "dedupe_key": { | |
| 4439 | + "name": "dedupe_key", | |
| 4440 | + "type": "text", | |
| 4441 | + "primaryKey": false, | |
| 4442 | + "notNull": true | |
| 4443 | + }, | |
| 4444 | + "created_at": { | |
| 4445 | + "name": "created_at", | |
| 4446 | + "type": "timestamp with time zone", | |
| 4447 | + "primaryKey": false, | |
| 4448 | + "notNull": true, | |
| 4449 | + "default": "now()" | |
| 4450 | + } | |
| 4451 | + }, | |
| 4452 | + "indexes": { | |
| 4453 | + "sales_dedupe_uq": { | |
| 4454 | + "name": "sales_dedupe_uq", | |
| 4455 | + "columns": [ | |
| 4456 | + { | |
| 4457 | + "expression": "dedupe_key", | |
| 4458 | + "isExpression": false, | |
| 4459 | + "asc": true, | |
| 4460 | + "nulls": "last" | |
| 4461 | + } | |
| 4462 | + ], | |
| 4463 | + "isUnique": true, | |
| 4464 | + "concurrently": false, | |
| 4465 | + "method": "btree", | |
| 4466 | + "with": {} | |
| 4467 | + }, | |
| 4468 | + "sales_asset_date_idx": { | |
| 4469 | + "name": "sales_asset_date_idx", | |
| 4470 | + "columns": [ | |
| 4471 | + { | |
| 4472 | + "expression": "asset_id", | |
| 4473 | + "isExpression": false, | |
| 4474 | + "asc": true, | |
| 4475 | + "nulls": "last" | |
| 4476 | + }, | |
| 4477 | + { | |
| 4478 | + "expression": "sale_date", | |
| 4479 | + "isExpression": false, | |
| 4480 | + "asc": true, | |
| 4481 | + "nulls": "last" | |
| 4482 | + } | |
| 4483 | + ], | |
| 4484 | + "isUnique": false, | |
| 4485 | + "concurrently": false, | |
| 4486 | + "method": "btree", | |
| 4487 | + "with": {} | |
| 4488 | + }, | |
| 4489 | + "sales_variant_date_idx": { | |
| 4490 | + "name": "sales_variant_date_idx", | |
| 4491 | + "columns": [ | |
| 4492 | + { | |
| 4493 | + "expression": "variant_id", | |
| 4494 | + "isExpression": false, | |
| 4495 | + "asc": true, | |
| 4496 | + "nulls": "last" | |
| 4497 | + }, | |
| 4498 | + { | |
| 4499 | + "expression": "sale_date", | |
| 4500 | + "isExpression": false, | |
| 4501 | + "asc": true, | |
| 4502 | + "nulls": "last" | |
| 4503 | + } | |
| 4504 | + ], | |
| 4505 | + "isUnique": false, | |
| 4506 | + "concurrently": false, | |
| 4507 | + "method": "btree", | |
| 4508 | + "with": {} | |
| 4509 | + }, | |
| 4510 | + "sales_source_idx": { | |
| 4511 | + "name": "sales_source_idx", | |
| 4512 | + "columns": [ | |
| 4513 | + { | |
| 4514 | + "expression": "source_id", | |
| 4515 | + "isExpression": false, | |
| 4516 | + "asc": true, | |
| 4517 | + "nulls": "last" | |
| 4518 | + }, | |
| 4519 | + { | |
| 4520 | + "expression": "sale_date", | |
| 4521 | + "isExpression": false, | |
| 4522 | + "asc": true, | |
| 4523 | + "nulls": "last" | |
| 4524 | + } | |
| 4525 | + ], | |
| 4526 | + "isUnique": false, | |
| 4527 | + "concurrently": false, | |
| 4528 | + "method": "btree", | |
| 4529 | + "with": {} | |
| 4530 | + }, | |
| 4531 | + "sales_date_idx": { | |
| 4532 | + "name": "sales_date_idx", | |
| 4533 | + "columns": [ | |
| 4534 | + { | |
| 4535 | + "expression": "sale_date", | |
| 4536 | + "isExpression": false, | |
| 4537 | + "asc": true, | |
| 4538 | + "nulls": "last" | |
| 4539 | + } | |
| 4540 | + ], | |
| 4541 | + "isUnique": false, | |
| 4542 | + "concurrently": false, | |
| 4543 | + "method": "btree", | |
| 4544 | + "with": {} | |
| 4545 | + }, | |
| 4546 | + "sales_price_idx": { | |
| 4547 | + "name": "sales_price_idx", | |
| 4548 | + "columns": [ | |
| 4549 | + { | |
| 4550 | + "expression": "price_usd", | |
| 4551 | + "isExpression": false, | |
| 4552 | + "asc": true, | |
| 4553 | + "nulls": "last" | |
| 4554 | + } | |
| 4555 | + ], | |
| 4556 | + "isUnique": false, | |
| 4557 | + "concurrently": false, | |
| 4558 | + "method": "btree", | |
| 4559 | + "with": {} | |
| 4560 | + } | |
| 4561 | + }, | |
| 4562 | + "foreignKeys": {}, | |
| 4563 | + "compositePrimaryKeys": {}, | |
| 4564 | + "uniqueConstraints": {}, | |
| 4565 | + "policies": {}, | |
| 4566 | + "checkConstraints": {}, | |
| 4567 | + "isRLSEnabled": false | |
| 4568 | + }, | |
| 4569 | + "public.benchmarks": { | |
| 4570 | + "name": "benchmarks", | |
| 4571 | + "schema": "", | |
| 4572 | + "columns": { | |
| 4573 | + "ticker": { | |
| 4574 | + "name": "ticker", | |
| 4575 | + "type": "text", | |
| 4576 | + "primaryKey": false, | |
| 4577 | + "notNull": true | |
| 4578 | + }, | |
| 4579 | + "date": { | |
| 4580 | + "name": "date", | |
| 4581 | + "type": "date", | |
| 4582 | + "primaryKey": false, | |
| 4583 | + "notNull": true | |
| 4584 | + }, | |
| 4585 | + "value": { | |
| 4586 | + "name": "value", | |
| 4587 | + "type": "real", | |
| 4588 | + "primaryKey": false, | |
| 4589 | + "notNull": true | |
| 4590 | + }, | |
| 4591 | + "source": { | |
| 4592 | + "name": "source", | |
| 4593 | + "type": "text", | |
| 4594 | + "primaryKey": false, | |
| 4595 | + "notNull": true | |
| 4596 | + } | |
| 4597 | + }, | |
| 4598 | + "indexes": {}, | |
| 4599 | + "foreignKeys": {}, | |
| 4600 | + "compositePrimaryKeys": { | |
| 4601 | + "benchmarks_ticker_date_pk": { | |
| 4602 | + "name": "benchmarks_ticker_date_pk", | |
| 4603 | + "columns": [ | |
| 4604 | + "ticker", | |
| 4605 | + "date" | |
| 4606 | + ] | |
| 4607 | + } | |
| 4608 | + }, | |
| 4609 | + "uniqueConstraints": {}, | |
| 4610 | + "policies": {}, | |
| 4611 | + "checkConstraints": {}, | |
| 4612 | + "isRLSEnabled": false | |
| 4613 | + }, | |
| 4614 | + "public.category_snapshots": { | |
| 4615 | + "name": "category_snapshots", | |
| 4616 | + "schema": "", | |
| 4617 | + "columns": { | |
| 4618 | + "category_slug": { | |
| 4619 | + "name": "category_slug", | |
| 4620 | + "type": "text", | |
| 4621 | + "primaryKey": false, | |
| 4622 | + "notNull": true | |
| 4623 | + }, | |
| 4624 | + "date": { | |
| 4625 | + "name": "date", | |
| 4626 | + "type": "date", | |
| 4627 | + "primaryKey": false, | |
| 4628 | + "notNull": true | |
| 4629 | + }, | |
| 4630 | + "index_value": { | |
| 4631 | + "name": "index_value", | |
| 4632 | + "type": "real", | |
| 4633 | + "primaryKey": false, | |
| 4634 | + "notNull": false | |
| 4635 | + }, | |
| 4636 | + "tracked_assets": { | |
| 4637 | + "name": "tracked_assets", | |
| 4638 | + "type": "integer", | |
| 4639 | + "primaryKey": false, | |
| 4640 | + "notNull": true, | |
| 4641 | + "default": 0 | |
| 4642 | + }, | |
| 4643 | + "assets_with_valuation": { | |
| 4644 | + "name": "assets_with_valuation", | |
| 4645 | + "type": "integer", | |
| 4646 | + "primaryKey": false, | |
| 4647 | + "notNull": true, | |
| 4648 | + "default": 0 | |
| 4649 | + }, | |
| 4650 | + "sales": { | |
| 4651 | + "name": "sales", | |
| 4652 | + "type": "integer", | |
| 4653 | + "primaryKey": false, | |
| 4654 | + "notNull": true, | |
| 4655 | + "default": 0 | |
| 4656 | + }, | |
| 4657 | + "volume_usd": { | |
| 4658 | + "name": "volume_usd", | |
| 4659 | + "type": "numeric(18, 4)", | |
| 4660 | + "primaryKey": false, | |
| 4661 | + "notNull": false | |
| 4662 | + }, | |
| 4663 | + "median_sale_usd": { | |
| 4664 | + "name": "median_sale_usd", | |
| 4665 | + "type": "numeric(18, 4)", | |
| 4666 | + "primaryKey": false, | |
| 4667 | + "notNull": false | |
| 4668 | + }, | |
| 4669 | + "active_listings": { | |
| 4670 | + "name": "active_listings", | |
| 4671 | + "type": "integer", | |
| 4672 | + "primaryKey": false, | |
| 4673 | + "notNull": true, | |
| 4674 | + "default": 0 | |
| 4675 | + }, | |
| 4676 | + "market_cap_est_usd": { | |
| 4677 | + "name": "market_cap_est_usd", | |
| 4678 | + "type": "numeric(18, 4)", | |
| 4679 | + "primaryKey": false, | |
| 4680 | + "notNull": false | |
| 4681 | + }, | |
| 4682 | + "liquidity_score": { | |
| 4683 | + "name": "liquidity_score", | |
| 4684 | + "type": "real", | |
| 4685 | + "primaryKey": false, | |
| 4686 | + "notNull": false | |
| 4687 | + }, | |
| 4688 | + "change_1d": { | |
| 4689 | + "name": "change_1d", | |
| 4690 | + "type": "numeric(8, 6)", | |
| 4691 | + "primaryKey": false, | |
| 4692 | + "notNull": false | |
| 4693 | + }, | |
| 4694 | + "change_7d": { | |
| 4695 | + "name": "change_7d", | |
| 4696 | + "type": "numeric(8, 6)", | |
| 4697 | + "primaryKey": false, | |
| 4698 | + "notNull": false | |
| 4699 | + }, | |
| 4700 | + "change_30d": { | |
| 4701 | + "name": "change_30d", | |
| 4702 | + "type": "numeric(8, 6)", | |
| 4703 | + "primaryKey": false, | |
| 4704 | + "notNull": false | |
| 4705 | + }, | |
| 4706 | + "change_1y": { | |
| 4707 | + "name": "change_1y", | |
| 4708 | + "type": "numeric(8, 6)", | |
| 4709 | + "primaryKey": false, | |
| 4710 | + "notNull": false | |
| 4711 | + } | |
| 4712 | + }, | |
| 4713 | + "indexes": {}, | |
| 4714 | + "foreignKeys": {}, | |
| 4715 | + "compositePrimaryKeys": { | |
| 4716 | + "category_snapshots_category_slug_date_pk": { | |
| 4717 | + "name": "category_snapshots_category_slug_date_pk", | |
| 4718 | + "columns": [ | |
| 4719 | + "category_slug", | |
| 4720 | + "date" | |
| 4721 | + ] | |
| 4722 | + } | |
| 4723 | + }, | |
| 4724 | + "uniqueConstraints": {}, | |
| 4725 | + "policies": {}, | |
| 4726 | + "checkConstraints": {}, | |
| 4727 | + "isRLSEnabled": false | |
| 4728 | + }, | |
| 4729 | + "public.correlations": { | |
| 4730 | + "name": "correlations", | |
| 4731 | + "schema": "", | |
| 4732 | + "columns": { | |
| 4733 | + "a": { | |
| 4734 | + "name": "a", | |
| 4735 | + "type": "text", | |
| 4736 | + "primaryKey": false, | |
| 4737 | + "notNull": true | |
| 4738 | + }, | |
| 4739 | + "b": { | |
| 4740 | + "name": "b", | |
| 4741 | + "type": "text", | |
| 4742 | + "primaryKey": false, | |
| 4743 | + "notNull": true | |
| 4744 | + }, | |
| 4745 | + "window_days": { | |
| 4746 | + "name": "window_days", | |
| 4747 | + "type": "integer", | |
| 4748 | + "primaryKey": false, | |
| 4749 | + "notNull": true | |
| 4750 | + }, | |
| 4751 | + "coefficient": { | |
| 4752 | + "name": "coefficient", | |
| 4753 | + "type": "real", | |
| 4754 | + "primaryKey": false, | |
| 4755 | + "notNull": true | |
| 4756 | + }, | |
| 4757 | + "observations": { | |
| 4758 | + "name": "observations", | |
| 4759 | + "type": "integer", | |
| 4760 | + "primaryKey": false, | |
| 4761 | + "notNull": true | |
| 4762 | + }, | |
| 4763 | + "computed_at": { | |
| 4764 | + "name": "computed_at", | |
| 4765 | + "type": "timestamp with time zone", | |
| 4766 | + "primaryKey": false, | |
| 4767 | + "notNull": true | |
| 4768 | + } | |
| 4769 | + }, | |
| 4770 | + "indexes": {}, | |
| 4771 | + "foreignKeys": {}, | |
| 4772 | + "compositePrimaryKeys": { | |
| 4773 | + "correlations_a_b_window_days_pk": { | |
| 4774 | + "name": "correlations_a_b_window_days_pk", | |
| 4775 | + "columns": [ | |
| 4776 | + "a", | |
| 4777 | + "b", | |
| 4778 | + "window_days" | |
| 4779 | + ] | |
| 4780 | + } | |
| 4781 | + }, | |
| 4782 | + "uniqueConstraints": {}, | |
| 4783 | + "policies": {}, | |
| 4784 | + "checkConstraints": {}, | |
| 4785 | + "isRLSEnabled": false | |
| 4786 | + }, | |
| 4787 | + "public.index_constituents": { | |
| 4788 | + "name": "index_constituents", | |
| 4789 | + "schema": "", | |
| 4790 | + "columns": { | |
| 4791 | + "index_id": { | |
| 4792 | + "name": "index_id", | |
| 4793 | + "type": "text", | |
| 4794 | + "primaryKey": false, | |
| 4795 | + "notNull": true | |
| 4796 | + }, | |
| 4797 | + "asset_id": { | |
| 4798 | + "name": "asset_id", | |
| 4799 | + "type": "text", | |
| 4800 | + "primaryKey": false, | |
| 4801 | + "notNull": true | |
| 4802 | + }, | |
| 4803 | + "variant_id": { | |
| 4804 | + "name": "variant_id", | |
| 4805 | + "type": "text", | |
| 4806 | + "primaryKey": false, | |
| 4807 | + "notNull": true, | |
| 4808 | + "default": "''" | |
| 4809 | + }, | |
| 4810 | + "weight": { | |
| 4811 | + "name": "weight", | |
| 4812 | + "type": "real", | |
| 4813 | + "primaryKey": false, | |
| 4814 | + "notNull": true, | |
| 4815 | + "default": 1 | |
| 4816 | + }, | |
| 4817 | + "added_at": { | |
| 4818 | + "name": "added_at", | |
| 4819 | + "type": "date", | |
| 4820 | + "primaryKey": false, | |
| 4821 | + "notNull": true | |
| 4822 | + }, | |
| 4823 | + "removed_at": { | |
| 4824 | + "name": "removed_at", | |
| 4825 | + "type": "date", | |
| 4826 | + "primaryKey": false, | |
| 4827 | + "notNull": false | |
| 4828 | + }, | |
| 4829 | + "reason": { | |
| 4830 | + "name": "reason", | |
| 4831 | + "type": "text", | |
| 4832 | + "primaryKey": false, | |
| 4833 | + "notNull": false | |
| 4834 | + } | |
| 4835 | + }, | |
| 4836 | + "indexes": { | |
| 4837 | + "index_constituents_asset_idx": { | |
| 4838 | + "name": "index_constituents_asset_idx", | |
| 4839 | + "columns": [ | |
| 4840 | + { | |
| 4841 | + "expression": "asset_id", | |
| 4842 | + "isExpression": false, | |
| 4843 | + "asc": true, | |
| 4844 | + "nulls": "last" | |
| 4845 | + } | |
| 4846 | + ], | |
| 4847 | + "isUnique": false, | |
| 4848 | + "concurrently": false, | |
| 4849 | + "method": "btree", | |
| 4850 | + "with": {} | |
| 4851 | + } | |
| 4852 | + }, | |
| 4853 | + "foreignKeys": {}, | |
| 4854 | + "compositePrimaryKeys": { | |
| 4855 | + "index_constituents_index_id_asset_id_variant_id_added_at_pk": { | |
| 4856 | + "name": "index_constituents_index_id_asset_id_variant_id_added_at_pk", | |
| 4857 | + "columns": [ | |
| 4858 | + "index_id", | |
| 4859 | + "asset_id", | |
| 4860 | + "variant_id", | |
| 4861 | + "added_at" | |
| 4862 | + ] | |
| 4863 | + } | |
| 4864 | + }, | |
| 4865 | + "uniqueConstraints": {}, | |
| 4866 | + "policies": {}, | |
| 4867 | + "checkConstraints": {}, | |
| 4868 | + "isRLSEnabled": false | |
| 4869 | + }, | |
| 4870 | + "public.index_values": { | |
| 4871 | + "name": "index_values", | |
| 4872 | + "schema": "", | |
| 4873 | + "columns": { | |
| 4874 | + "index_id": { | |
| 4875 | + "name": "index_id", | |
| 4876 | + "type": "text", | |
| 4877 | + "primaryKey": false, | |
| 4878 | + "notNull": true | |
| 4879 | + }, | |
| 4880 | + "date": { | |
| 4881 | + "name": "date", | |
| 4882 | + "type": "date", | |
| 4883 | + "primaryKey": false, | |
| 4884 | + "notNull": true | |
| 4885 | + }, | |
| 4886 | + "value": { | |
| 4887 | + "name": "value", | |
| 4888 | + "type": "real", | |
| 4889 | + "primaryKey": false, | |
| 4890 | + "notNull": true | |
| 4891 | + }, | |
| 4892 | + "constituents_count": { | |
| 4893 | + "name": "constituents_count", | |
| 4894 | + "type": "integer", | |
| 4895 | + "primaryKey": false, | |
| 4896 | + "notNull": true, | |
| 4897 | + "default": 0 | |
| 4898 | + }, | |
| 4899 | + "transactions": { | |
| 4900 | + "name": "transactions", | |
| 4901 | + "type": "integer", | |
| 4902 | + "primaryKey": false, | |
| 4903 | + "notNull": true, | |
| 4904 | + "default": 0 | |
| 4905 | + }, | |
| 4906 | + "volume_usd": { | |
| 4907 | + "name": "volume_usd", | |
| 4908 | + "type": "numeric(18, 4)", | |
| 4909 | + "primaryKey": false, | |
| 4910 | + "notNull": false | |
| 4911 | + }, | |
| 4912 | + "median_sale_usd": { | |
| 4913 | + "name": "median_sale_usd", | |
| 4914 | + "type": "numeric(18, 4)", | |
| 4915 | + "primaryKey": false, | |
| 4916 | + "notNull": false | |
| 4917 | + }, | |
| 4918 | + "avg_sale_usd": { | |
| 4919 | + "name": "avg_sale_usd", | |
| 4920 | + "type": "numeric(18, 4)", | |
| 4921 | + "primaryKey": false, | |
| 4922 | + "notNull": false | |
| 4923 | + }, | |
| 4924 | + "market_cap_est_usd": { | |
| 4925 | + "name": "market_cap_est_usd", | |
| 4926 | + "type": "numeric(18, 4)", | |
| 4927 | + "primaryKey": false, | |
| 4928 | + "notNull": false | |
| 4929 | + }, | |
| 4930 | + "market_cap_confidence": { | |
| 4931 | + "name": "market_cap_confidence", | |
| 4932 | + "type": "text", | |
| 4933 | + "primaryKey": false, | |
| 4934 | + "notNull": false | |
| 4935 | + }, | |
| 4936 | + "liquidity_score": { | |
| 4937 | + "name": "liquidity_score", | |
| 4938 | + "type": "real", | |
| 4939 | + "primaryKey": false, | |
| 4940 | + "notNull": false | |
| 4941 | + }, | |
| 4942 | + "momentum": { | |
| 4943 | + "name": "momentum", | |
| 4944 | + "type": "real", | |
| 4945 | + "primaryKey": false, | |
| 4946 | + "notNull": false | |
| 4947 | + }, | |
| 4948 | + "breadth": { | |
| 4949 | + "name": "breadth", | |
| 4950 | + "type": "integer", | |
| 4951 | + "primaryKey": false, | |
| 4952 | + "notNull": false | |
| 4953 | + }, | |
| 4954 | + "tracked_assets": { | |
| 4955 | + "name": "tracked_assets", | |
| 4956 | + "type": "integer", | |
| 4957 | + "primaryKey": false, | |
| 4958 | + "notNull": false | |
| 4959 | + }, | |
| 4960 | + "coverage": { | |
| 4961 | + "name": "coverage", | |
| 4962 | + "type": "real", | |
| 4963 | + "primaryKey": false, | |
| 4964 | + "notNull": false | |
| 4965 | + } | |
| 4966 | + }, | |
| 4967 | + "indexes": {}, | |
| 4968 | + "foreignKeys": {}, | |
| 4969 | + "compositePrimaryKeys": { | |
| 4970 | + "index_values_index_id_date_pk": { | |
| 4971 | + "name": "index_values_index_id_date_pk", | |
| 4972 | + "columns": [ | |
| 4973 | + "index_id", | |
| 4974 | + "date" | |
| 4975 | + ] | |
| 4976 | + } | |
| 4977 | + }, | |
| 4978 | + "uniqueConstraints": {}, | |
| 4979 | + "policies": {}, | |
| 4980 | + "checkConstraints": {}, | |
| 4981 | + "isRLSEnabled": false | |
| 4982 | + }, | |
| 4983 | + "public.indices": { | |
| 4984 | + "name": "indices", | |
| 4985 | + "schema": "", | |
| 4986 | + "columns": { | |
| 4987 | + "id": { | |
| 4988 | + "name": "id", | |
| 4989 | + "type": "text", | |
| 4990 | + "primaryKey": true, | |
| 4991 | + "notNull": true | |
| 4992 | + }, | |
| 4993 | + "ticker": { | |
| 4994 | + "name": "ticker", | |
| 4995 | + "type": "text", | |
| 4996 | + "primaryKey": false, | |
| 4997 | + "notNull": true | |
| 4998 | + }, | |
| 4999 | + "name": { | |
| 5000 | + "name": "name", | |
| 5001 | + "type": "text", | |
| 5002 | + "primaryKey": false, | |
| 5003 | + "notNull": true | |
| 5004 | + }, | |
| 5005 | + "description": { | |
| 5006 | + "name": "description", | |
| 5007 | + "type": "text", | |
| 5008 | + "primaryKey": false, | |
| 5009 | + "notNull": false | |
| 5010 | + }, | |
| 5011 | + "category_slugs": { | |
| 5012 | + "name": "category_slugs", | |
| 5013 | + "type": "text[]", | |
| 5014 | + "primaryKey": false, | |
| 5015 | + "notNull": true, | |
| 5016 | + "default": "'{}'::text[]" | |
| 5017 | + }, | |
| 5018 | + "family_slugs": { | |
| 5019 | + "name": "family_slugs", | |
| 5020 | + "type": "text[]", | |
| 5021 | + "primaryKey": false, | |
| 5022 | + "notNull": true, | |
| 5023 | + "default": "'{}'::text[]" | |
| 5024 | + }, | |
| 5025 | + "parent_ticker": { | |
| 5026 | + "name": "parent_ticker", | |
| 5027 | + "type": "text", | |
| 5028 | + "primaryKey": false, | |
| 5029 | + "notNull": false | |
| 5030 | + }, | |
| 5031 | + "methodology": { | |
| 5032 | + "name": "methodology", | |
| 5033 | + "type": "text", | |
| 5034 | + "primaryKey": false, | |
| 5035 | + "notNull": true, | |
| 5036 | + "default": "'chain_linked_equal_weight_v1'" | |
| 5037 | + }, | |
| 5038 | + "weighting": { | |
| 5039 | + "name": "weighting", | |
| 5040 | + "type": "text", | |
| 5041 | + "primaryKey": false, | |
| 5042 | + "notNull": true, | |
| 5043 | + "default": "'equal'" | |
| 5044 | + }, | |
| 5045 | + "base_date": { | |
| 5046 | + "name": "base_date", | |
| 5047 | + "type": "date", | |
| 5048 | + "primaryKey": false, | |
| 5049 | + "notNull": true | |
| 5050 | + }, | |
| 5051 | + "base_value": { | |
| 5052 | + "name": "base_value", | |
| 5053 | + "type": "real", | |
| 5054 | + "primaryKey": false, | |
| 5055 | + "notNull": true, | |
| 5056 | + "default": 1000 | |
| 5057 | + }, | |
| 5058 | + "min_constituents": { | |
| 5059 | + "name": "min_constituents", | |
| 5060 | + "type": "integer", | |
| 5061 | + "primaryKey": false, | |
| 5062 | + "notNull": true, | |
| 5063 | + "default": 10 | |
| 5064 | + }, | |
| 5065 | + "active": { | |
| 5066 | + "name": "active", | |
| 5067 | + "type": "boolean", | |
| 5068 | + "primaryKey": false, | |
| 5069 | + "notNull": true, | |
| 5070 | + "default": true | |
| 5071 | + }, | |
| 5072 | + "is_flagship": { | |
| 5073 | + "name": "is_flagship", | |
| 5074 | + "type": "boolean", | |
| 5075 | + "primaryKey": false, | |
| 5076 | + "notNull": true, | |
| 5077 | + "default": false | |
| 5078 | + }, | |
| 5079 | + "color": { | |
| 5080 | + "name": "color", | |
| 5081 | + "type": "text", | |
| 5082 | + "primaryKey": false, | |
| 5083 | + "notNull": false | |
| 5084 | + }, | |
| 5085 | + "created_at": { | |
| 5086 | + "name": "created_at", | |
| 5087 | + "type": "timestamp with time zone", | |
| 5088 | + "primaryKey": false, | |
| 5089 | + "notNull": true, | |
| 5090 | + "default": "now()" | |
| 5091 | + } | |
| 5092 | + }, | |
| 5093 | + "indexes": {}, | |
| 5094 | + "foreignKeys": {}, | |
| 5095 | + "compositePrimaryKeys": {}, | |
| 5096 | + "uniqueConstraints": { | |
| 5097 | + "indices_ticker_unique": { | |
| 5098 | + "name": "indices_ticker_unique", | |
| 5099 | + "nullsNotDistinct": false, | |
| 5100 | + "columns": [ | |
| 5101 | + "ticker" | |
| 5102 | + ] | |
| 5103 | + } | |
| 5104 | + }, | |
| 5105 | + "policies": {}, | |
| 5106 | + "checkConstraints": {}, | |
| 5107 | + "isRLSEnabled": false | |
| 5108 | + }, | |
| 5109 | + "public.price_snapshots": { | |
| 5110 | + "name": "price_snapshots", | |
| 5111 | + "schema": "", | |
| 5112 | + "columns": { | |
| 5113 | + "asset_id": { | |
| 5114 | + "name": "asset_id", | |
| 5115 | + "type": "text", | |
| 5116 | + "primaryKey": false, | |
| 5117 | + "notNull": true | |
| 5118 | + }, | |
| 5119 | + "variant_id": { | |
| 5120 | + "name": "variant_id", | |
| 5121 | + "type": "text", | |
| 5122 | + "primaryKey": false, | |
| 5123 | + "notNull": true, | |
| 5124 | + "default": "''" | |
| 5125 | + }, | |
| 5126 | + "date": { | |
| 5127 | + "name": "date", | |
| 5128 | + "type": "date", | |
| 5129 | + "primaryKey": false, | |
| 5130 | + "notNull": true | |
| 5131 | + }, | |
| 5132 | + "riv_usd": { | |
| 5133 | + "name": "riv_usd", | |
| 5134 | + "type": "numeric(18, 4)", | |
| 5135 | + "primaryKey": false, | |
| 5136 | + "notNull": false | |
| 5137 | + }, | |
| 5138 | + "latest_sale_usd": { | |
| 5139 | + "name": "latest_sale_usd", | |
| 5140 | + "type": "numeric(18, 4)", | |
| 5141 | + "primaryKey": false, | |
| 5142 | + "notNull": false | |
| 5143 | + }, | |
| 5144 | + "median_usd": { | |
| 5145 | + "name": "median_usd", | |
| 5146 | + "type": "numeric(18, 4)", | |
| 5147 | + "primaryKey": false, | |
| 5148 | + "notNull": false | |
| 5149 | + }, | |
| 5150 | + "sales_count": { | |
| 5151 | + "name": "sales_count", | |
| 5152 | + "type": "integer", | |
| 5153 | + "primaryKey": false, | |
| 5154 | + "notNull": true, | |
| 5155 | + "default": 0 | |
| 5156 | + }, | |
| 5157 | + "volume_usd": { | |
| 5158 | + "name": "volume_usd", | |
| 5159 | + "type": "numeric(18, 4)", | |
| 5160 | + "primaryKey": false, | |
| 5161 | + "notNull": false | |
| 5162 | + }, | |
| 5163 | + "listings_count": { | |
| 5164 | + "name": "listings_count", | |
| 5165 | + "type": "integer", | |
| 5166 | + "primaryKey": false, | |
| 5167 | + "notNull": true, | |
| 5168 | + "default": 0 | |
| 5169 | + }, | |
| 5170 | + "min_ask_usd": { | |
| 5171 | + "name": "min_ask_usd", | |
| 5172 | + "type": "numeric(18, 4)", | |
| 5173 | + "primaryKey": false, | |
| 5174 | + "notNull": false | |
| 5175 | + }, | |
| 5176 | + "observation_usd": { | |
| 5177 | + "name": "observation_usd", | |
| 5178 | + "type": "numeric(18, 4)", | |
| 5179 | + "primaryKey": false, | |
| 5180 | + "notNull": false | |
| 5181 | + } | |
| 5182 | + }, | |
| 5183 | + "indexes": { | |
| 5184 | + "price_snapshots_date_idx": { | |
| 5185 | + "name": "price_snapshots_date_idx", | |
| 5186 | + "columns": [ | |
| 5187 | + { | |
| 5188 | + "expression": "date", | |
| 5189 | + "isExpression": false, | |
| 5190 | + "asc": true, | |
| 5191 | + "nulls": "last" | |
| 5192 | + } | |
| 5193 | + ], | |
| 5194 | + "isUnique": false, | |
| 5195 | + "concurrently": false, | |
| 5196 | + "method": "btree", | |
| 5197 | + "with": {} | |
| 5198 | + } | |
| 5199 | + }, | |
| 5200 | + "foreignKeys": {}, | |
| 5201 | + "compositePrimaryKeys": { | |
| 5202 | + "price_snapshots_asset_id_variant_id_date_pk": { | |
| 5203 | + "name": "price_snapshots_asset_id_variant_id_date_pk", | |
| 5204 | + "columns": [ | |
| 5205 | + "asset_id", | |
| 5206 | + "variant_id", | |
| 5207 | + "date" | |
| 5208 | + ] | |
| 5209 | + } | |
| 5210 | + }, | |
| 5211 | + "uniqueConstraints": {}, | |
| 5212 | + "policies": {}, | |
| 5213 | + "checkConstraints": {}, | |
| 5214 | + "isRLSEnabled": false | |
| 5215 | + }, | |
| 5216 | + "public.radar_findings": { | |
| 5217 | + "name": "radar_findings", | |
| 5218 | + "schema": "", | |
| 5219 | + "columns": { | |
| 5220 | + "id": { | |
| 5221 | + "name": "id", | |
| 5222 | + "type": "text", | |
| 5223 | + "primaryKey": true, | |
| 5224 | + "notNull": true | |
| 5225 | + }, | |
| 5226 | + "asset_id": { | |
| 5227 | + "name": "asset_id", | |
| 5228 | + "type": "text", | |
| 5229 | + "primaryKey": false, | |
| 5230 | + "notNull": true | |
| 5231 | + }, | |
| 5232 | + "kind": { | |
| 5233 | + "name": "kind", | |
| 5234 | + "type": "text", | |
| 5235 | + "primaryKey": false, | |
| 5236 | + "notNull": true | |
| 5237 | + }, | |
| 5238 | + "score": { | |
| 5239 | + "name": "score", | |
| 5240 | + "type": "real", | |
| 5241 | + "primaryKey": false, | |
| 5242 | + "notNull": true | |
| 5243 | + }, | |
| 5244 | + "evidence": { | |
| 5245 | + "name": "evidence", | |
| 5246 | + "type": "jsonb", | |
| 5247 | + "primaryKey": false, | |
| 5248 | + "notNull": true, | |
| 5249 | + "default": "'{}'::jsonb" | |
| 5250 | + }, | |
| 5251 | + "entity_type": { | |
| 5252 | + "name": "entity_type", | |
| 5253 | + "type": "text", | |
| 5254 | + "primaryKey": false, | |
| 5255 | + "notNull": false | |
| 5256 | + }, | |
| 5257 | + "entity_id": { | |
| 5258 | + "name": "entity_id", | |
| 5259 | + "type": "text", | |
| 5260 | + "primaryKey": false, | |
| 5261 | + "notNull": false | |
| 5262 | + }, | |
| 5263 | + "detected_at": { | |
| 5264 | + "name": "detected_at", | |
| 5265 | + "type": "timestamp with time zone", | |
| 5266 | + "primaryKey": false, | |
| 5267 | + "notNull": true | |
| 5268 | + }, | |
| 5269 | + "expires_at": { | |
| 5270 | + "name": "expires_at", | |
| 5271 | + "type": "timestamp with time zone", | |
| 5272 | + "primaryKey": false, | |
| 5273 | + "notNull": false | |
| 5274 | + } | |
| 5275 | + }, | |
| 5276 | + "indexes": { | |
| 5277 | + "radar_kind_idx": { | |
| 5278 | + "name": "radar_kind_idx", | |
| 5279 | + "columns": [ | |
| 5280 | + { | |
| 5281 | + "expression": "kind", | |
| 5282 | + "isExpression": false, | |
| 5283 | + "asc": true, | |
| 5284 | + "nulls": "last" | |
| 5285 | + }, | |
| 5286 | + { | |
| 5287 | + "expression": "detected_at", | |
| 5288 | + "isExpression": false, | |
| 5289 | + "asc": true, | |
| 5290 | + "nulls": "last" | |
| 5291 | + } | |
| 5292 | + ], | |
| 5293 | + "isUnique": false, | |
| 5294 | + "concurrently": false, | |
| 5295 | + "method": "btree", | |
| 5296 | + "with": {} | |
| 5297 | + }, | |
| 5298 | + "radar_entity_uq": { | |
| 5299 | + "name": "radar_entity_uq", | |
| 5300 | + "columns": [ | |
| 5301 | + { | |
| 5302 | + "expression": "kind", | |
| 5303 | + "isExpression": false, | |
| 5304 | + "asc": true, | |
| 5305 | + "nulls": "last" | |
| 5306 | + }, | |
| 5307 | + { | |
| 5308 | + "expression": "entity_type", | |
| 5309 | + "isExpression": false, | |
| 5310 | + "asc": true, | |
| 5311 | + "nulls": "last" | |
| 5312 | + }, | |
| 5313 | + { | |
| 5314 | + "expression": "entity_id", | |
| 5315 | + "isExpression": false, | |
| 5316 | + "asc": true, | |
| 5317 | + "nulls": "last" | |
| 5318 | + } | |
| 5319 | + ], | |
| 5320 | + "isUnique": true, | |
| 5321 | + "concurrently": false, | |
| 5322 | + "method": "btree", | |
| 5323 | + "with": {} | |
| 5324 | + } | |
| 5325 | + }, | |
| 5326 | + "foreignKeys": {}, | |
| 5327 | + "compositePrimaryKeys": {}, | |
| 5328 | + "uniqueConstraints": {}, | |
| 5329 | + "policies": {}, | |
| 5330 | + "checkConstraints": {}, | |
| 5331 | + "isRLSEnabled": false | |
| 5332 | + }, | |
| 5333 | + "public.valuations": { | |
| 5334 | + "name": "valuations", | |
| 5335 | + "schema": "", | |
| 5336 | + "columns": { | |
| 5337 | + "id": { | |
| 5338 | + "name": "id", | |
| 5339 | + "type": "text", | |
| 5340 | + "primaryKey": true, | |
| 5341 | + "notNull": true | |
| 5342 | + }, | |
| 5343 | + "asset_id": { | |
| 5344 | + "name": "asset_id", | |
| 5345 | + "type": "text", | |
| 5346 | + "primaryKey": false, | |
| 5347 | + "notNull": true | |
| 5348 | + }, | |
| 5349 | + "variant_id": { | |
| 5350 | + "name": "variant_id", | |
| 5351 | + "type": "text", | |
| 5352 | + "primaryKey": false, | |
| 5353 | + "notNull": false | |
| 5354 | + }, | |
| 5355 | + "computed_at": { | |
| 5356 | + "name": "computed_at", | |
| 5357 | + "type": "timestamp with time zone", | |
| 5358 | + "primaryKey": false, | |
| 5359 | + "notNull": true | |
| 5360 | + }, | |
| 5361 | + "riv_usd": { | |
| 5362 | + "name": "riv_usd", | |
| 5363 | + "type": "numeric(18, 4)", | |
| 5364 | + "primaryKey": false, | |
| 5365 | + "notNull": false | |
| 5366 | + }, | |
| 5367 | + "low_usd": { | |
| 5368 | + "name": "low_usd", | |
| 5369 | + "type": "numeric(18, 4)", | |
| 5370 | + "primaryKey": false, | |
| 5371 | + "notNull": false | |
| 5372 | + }, | |
| 5373 | + "high_usd": { | |
| 5374 | + "name": "high_usd", | |
| 5375 | + "type": "numeric(18, 4)", | |
| 5376 | + "primaryKey": false, | |
| 5377 | + "notNull": false | |
| 5378 | + }, | |
| 5379 | + "confidence": { | |
| 5380 | + "name": "confidence", | |
| 5381 | + "type": "numeric(8, 6)", | |
| 5382 | + "primaryKey": false, | |
| 5383 | + "notNull": true, | |
| 5384 | + "default": 0 | |
| 5385 | + }, | |
| 5386 | + "confidence_label": { | |
| 5387 | + "name": "confidence_label", | |
| 5388 | + "type": "text", | |
| 5389 | + "primaryKey": false, | |
| 5390 | + "notNull": true, | |
| 5391 | + "default": "'insufficient'" | |
| 5392 | + }, | |
| 5393 | + "sample_size": { | |
| 5394 | + "name": "sample_size", | |
| 5395 | + "type": "integer", | |
| 5396 | + "primaryKey": false, | |
| 5397 | + "notNull": true, | |
| 5398 | + "default": 0 | |
| 5399 | + }, | |
| 5400 | + "window_days": { | |
| 5401 | + "name": "window_days", | |
| 5402 | + "type": "integer", | |
| 5403 | + "primaryKey": false, | |
| 5404 | + "notNull": true, | |
| 5405 | + "default": 365 | |
| 5406 | + }, | |
| 5407 | + "methods": { | |
| 5408 | + "name": "methods", | |
| 5409 | + "type": "jsonb", | |
| 5410 | + "primaryKey": false, | |
| 5411 | + "notNull": true, | |
| 5412 | + "default": "'{}'::jsonb" | |
| 5413 | + }, | |
| 5414 | + "sales_used": { | |
| 5415 | + "name": "sales_used", | |
| 5416 | + "type": "text[]", | |
| 5417 | + "primaryKey": false, | |
| 5418 | + "notNull": true, | |
| 5419 | + "default": "'{}'::text[]" | |
| 5420 | + }, | |
| 5421 | + "observations_used": { | |
| 5422 | + "name": "observations_used", | |
| 5423 | + "type": "integer", | |
| 5424 | + "primaryKey": false, | |
| 5425 | + "notNull": true, | |
| 5426 | + "default": 0 | |
| 5427 | + }, | |
| 5428 | + "method": { | |
| 5429 | + "name": "method", | |
| 5430 | + "type": "text", | |
| 5431 | + "primaryKey": false, | |
| 5432 | + "notNull": true, | |
| 5433 | + "default": "'ensemble_v1'" | |
| 5434 | + }, | |
| 5435 | + "notes": { | |
| 5436 | + "name": "notes", | |
| 5437 | + "type": "text[]", | |
| 5438 | + "primaryKey": false, | |
| 5439 | + "notNull": true, | |
| 5440 | + "default": "'{}'::text[]" | |
| 5441 | + } | |
| 5442 | + }, | |
| 5443 | + "indexes": { | |
| 5444 | + "valuations_asset_idx": { | |
| 5445 | + "name": "valuations_asset_idx", | |
| 5446 | + "columns": [ | |
| 5447 | + { | |
| 5448 | + "expression": "asset_id", | |
| 5449 | + "isExpression": false, | |
| 5450 | + "asc": true, | |
| 5451 | + "nulls": "last" | |
| 5452 | + }, | |
| 5453 | + { | |
| 5454 | + "expression": "computed_at", | |
| 5455 | + "isExpression": false, | |
| 5456 | + "asc": true, | |
| 5457 | + "nulls": "last" | |
| 5458 | + } | |
| 5459 | + ], | |
| 5460 | + "isUnique": false, | |
| 5461 | + "concurrently": false, | |
| 5462 | + "method": "btree", | |
| 5463 | + "with": {} | |
| 5464 | + }, | |
| 5465 | + "valuations_variant_idx": { | |
| 5466 | + "name": "valuations_variant_idx", | |
| 5467 | + "columns": [ | |
| 5468 | + { | |
| 5469 | + "expression": "variant_id", | |
| 5470 | + "isExpression": false, | |
| 5471 | + "asc": true, | |
| 5472 | + "nulls": "last" | |
| 5473 | + }, | |
| 5474 | + { | |
| 5475 | + "expression": "computed_at", | |
| 5476 | + "isExpression": false, | |
| 5477 | + "asc": true, | |
| 5478 | + "nulls": "last" | |
| 5479 | + } | |
| 5480 | + ], | |
| 5481 | + "isUnique": false, | |
| 5482 | + "concurrently": false, | |
| 5483 | + "method": "btree", | |
| 5484 | + "with": {} | |
| 5485 | + } | |
| 5486 | + }, | |
| 5487 | + "foreignKeys": {}, | |
| 5488 | + "compositePrimaryKeys": {}, | |
| 5489 | + "uniqueConstraints": {}, | |
| 5490 | + "policies": {}, | |
| 5491 | + "checkConstraints": {}, | |
| 5492 | + "isRLSEnabled": false | |
| 5493 | + }, | |
| 5494 | + "public.alert_events": { | |
| 5495 | + "name": "alert_events", | |
| 5496 | + "schema": "", | |
| 5497 | + "columns": { | |
| 5498 | + "id": { | |
| 5499 | + "name": "id", | |
| 5500 | + "type": "text", | |
| 5501 | + "primaryKey": true, | |
| 5502 | + "notNull": true | |
| 5503 | + }, | |
| 5504 | + "alert_id": { | |
| 5505 | + "name": "alert_id", | |
| 5506 | + "type": "text", | |
| 5507 | + "primaryKey": false, | |
| 5508 | + "notNull": true | |
| 5509 | + }, | |
| 5510 | + "user_id": { | |
| 5511 | + "name": "user_id", | |
| 5512 | + "type": "text", | |
| 5513 | + "primaryKey": false, | |
| 5514 | + "notNull": true | |
| 5515 | + }, | |
| 5516 | + "message": { | |
| 5517 | + "name": "message", | |
| 5518 | + "type": "text", | |
| 5519 | + "primaryKey": false, | |
| 5520 | + "notNull": true | |
| 5521 | + }, | |
| 5522 | + "payload": { | |
| 5523 | + "name": "payload", | |
| 5524 | + "type": "jsonb", | |
| 5525 | + "primaryKey": false, | |
| 5526 | + "notNull": true, | |
| 5527 | + "default": "'{}'::jsonb" | |
| 5528 | + }, | |
| 5529 | + "read_at": { | |
| 5530 | + "name": "read_at", | |
| 5531 | + "type": "timestamp with time zone", | |
| 5532 | + "primaryKey": false, | |
| 5533 | + "notNull": false | |
| 5534 | + }, | |
| 5535 | + "created_at": { | |
| 5536 | + "name": "created_at", | |
| 5537 | + "type": "timestamp with time zone", | |
| 5538 | + "primaryKey": false, | |
| 5539 | + "notNull": true, | |
| 5540 | + "default": "now()" | |
| 5541 | + } | |
| 5542 | + }, | |
| 5543 | + "indexes": { | |
| 5544 | + "alert_events_user_idx": { | |
| 5545 | + "name": "alert_events_user_idx", | |
| 5546 | + "columns": [ | |
| 5547 | + { | |
| 5548 | + "expression": "user_id", | |
| 5549 | + "isExpression": false, | |
| 5550 | + "asc": true, | |
| 5551 | + "nulls": "last" | |
| 5552 | + }, | |
| 5553 | + { | |
| 5554 | + "expression": "created_at", | |
| 5555 | + "isExpression": false, | |
| 5556 | + "asc": true, | |
| 5557 | + "nulls": "last" | |
| 5558 | + } | |
| 5559 | + ], | |
| 5560 | + "isUnique": false, | |
| 5561 | + "concurrently": false, | |
| 5562 | + "method": "btree", | |
| 5563 | + "with": {} | |
| 5564 | + } | |
| 5565 | + }, | |
| 5566 | + "foreignKeys": {}, | |
| 5567 | + "compositePrimaryKeys": {}, | |
| 5568 | + "uniqueConstraints": {}, | |
| 5569 | + "policies": {}, | |
| 5570 | + "checkConstraints": {}, | |
| 5571 | + "isRLSEnabled": false | |
| 5572 | + }, | |
| 5573 | + "public.alerts": { | |
| 5574 | + "name": "alerts", | |
| 5575 | + "schema": "", | |
| 5576 | + "columns": { | |
| 5577 | + "id": { | |
| 5578 | + "name": "id", | |
| 5579 | + "type": "text", | |
| 5580 | + "primaryKey": true, | |
| 5581 | + "notNull": true | |
| 5582 | + }, | |
| 5583 | + "user_id": { | |
| 5584 | + "name": "user_id", | |
| 5585 | + "type": "text", | |
| 5586 | + "primaryKey": false, | |
| 5587 | + "notNull": true | |
| 5588 | + }, | |
| 5589 | + "alert_type": { | |
| 5590 | + "name": "alert_type", | |
| 5591 | + "type": "text", | |
| 5592 | + "primaryKey": false, | |
| 5593 | + "notNull": true | |
| 5594 | + }, | |
| 5595 | + "target_type": { | |
| 5596 | + "name": "target_type", | |
| 5597 | + "type": "text", | |
| 5598 | + "primaryKey": false, | |
| 5599 | + "notNull": true | |
| 5600 | + }, | |
| 5601 | + "target_id": { | |
| 5602 | + "name": "target_id", | |
| 5603 | + "type": "text", | |
| 5604 | + "primaryKey": false, | |
| 5605 | + "notNull": true | |
| 5606 | + }, | |
| 5607 | + "threshold": { | |
| 5608 | + "name": "threshold", | |
| 5609 | + "type": "numeric(18, 4)", | |
| 5610 | + "primaryKey": false, | |
| 5611 | + "notNull": false | |
| 5612 | + }, | |
| 5613 | + "currency": { | |
| 5614 | + "name": "currency", | |
| 5615 | + "type": "text", | |
| 5616 | + "primaryKey": false, | |
| 5617 | + "notNull": false | |
| 5618 | + }, | |
| 5619 | + "params": { | |
| 5620 | + "name": "params", | |
| 5621 | + "type": "jsonb", | |
| 5622 | + "primaryKey": false, | |
| 5623 | + "notNull": true, | |
| 5624 | + "default": "'{}'::jsonb" | |
| 5625 | + }, | |
| 5626 | + "channel": { | |
| 5627 | + "name": "channel", | |
| 5628 | + "type": "text", | |
| 5629 | + "primaryKey": false, | |
| 5630 | + "notNull": true, | |
| 5631 | + "default": "'inapp'" | |
| 5632 | + }, | |
| 5633 | + "active": { | |
| 5634 | + "name": "active", | |
| 5635 | + "type": "boolean", | |
| 5636 | + "primaryKey": false, | |
| 5637 | + "notNull": true, | |
| 5638 | + "default": true | |
| 5639 | + }, | |
| 5640 | + "last_triggered_at": { | |
| 5641 | + "name": "last_triggered_at", | |
| 5642 | + "type": "timestamp with time zone", | |
| 5643 | + "primaryKey": false, | |
| 5644 | + "notNull": false | |
| 5645 | + }, | |
| 5646 | + "created_at": { | |
| 5647 | + "name": "created_at", | |
| 5648 | + "type": "timestamp with time zone", | |
| 5649 | + "primaryKey": false, | |
| 5650 | + "notNull": true, | |
| 5651 | + "default": "now()" | |
| 5652 | + } | |
| 5653 | + }, | |
| 5654 | + "indexes": { | |
| 5655 | + "alerts_user_idx": { | |
| 5656 | + "name": "alerts_user_idx", | |
| 5657 | + "columns": [ | |
| 5658 | + { | |
| 5659 | + "expression": "user_id", | |
| 5660 | + "isExpression": false, | |
| 5661 | + "asc": true, | |
| 5662 | + "nulls": "last" | |
| 5663 | + } | |
| 5664 | + ], | |
| 5665 | + "isUnique": false, | |
| 5666 | + "concurrently": false, | |
| 5667 | + "method": "btree", | |
| 5668 | + "with": {} | |
| 5669 | + }, | |
| 5670 | + "alerts_target_idx": { | |
| 5671 | + "name": "alerts_target_idx", | |
| 5672 | + "columns": [ | |
| 5673 | + { | |
| 5674 | + "expression": "target_type", | |
| 5675 | + "isExpression": false, | |
| 5676 | + "asc": true, | |
| 5677 | + "nulls": "last" | |
| 5678 | + }, | |
| 5679 | + { | |
| 5680 | + "expression": "target_id", | |
| 5681 | + "isExpression": false, | |
| 5682 | + "asc": true, | |
| 5683 | + "nulls": "last" | |
| 5684 | + }, | |
| 5685 | + { | |
| 5686 | + "expression": "active", | |
| 5687 | + "isExpression": false, | |
| 5688 | + "asc": true, | |
| 5689 | + "nulls": "last" | |
| 5690 | + } | |
| 5691 | + ], | |
| 5692 | + "isUnique": false, | |
| 5693 | + "concurrently": false, | |
| 5694 | + "method": "btree", | |
| 5695 | + "with": {} | |
| 5696 | + } | |
| 5697 | + }, | |
| 5698 | + "foreignKeys": {}, | |
| 5699 | + "compositePrimaryKeys": {}, | |
| 5700 | + "uniqueConstraints": {}, | |
| 5701 | + "policies": {}, | |
| 5702 | + "checkConstraints": {}, | |
| 5703 | + "isRLSEnabled": false | |
| 5704 | + }, | |
| 5705 | + "public.api_keys": { | |
| 5706 | + "name": "api_keys", | |
| 5707 | + "schema": "", | |
| 5708 | + "columns": { | |
| 5709 | + "id": { | |
| 5710 | + "name": "id", | |
| 5711 | + "type": "text", | |
| 5712 | + "primaryKey": true, | |
| 5713 | + "notNull": true | |
| 5714 | + }, | |
| 5715 | + "user_id": { | |
| 5716 | + "name": "user_id", | |
| 5717 | + "type": "text", | |
| 5718 | + "primaryKey": false, | |
| 5719 | + "notNull": false | |
| 5720 | + }, | |
| 5721 | + "name": { | |
| 5722 | + "name": "name", | |
| 5723 | + "type": "text", | |
| 5724 | + "primaryKey": false, | |
| 5725 | + "notNull": true | |
| 5726 | + }, | |
| 5727 | + "prefix": { | |
| 5728 | + "name": "prefix", | |
| 5729 | + "type": "text", | |
| 5730 | + "primaryKey": false, | |
| 5731 | + "notNull": true | |
| 5732 | + }, | |
| 5733 | + "key_hash": { | |
| 5734 | + "name": "key_hash", | |
| 5735 | + "type": "text", | |
| 5736 | + "primaryKey": false, | |
| 5737 | + "notNull": true | |
| 5738 | + }, | |
| 5739 | + "tier": { | |
| 5740 | + "name": "tier", | |
| 5741 | + "type": "text", | |
| 5742 | + "primaryKey": false, | |
| 5743 | + "notNull": true, | |
| 5744 | + "default": "'free'" | |
| 5745 | + }, | |
| 5746 | + "rate_limit_per_minute": { | |
| 5747 | + "name": "rate_limit_per_minute", | |
| 5748 | + "type": "integer", | |
| 5749 | + "primaryKey": false, | |
| 5750 | + "notNull": true, | |
| 5751 | + "default": 60 | |
| 5752 | + }, | |
| 5753 | + "daily_quota": { | |
| 5754 | + "name": "daily_quota", | |
| 5755 | + "type": "integer", | |
| 5756 | + "primaryKey": false, | |
| 5757 | + "notNull": true, | |
| 5758 | + "default": 1000 | |
| 5759 | + }, | |
| 5760 | + "created_at": { | |
| 5761 | + "name": "created_at", | |
| 5762 | + "type": "timestamp with time zone", | |
| 5763 | + "primaryKey": false, | |
| 5764 | + "notNull": true, | |
| 5765 | + "default": "now()" | |
| 5766 | + }, | |
| 5767 | + "last_used_at": { | |
| 5768 | + "name": "last_used_at", | |
| 5769 | + "type": "timestamp with time zone", | |
| 5770 | + "primaryKey": false, | |
| 5771 | + "notNull": false | |
| 5772 | + }, | |
| 5773 | + "revoked_at": { | |
| 5774 | + "name": "revoked_at", | |
| 5775 | + "type": "timestamp with time zone", | |
| 5776 | + "primaryKey": false, | |
| 5777 | + "notNull": false | |
| 5778 | + } | |
| 5779 | + }, | |
| 5780 | + "indexes": { | |
| 5781 | + "api_keys_user_idx": { | |
| 5782 | + "name": "api_keys_user_idx", | |
| 5783 | + "columns": [ | |
| 5784 | + { | |
| 5785 | + "expression": "user_id", | |
| 5786 | + "isExpression": false, | |
| 5787 | + "asc": true, | |
| 5788 | + "nulls": "last" | |
| 5789 | + } | |
| 5790 | + ], | |
| 5791 | + "isUnique": false, | |
| 5792 | + "concurrently": false, | |
| 5793 | + "method": "btree", | |
| 5794 | + "with": {} | |
| 5795 | + } | |
| 5796 | + }, | |
| 5797 | + "foreignKeys": {}, | |
| 5798 | + "compositePrimaryKeys": {}, | |
| 5799 | + "uniqueConstraints": { | |
| 5800 | + "api_keys_key_hash_unique": { | |
| 5801 | + "name": "api_keys_key_hash_unique", | |
| 5802 | + "nullsNotDistinct": false, | |
| 5803 | + "columns": [ | |
| 5804 | + "key_hash" | |
| 5805 | + ] | |
| 5806 | + } | |
| 5807 | + }, | |
| 5808 | + "policies": {}, | |
| 5809 | + "checkConstraints": {}, | |
| 5810 | + "isRLSEnabled": false | |
| 5811 | + }, | |
| 5812 | + "public.api_usage": { | |
| 5813 | + "name": "api_usage", | |
| 5814 | + "schema": "", | |
| 5815 | + "columns": { | |
| 5816 | + "key_id": { | |
| 5817 | + "name": "key_id", | |
| 5818 | + "type": "text", | |
| 5819 | + "primaryKey": false, | |
| 5820 | + "notNull": true | |
| 5821 | + }, | |
| 5822 | + "date": { | |
| 5823 | + "name": "date", | |
| 5824 | + "type": "date", | |
| 5825 | + "primaryKey": false, | |
| 5826 | + "notNull": true | |
| 5827 | + }, | |
| 5828 | + "endpoint": { | |
| 5829 | + "name": "endpoint", | |
| 5830 | + "type": "text", | |
| 5831 | + "primaryKey": false, | |
| 5832 | + "notNull": true | |
| 5833 | + }, | |
| 5834 | + "count": { | |
| 5835 | + "name": "count", | |
| 5836 | + "type": "integer", | |
| 5837 | + "primaryKey": false, | |
| 5838 | + "notNull": true, | |
| 5839 | + "default": 0 | |
| 5840 | + }, | |
| 5841 | + "latency_ms_avg": { | |
| 5842 | + "name": "latency_ms_avg", | |
| 5843 | + "type": "real", | |
| 5844 | + "primaryKey": false, | |
| 5845 | + "notNull": false | |
| 5846 | + } | |
| 5847 | + }, | |
| 5848 | + "indexes": {}, | |
| 5849 | + "foreignKeys": {}, | |
| 5850 | + "compositePrimaryKeys": { | |
| 5851 | + "api_usage_key_id_date_endpoint_pk": { | |
| 5852 | + "name": "api_usage_key_id_date_endpoint_pk", | |
| 5853 | + "columns": [ | |
| 5854 | + "key_id", | |
| 5855 | + "date", | |
| 5856 | + "endpoint" | |
| 5857 | + ] | |
| 5858 | + } | |
| 5859 | + }, | |
| 5860 | + "uniqueConstraints": {}, | |
| 5861 | + "policies": {}, | |
| 5862 | + "checkConstraints": {}, | |
| 5863 | + "isRLSEnabled": false | |
| 5864 | + }, | |
| 5865 | + "public.asset_views": { | |
| 5866 | + "name": "asset_views", | |
| 5867 | + "schema": "", | |
| 5868 | + "columns": { | |
| 5869 | + "asset_id": { | |
| 5870 | + "name": "asset_id", | |
| 5871 | + "type": "text", | |
| 5872 | + "primaryKey": false, | |
| 5873 | + "notNull": true | |
| 5874 | + }, | |
| 5875 | + "date": { | |
| 5876 | + "name": "date", | |
| 5877 | + "type": "date", | |
| 5878 | + "primaryKey": false, | |
| 5879 | + "notNull": true | |
| 5880 | + }, | |
| 5881 | + "views": { | |
| 5882 | + "name": "views", | |
| 5883 | + "type": "integer", | |
| 5884 | + "primaryKey": false, | |
| 5885 | + "notNull": true, | |
| 5886 | + "default": 0 | |
| 5887 | + } | |
| 5888 | + }, | |
| 5889 | + "indexes": {}, | |
| 5890 | + "foreignKeys": {}, | |
| 5891 | + "compositePrimaryKeys": { | |
| 5892 | + "asset_views_asset_id_date_pk": { | |
| 5893 | + "name": "asset_views_asset_id_date_pk", | |
| 5894 | + "columns": [ | |
| 5895 | + "asset_id", | |
| 5896 | + "date" | |
| 5897 | + ] | |
| 5898 | + } | |
| 5899 | + }, | |
| 5900 | + "uniqueConstraints": {}, | |
| 5901 | + "policies": {}, | |
| 5902 | + "checkConstraints": {}, | |
| 5903 | + "isRLSEnabled": false | |
| 5904 | + }, | |
| 5905 | + "public.collection_items": { | |
| 5906 | + "name": "collection_items", | |
| 5907 | + "schema": "", | |
| 5908 | + "columns": { | |
| 5909 | + "id": { | |
| 5910 | + "name": "id", | |
| 5911 | + "type": "text", | |
| 5912 | + "primaryKey": true, | |
| 5913 | + "notNull": true | |
| 5914 | + }, | |
| 5915 | + "collection_id": { | |
| 5916 | + "name": "collection_id", | |
| 5917 | + "type": "text", | |
| 5918 | + "primaryKey": false, | |
| 5919 | + "notNull": true | |
| 5920 | + }, | |
| 5921 | + "asset_id": { | |
| 5922 | + "name": "asset_id", | |
| 5923 | + "type": "text", | |
| 5924 | + "primaryKey": false, | |
| 5925 | + "notNull": true | |
| 5926 | + }, | |
| 5927 | + "variant_id": { | |
| 5928 | + "name": "variant_id", | |
| 5929 | + "type": "text", | |
| 5930 | + "primaryKey": false, | |
| 5931 | + "notNull": false | |
| 5932 | + }, | |
| 5933 | + "quantity": { | |
| 5934 | + "name": "quantity", | |
| 5935 | + "type": "integer", | |
| 5936 | + "primaryKey": false, | |
| 5937 | + "notNull": true, | |
| 5938 | + "default": 1 | |
| 5939 | + }, | |
| 5940 | + "acquired_at": { | |
| 5941 | + "name": "acquired_at", | |
| 5942 | + "type": "date", | |
| 5943 | + "primaryKey": false, | |
| 5944 | + "notNull": false | |
| 5945 | + }, | |
| 5946 | + "purchase_price": { | |
| 5947 | + "name": "purchase_price", | |
| 5948 | + "type": "numeric(18, 4)", | |
| 5949 | + "primaryKey": false, | |
| 5950 | + "notNull": false | |
| 5951 | + }, | |
| 5952 | + "purchase_currency": { | |
| 5953 | + "name": "purchase_currency", | |
| 5954 | + "type": "text", | |
| 5955 | + "primaryKey": false, | |
| 5956 | + "notNull": false | |
| 5957 | + }, | |
| 5958 | + "purchase_price_usd": { | |
| 5959 | + "name": "purchase_price_usd", | |
| 5960 | + "type": "numeric(18, 4)", | |
| 5961 | + "primaryKey": false, | |
| 5962 | + "notNull": false | |
| 5963 | + }, | |
| 5964 | + "source": { | |
| 5965 | + "name": "source", | |
| 5966 | + "type": "text", | |
| 5967 | + "primaryKey": false, | |
| 5968 | + "notNull": false | |
| 5969 | + }, | |
| 5970 | + "grader": { | |
| 5971 | + "name": "grader", | |
| 5972 | + "type": "text", | |
| 5973 | + "primaryKey": false, | |
| 5974 | + "notNull": false | |
| 5975 | + }, | |
| 5976 | + "grade": { | |
| 5977 | + "name": "grade", | |
| 5978 | + "type": "text", | |
| 5979 | + "primaryKey": false, | |
| 5980 | + "notNull": false | |
| 5981 | + }, | |
| 5982 | + "certification_number": { | |
| 5983 | + "name": "certification_number", | |
| 5984 | + "type": "text", | |
| 5985 | + "primaryKey": false, | |
| 5986 | + "notNull": false | |
| 5987 | + }, | |
| 5988 | + "serial": { | |
| 5989 | + "name": "serial", | |
| 5990 | + "type": "text", | |
| 5991 | + "primaryKey": false, | |
| 5992 | + "notNull": false | |
| 5993 | + }, | |
| 5994 | + "photos": { | |
| 5995 | + "name": "photos", | |
| 5996 | + "type": "jsonb", | |
| 5997 | + "primaryKey": false, | |
| 5998 | + "notNull": true, | |
| 5999 | + "default": "'[]'::jsonb" | |
| 6000 | + }, | |
| 6001 | + "notes": { | |
| 6002 | + "name": "notes", | |
| 6003 | + "type": "text", | |
| 6004 | + "primaryKey": false, | |
| 6005 | + "notNull": false | |
| 6006 | + }, | |
| 6007 | + "created_at": { | |
| 6008 | + "name": "created_at", | |
| 6009 | + "type": "timestamp with time zone", | |
| 6010 | + "primaryKey": false, | |
| 6011 | + "notNull": true, | |
| 6012 | + "default": "now()" | |
| 6013 | + }, | |
| 6014 | + "updated_at": { | |
| 6015 | + "name": "updated_at", | |
| 6016 | + "type": "timestamp with time zone", | |
| 6017 | + "primaryKey": false, | |
| 6018 | + "notNull": true, | |
| 6019 | + "default": "now()" | |
| 6020 | + } | |
| 6021 | + }, | |
| 6022 | + "indexes": { | |
| 6023 | + "collection_items_collection_idx": { | |
| 6024 | + "name": "collection_items_collection_idx", | |
| 6025 | + "columns": [ | |
| 6026 | + { | |
| 6027 | + "expression": "collection_id", | |
| 6028 | + "isExpression": false, | |
| 6029 | + "asc": true, | |
| 6030 | + "nulls": "last" | |
| 6031 | + } | |
| 6032 | + ], | |
| 6033 | + "isUnique": false, | |
| 6034 | + "concurrently": false, | |
| 6035 | + "method": "btree", | |
| 6036 | + "with": {} | |
| 6037 | + }, | |
| 6038 | + "collection_items_asset_idx": { | |
| 6039 | + "name": "collection_items_asset_idx", | |
| 6040 | + "columns": [ | |
| 6041 | + { | |
| 6042 | + "expression": "asset_id", | |
| 6043 | + "isExpression": false, | |
| 6044 | + "asc": true, | |
| 6045 | + "nulls": "last" | |
| 6046 | + } | |
| 6047 | + ], | |
| 6048 | + "isUnique": false, | |
| 6049 | + "concurrently": false, | |
| 6050 | + "method": "btree", | |
| 6051 | + "with": {} | |
| 6052 | + } | |
| 6053 | + }, | |
| 6054 | + "foreignKeys": {}, | |
| 6055 | + "compositePrimaryKeys": {}, | |
| 6056 | + "uniqueConstraints": {}, | |
| 6057 | + "policies": {}, | |
| 6058 | + "checkConstraints": {}, | |
| 6059 | + "isRLSEnabled": false | |
| 6060 | + }, | |
| 6061 | + "public.collection_snapshots": { | |
| 6062 | + "name": "collection_snapshots", | |
| 6063 | + "schema": "", | |
| 6064 | + "columns": { | |
| 6065 | + "collection_id": { | |
| 6066 | + "name": "collection_id", | |
| 6067 | + "type": "text", | |
| 6068 | + "primaryKey": false, | |
| 6069 | + "notNull": true | |
| 6070 | + }, | |
| 6071 | + "date": { | |
| 6072 | + "name": "date", | |
| 6073 | + "type": "date", | |
| 6074 | + "primaryKey": false, | |
| 6075 | + "notNull": true | |
| 6076 | + }, | |
| 6077 | + "value_usd": { | |
| 6078 | + "name": "value_usd", | |
| 6079 | + "type": "numeric(18, 4)", | |
| 6080 | + "primaryKey": false, | |
| 6081 | + "notNull": true | |
| 6082 | + }, | |
| 6083 | + "cost_basis_usd": { | |
| 6084 | + "name": "cost_basis_usd", | |
| 6085 | + "type": "numeric(18, 4)", | |
| 6086 | + "primaryKey": false, | |
| 6087 | + "notNull": true | |
| 6088 | + }, | |
| 6089 | + "items": { | |
| 6090 | + "name": "items", | |
| 6091 | + "type": "integer", | |
| 6092 | + "primaryKey": false, | |
| 6093 | + "notNull": true | |
| 6094 | + } | |
| 6095 | + }, | |
| 6096 | + "indexes": {}, | |
| 6097 | + "foreignKeys": {}, | |
| 6098 | + "compositePrimaryKeys": { | |
| 6099 | + "collection_snapshots_collection_id_date_pk": { | |
| 6100 | + "name": "collection_snapshots_collection_id_date_pk", | |
| 6101 | + "columns": [ | |
| 6102 | + "collection_id", | |
| 6103 | + "date" | |
| 6104 | + ] | |
| 6105 | + } | |
| 6106 | + }, | |
| 6107 | + "uniqueConstraints": {}, | |
| 6108 | + "policies": {}, | |
| 6109 | + "checkConstraints": {}, | |
| 6110 | + "isRLSEnabled": false | |
| 6111 | + }, | |
| 6112 | + "public.collections": { | |
| 6113 | + "name": "collections", | |
| 6114 | + "schema": "", | |
| 6115 | + "columns": { | |
| 6116 | + "id": { | |
| 6117 | + "name": "id", | |
| 6118 | + "type": "text", | |
| 6119 | + "primaryKey": true, | |
| 6120 | + "notNull": true | |
| 6121 | + }, | |
| 6122 | + "user_id": { | |
| 6123 | + "name": "user_id", | |
| 6124 | + "type": "text", | |
| 6125 | + "primaryKey": false, | |
| 6126 | + "notNull": true | |
| 6127 | + }, | |
| 6128 | + "name": { | |
| 6129 | + "name": "name", | |
| 6130 | + "type": "text", | |
| 6131 | + "primaryKey": false, | |
| 6132 | + "notNull": true | |
| 6133 | + }, | |
| 6134 | + "description": { | |
| 6135 | + "name": "description", | |
| 6136 | + "type": "text", | |
| 6137 | + "primaryKey": false, | |
| 6138 | + "notNull": false | |
| 6139 | + }, | |
| 6140 | + "is_public": { | |
| 6141 | + "name": "is_public", | |
| 6142 | + "type": "boolean", | |
| 6143 | + "primaryKey": false, | |
| 6144 | + "notNull": true, | |
| 6145 | + "default": false | |
| 6146 | + }, | |
| 6147 | + "public_slug": { | |
| 6148 | + "name": "public_slug", | |
| 6149 | + "type": "text", | |
| 6150 | + "primaryKey": false, | |
| 6151 | + "notNull": false | |
| 6152 | + }, | |
| 6153 | + "created_at": { | |
| 6154 | + "name": "created_at", | |
| 6155 | + "type": "timestamp with time zone", | |
| 6156 | + "primaryKey": false, | |
| 6157 | + "notNull": true, | |
| 6158 | + "default": "now()" | |
| 6159 | + }, | |
| 6160 | + "updated_at": { | |
| 6161 | + "name": "updated_at", | |
| 6162 | + "type": "timestamp with time zone", | |
| 6163 | + "primaryKey": false, | |
| 6164 | + "notNull": true, | |
| 6165 | + "default": "now()" | |
| 6166 | + } | |
| 6167 | + }, | |
| 6168 | + "indexes": { | |
| 6169 | + "collections_user_idx": { | |
| 6170 | + "name": "collections_user_idx", | |
| 6171 | + "columns": [ | |
| 6172 | + { | |
| 6173 | + "expression": "user_id", | |
| 6174 | + "isExpression": false, | |
| 6175 | + "asc": true, | |
| 6176 | + "nulls": "last" | |
| 6177 | + } | |
| 6178 | + ], | |
| 6179 | + "isUnique": false, | |
| 6180 | + "concurrently": false, | |
| 6181 | + "method": "btree", | |
| 6182 | + "with": {} | |
| 6183 | + }, | |
| 6184 | + "collections_public_slug_uq": { | |
| 6185 | + "name": "collections_public_slug_uq", | |
| 6186 | + "columns": [ | |
| 6187 | + { | |
| 6188 | + "expression": "public_slug", | |
| 6189 | + "isExpression": false, | |
| 6190 | + "asc": true, | |
| 6191 | + "nulls": "last" | |
| 6192 | + } | |
| 6193 | + ], | |
| 6194 | + "isUnique": true, | |
| 6195 | + "concurrently": false, | |
| 6196 | + "method": "btree", | |
| 6197 | + "with": {} | |
| 6198 | + } | |
| 6199 | + }, | |
| 6200 | + "foreignKeys": {}, | |
| 6201 | + "compositePrimaryKeys": {}, | |
| 6202 | + "uniqueConstraints": {}, | |
| 6203 | + "policies": {}, | |
| 6204 | + "checkConstraints": {}, | |
| 6205 | + "isRLSEnabled": false | |
| 6206 | + }, | |
| 6207 | + "public.search_log": { | |
| 6208 | + "name": "search_log", | |
| 6209 | + "schema": "", | |
| 6210 | + "columns": { | |
| 6211 | + "id": { | |
| 6212 | + "name": "id", | |
| 6213 | + "type": "text", | |
| 6214 | + "primaryKey": true, | |
| 6215 | + "notNull": true | |
| 6216 | + }, | |
| 6217 | + "query": { | |
| 6218 | + "name": "query", | |
| 6219 | + "type": "text", | |
| 6220 | + "primaryKey": false, | |
| 6221 | + "notNull": true | |
| 6222 | + }, | |
| 6223 | + "normalized": { | |
| 6224 | + "name": "normalized", | |
| 6225 | + "type": "text", | |
| 6226 | + "primaryKey": false, | |
| 6227 | + "notNull": true | |
| 6228 | + }, | |
| 6229 | + "results": { | |
| 6230 | + "name": "results", | |
| 6231 | + "type": "integer", | |
| 6232 | + "primaryKey": false, | |
| 6233 | + "notNull": true | |
| 6234 | + }, | |
| 6235 | + "user_id": { | |
| 6236 | + "name": "user_id", | |
| 6237 | + "type": "text", | |
| 6238 | + "primaryKey": false, | |
| 6239 | + "notNull": false | |
| 6240 | + }, | |
| 6241 | + "created_at": { | |
| 6242 | + "name": "created_at", | |
| 6243 | + "type": "timestamp with time zone", | |
| 6244 | + "primaryKey": false, | |
| 6245 | + "notNull": true, | |
| 6246 | + "default": "now()" | |
| 6247 | + } | |
| 6248 | + }, | |
| 6249 | + "indexes": { | |
| 6250 | + "search_log_created_idx": { | |
| 6251 | + "name": "search_log_created_idx", | |
| 6252 | + "columns": [ | |
| 6253 | + { | |
| 6254 | + "expression": "created_at", | |
| 6255 | + "isExpression": false, | |
| 6256 | + "asc": true, | |
| 6257 | + "nulls": "last" | |
| 6258 | + } | |
| 6259 | + ], | |
| 6260 | + "isUnique": false, | |
| 6261 | + "concurrently": false, | |
| 6262 | + "method": "btree", | |
| 6263 | + "with": {} | |
| 6264 | + }, | |
| 6265 | + "search_log_normalized_idx": { | |
| 6266 | + "name": "search_log_normalized_idx", | |
| 6267 | + "columns": [ | |
| 6268 | + { | |
| 6269 | + "expression": "normalized", | |
| 6270 | + "isExpression": false, | |
| 6271 | + "asc": true, | |
| 6272 | + "nulls": "last" | |
| 6273 | + } | |
| 6274 | + ], | |
| 6275 | + "isUnique": false, | |
| 6276 | + "concurrently": false, | |
| 6277 | + "method": "btree", | |
| 6278 | + "with": {} | |
| 6279 | + } | |
| 6280 | + }, | |
| 6281 | + "foreignKeys": {}, | |
| 6282 | + "compositePrimaryKeys": {}, | |
| 6283 | + "uniqueConstraints": {}, | |
| 6284 | + "policies": {}, | |
| 6285 | + "checkConstraints": {}, | |
| 6286 | + "isRLSEnabled": false | |
| 6287 | + }, | |
| 6288 | + "public.sessions": { | |
| 6289 | + "name": "sessions", | |
| 6290 | + "schema": "", | |
| 6291 | + "columns": { | |
| 6292 | + "id": { | |
| 6293 | + "name": "id", | |
| 6294 | + "type": "text", | |
| 6295 | + "primaryKey": true, | |
| 6296 | + "notNull": true | |
| 6297 | + }, | |
| 6298 | + "user_id": { | |
| 6299 | + "name": "user_id", | |
| 6300 | + "type": "text", | |
| 6301 | + "primaryKey": false, | |
| 6302 | + "notNull": true | |
| 6303 | + }, | |
| 6304 | + "expires_at": { | |
| 6305 | + "name": "expires_at", | |
| 6306 | + "type": "timestamp with time zone", | |
| 6307 | + "primaryKey": false, | |
| 6308 | + "notNull": true | |
| 6309 | + }, | |
| 6310 | + "user_agent": { | |
| 6311 | + "name": "user_agent", | |
| 6312 | + "type": "text", | |
| 6313 | + "primaryKey": false, | |
| 6314 | + "notNull": false | |
| 6315 | + }, | |
| 6316 | + "created_at": { | |
| 6317 | + "name": "created_at", | |
| 6318 | + "type": "timestamp with time zone", | |
| 6319 | + "primaryKey": false, | |
| 6320 | + "notNull": true, | |
| 6321 | + "default": "now()" | |
| 6322 | + } | |
| 6323 | + }, | |
| 6324 | + "indexes": { | |
| 6325 | + "sessions_user_idx": { | |
| 6326 | + "name": "sessions_user_idx", | |
| 6327 | + "columns": [ | |
| 6328 | + { | |
| 6329 | + "expression": "user_id", | |
| 6330 | + "isExpression": false, | |
| 6331 | + "asc": true, | |
| 6332 | + "nulls": "last" | |
| 6333 | + } | |
| 6334 | + ], | |
| 6335 | + "isUnique": false, | |
| 6336 | + "concurrently": false, | |
| 6337 | + "method": "btree", | |
| 6338 | + "with": {} | |
| 6339 | + } | |
| 6340 | + }, | |
| 6341 | + "foreignKeys": {}, | |
| 6342 | + "compositePrimaryKeys": {}, | |
| 6343 | + "uniqueConstraints": {}, | |
| 6344 | + "policies": {}, | |
| 6345 | + "checkConstraints": {}, | |
| 6346 | + "isRLSEnabled": false | |
| 6347 | + }, | |
| 6348 | + "public.users": { | |
| 6349 | + "name": "users", | |
| 6350 | + "schema": "", | |
| 6351 | + "columns": { | |
| 6352 | + "id": { | |
| 6353 | + "name": "id", | |
| 6354 | + "type": "text", | |
| 6355 | + "primaryKey": true, | |
| 6356 | + "notNull": true | |
| 6357 | + }, | |
| 6358 | + "email": { | |
| 6359 | + "name": "email", | |
| 6360 | + "type": "text", | |
| 6361 | + "primaryKey": false, | |
| 6362 | + "notNull": true | |
| 6363 | + }, | |
| 6364 | + "email_verified_at": { | |
| 6365 | + "name": "email_verified_at", | |
| 6366 | + "type": "timestamp with time zone", | |
| 6367 | + "primaryKey": false, | |
| 6368 | + "notNull": false | |
| 6369 | + }, | |
| 6370 | + "password_hash": { | |
| 6371 | + "name": "password_hash", | |
| 6372 | + "type": "text", | |
| 6373 | + "primaryKey": false, | |
| 6374 | + "notNull": false | |
| 6375 | + }, | |
| 6376 | + "name": { | |
| 6377 | + "name": "name", | |
| 6378 | + "type": "text", | |
| 6379 | + "primaryKey": false, | |
| 6380 | + "notNull": false | |
| 6381 | + }, | |
| 6382 | + "role": { | |
| 6383 | + "name": "role", | |
| 6384 | + "type": "text", | |
| 6385 | + "primaryKey": false, | |
| 6386 | + "notNull": true, | |
| 6387 | + "default": "'user'" | |
| 6388 | + }, | |
| 6389 | + "display_currency": { | |
| 6390 | + "name": "display_currency", | |
| 6391 | + "type": "text", | |
| 6392 | + "primaryKey": false, | |
| 6393 | + "notNull": true, | |
| 6394 | + "default": "'USD'" | |
| 6395 | + }, | |
| 6396 | + "providers": { | |
| 6397 | + "name": "providers", | |
| 6398 | + "type": "jsonb", | |
| 6399 | + "primaryKey": false, | |
| 6400 | + "notNull": true, | |
| 6401 | + "default": "'[]'::jsonb" | |
| 6402 | + }, | |
| 6403 | + "preferences": { | |
| 6404 | + "name": "preferences", | |
| 6405 | + "type": "jsonb", | |
| 6406 | + "primaryKey": false, | |
| 6407 | + "notNull": true, | |
| 6408 | + "default": "'{}'::jsonb" | |
| 6409 | + }, | |
| 6410 | + "created_at": { | |
| 6411 | + "name": "created_at", | |
| 6412 | + "type": "timestamp with time zone", | |
| 6413 | + "primaryKey": false, | |
| 6414 | + "notNull": true, | |
| 6415 | + "default": "now()" | |
| 6416 | + }, | |
| 6417 | + "last_login_at": { | |
| 6418 | + "name": "last_login_at", | |
| 6419 | + "type": "timestamp with time zone", | |
| 6420 | + "primaryKey": false, | |
| 6421 | + "notNull": false | |
| 6422 | + } | |
| 6423 | + }, | |
| 6424 | + "indexes": {}, | |
| 6425 | + "foreignKeys": {}, | |
| 6426 | + "compositePrimaryKeys": {}, | |
| 6427 | + "uniqueConstraints": { | |
| 6428 | + "users_email_unique": { | |
| 6429 | + "name": "users_email_unique", | |
| 6430 | + "nullsNotDistinct": false, | |
| 6431 | + "columns": [ | |
| 6432 | + "email" | |
| 6433 | + ] | |
| 6434 | + } | |
| 6435 | + }, | |
| 6436 | + "policies": {}, | |
| 6437 | + "checkConstraints": {}, | |
| 6438 | + "isRLSEnabled": false | |
| 6439 | + }, | |
| 6440 | + "public.watchlist_items": { | |
| 6441 | + "name": "watchlist_items", | |
| 6442 | + "schema": "", | |
| 6443 | + "columns": { | |
| 6444 | + "id": { | |
| 6445 | + "name": "id", | |
| 6446 | + "type": "text", | |
| 6447 | + "primaryKey": true, | |
| 6448 | + "notNull": true | |
| 6449 | + }, | |
| 6450 | + "watchlist_id": { | |
| 6451 | + "name": "watchlist_id", | |
| 6452 | + "type": "text", | |
| 6453 | + "primaryKey": false, | |
| 6454 | + "notNull": true | |
| 6455 | + }, | |
| 6456 | + "target_type": { | |
| 6457 | + "name": "target_type", | |
| 6458 | + "type": "text", | |
| 6459 | + "primaryKey": false, | |
| 6460 | + "notNull": true | |
| 6461 | + }, | |
| 6462 | + "target_id": { | |
| 6463 | + "name": "target_id", | |
| 6464 | + "type": "text", | |
| 6465 | + "primaryKey": false, | |
| 6466 | + "notNull": true | |
| 6467 | + }, | |
| 6468 | + "created_at": { | |
| 6469 | + "name": "created_at", | |
| 6470 | + "type": "timestamp with time zone", | |
| 6471 | + "primaryKey": false, | |
| 6472 | + "notNull": true, | |
| 6473 | + "default": "now()" | |
| 6474 | + } | |
| 6475 | + }, | |
| 6476 | + "indexes": { | |
| 6477 | + "watchlist_items_uq": { | |
| 6478 | + "name": "watchlist_items_uq", | |
| 6479 | + "columns": [ | |
| 6480 | + { | |
| 6481 | + "expression": "watchlist_id", | |
| 6482 | + "isExpression": false, | |
| 6483 | + "asc": true, | |
| 6484 | + "nulls": "last" | |
| 6485 | + }, | |
| 6486 | + { | |
| 6487 | + "expression": "target_type", | |
| 6488 | + "isExpression": false, | |
| 6489 | + "asc": true, | |
| 6490 | + "nulls": "last" | |
| 6491 | + }, | |
| 6492 | + { | |
| 6493 | + "expression": "target_id", | |
| 6494 | + "isExpression": false, | |
| 6495 | + "asc": true, | |
| 6496 | + "nulls": "last" | |
| 6497 | + } | |
| 6498 | + ], | |
| 6499 | + "isUnique": true, | |
| 6500 | + "concurrently": false, | |
| 6501 | + "method": "btree", | |
| 6502 | + "with": {} | |
| 6503 | + } | |
| 6504 | + }, | |
| 6505 | + "foreignKeys": {}, | |
| 6506 | + "compositePrimaryKeys": {}, | |
| 6507 | + "uniqueConstraints": {}, | |
| 6508 | + "policies": {}, | |
| 6509 | + "checkConstraints": {}, | |
| 6510 | + "isRLSEnabled": false | |
| 6511 | + }, | |
| 6512 | + "public.watchlists": { | |
| 6513 | + "name": "watchlists", | |
| 6514 | + "schema": "", | |
| 6515 | + "columns": { | |
| 6516 | + "id": { | |
| 6517 | + "name": "id", | |
| 6518 | + "type": "text", | |
| 6519 | + "primaryKey": true, | |
| 6520 | + "notNull": true | |
| 6521 | + }, | |
| 6522 | + "user_id": { | |
| 6523 | + "name": "user_id", | |
| 6524 | + "type": "text", | |
| 6525 | + "primaryKey": false, | |
| 6526 | + "notNull": true | |
| 6527 | + }, | |
| 6528 | + "name": { | |
| 6529 | + "name": "name", | |
| 6530 | + "type": "text", | |
| 6531 | + "primaryKey": false, | |
| 6532 | + "notNull": true, | |
| 6533 | + "default": "'Watchlist'" | |
| 6534 | + }, | |
| 6535 | + "created_at": { | |
| 6536 | + "name": "created_at", | |
| 6537 | + "type": "timestamp with time zone", | |
| 6538 | + "primaryKey": false, | |
| 6539 | + "notNull": true, | |
| 6540 | + "default": "now()" | |
| 6541 | + } | |
| 6542 | + }, | |
| 6543 | + "indexes": { | |
| 6544 | + "watchlists_user_idx": { | |
| 6545 | + "name": "watchlists_user_idx", | |
| 6546 | + "columns": [ | |
| 6547 | + { | |
| 6548 | + "expression": "user_id", | |
| 6549 | + "isExpression": false, | |
| 6550 | + "asc": true, | |
| 6551 | + "nulls": "last" | |
| 6552 | + } | |
| 6553 | + ], | |
| 6554 | + "isUnique": false, | |
| 6555 | + "concurrently": false, | |
| 6556 | + "method": "btree", | |
| 6557 | + "with": {} | |
| 6558 | + } | |
| 6559 | + }, | |
| 6560 | + "foreignKeys": {}, | |
| 6561 | + "compositePrimaryKeys": {}, | |
| 6562 | + "uniqueConstraints": {}, | |
| 6563 | + "policies": {}, | |
| 6564 | + "checkConstraints": {}, | |
| 6565 | + "isRLSEnabled": false | |
| 6566 | + } | |
| 6567 | + }, | |
| 6568 | + "enums": {}, | |
| 6569 | + "schemas": {}, | |
| 6570 | + "sequences": {}, | |
| 6571 | + "roles": {}, | |
| 6572 | + "policies": {}, | |
| 6573 | + "views": {}, | |
| 6574 | + "_meta": { | |
| 6575 | + "columns": {}, | |
| 6576 | + "schemas": {}, | |
| 6577 | + "tables": {} | |
| 6578 | + } | |
| 6579 | +} | |
| \ No newline at end of file | ||
added
packages/database/migrations/meta/_journal.json
+13 −0
@@ -0,0 +1,13 @@ | ||
| 1 | +{ | |
| 2 | + "version": "7", | |
| 3 | + "dialect": "postgresql", | |
| 4 | + "entries": [ | |
| 5 | + { | |
| 6 | + "idx": 0, | |
| 7 | + "version": "7", | |
| 8 | + "when": 1788754246505, | |
| 9 | + "tag": "0000_clear_unicorn", | |
| 10 | + "breakpoints": true | |
| 11 | + } | |
| 12 | + ] | |
| 13 | +} | |
| \ No newline at end of file | ||
added
packages/database/package.json
+38 −0
@@ -0,0 +1,38 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@rareindex/database", | |
| 3 | + "version": "0.1.0", | |
| 4 | + "private": true, | |
| 5 | + "type": "module", | |
| 6 | + "exports": { | |
| 7 | + ".": { | |
| 8 | + "types": "./src/index.ts", | |
| 9 | + "default": "./src/index.ts" | |
| 10 | + }, | |
| 11 | + "./schema": { | |
| 12 | + "types": "./src/schema/index.ts", | |
| 13 | + "default": "./src/schema/index.ts" | |
| 14 | + } | |
| 15 | + }, | |
| 16 | + "scripts": { | |
| 17 | + "build": "tsc -p tsconfig.json --noEmit", | |
| 18 | + "typecheck": "tsc -p tsconfig.json --noEmit", | |
| 19 | + "test": "vitest run --passWithNoTests", | |
| 20 | + "generate": "drizzle-kit generate", | |
| 21 | + "migrate": "tsx src/migrate.ts", | |
| 22 | + "seed": "tsx src/seed.ts", | |
| 23 | + "studio": "drizzle-kit studio" | |
| 24 | + }, | |
| 25 | + "dependencies": { | |
| 26 | + "@rareindex/shared": "workspace:*", | |
| 27 | + "@rareindex/taxonomy": "workspace:*", | |
| 28 | + "drizzle-orm": "^0.45.0", | |
| 29 | + "postgres": "^3.4.7" | |
| 30 | + }, | |
| 31 | + "devDependencies": { | |
| 32 | + "@types/node": "^24.0.0", | |
| 33 | + "drizzle-kit": "^0.31.0", | |
| 34 | + "tsx": "^4.20.0", | |
| 35 | + "typescript": "^5.9.3", | |
| 36 | + "vitest": "^3.2.0" | |
| 37 | + } | |
| 38 | +} | |
added
packages/database/src/client.ts
+44 −0
@@ -0,0 +1,44 @@ | ||
| 1 | +import postgres from 'postgres'; | |
| 2 | +import { drizzle, type PostgresJsDatabase } from 'drizzle-orm/postgres-js'; | |
| 3 | +import * as schema from './schema/index.js'; | |
| 4 | + | |
| 5 | +export type Database = PostgresJsDatabase<typeof schema>; | |
| 6 | + | |
| 7 | +let _sql: ReturnType<typeof postgres> | null = null; | |
| 8 | +let _db: Database | null = null; | |
| 9 | + | |
| 10 | +export interface DbOptions { | |
| 11 | + url?: string; | |
| 12 | + max?: number; | |
| 13 | +} | |
| 14 | + | |
| 15 | +/** Lazily created singleton; safe to import from Next.js server components and workers alike. */ | |
| 16 | +export function getSql(opts: DbOptions = {}) { | |
| 17 | + if (!_sql) { | |
| 18 | + const url = opts.url ?? process.env.DATABASE_URL ?? 'postgres://localhost:5432/rareindex'; | |
| 19 | + _sql = postgres(url, { | |
| 20 | + max: opts.max ?? Number(process.env.DB_POOL_MAX ?? 10), | |
| 21 | + idle_timeout: 30, | |
| 22 | + connect_timeout: 10, | |
| 23 | + prepare: true, | |
| 24 | + transform: { undefined: null }, | |
| 25 | + onnotice: () => {}, | |
| 26 | + }); | |
| 27 | + } | |
| 28 | + return _sql; | |
| 29 | +} | |
| 30 | + | |
| 31 | +export function getDb(opts: DbOptions = {}): Database { | |
| 32 | + if (!_db) _db = drizzle(getSql(opts), { schema, casing: 'snake_case' }); | |
| 33 | + return _db; | |
| 34 | +} | |
| 35 | + | |
| 36 | +export async function closeDb(): Promise<void> { | |
| 37 | + if (_sql) { | |
| 38 | + await _sql.end({ timeout: 5 }); | |
| 39 | + _sql = null; | |
| 40 | + _db = null; | |
| 41 | + } | |
| 42 | +} | |
| 43 | + | |
| 44 | +export { schema }; | |
added
packages/database/src/index.ts
+6 −0
@@ -0,0 +1,6 @@ | ||
| 1 | +export * from './client.js'; | |
| 2 | +export * as schema from './schema/index.js'; | |
| 3 | +export * from './schema/index.js'; | |
| 4 | +export { runMigrations } from './migrate.js'; | |
| 5 | +export { seedTaxonomy, seedIndices } from './seed.js'; | |
| 6 | +export { sql, eq, and, or, desc, asc, gte, lte, lt, gt, inArray, isNull, isNotNull, ilike, count, sum, avg, max, min, ne, between, notInArray } from 'drizzle-orm'; | |
added
packages/database/src/migrate.ts
+33 −0
@@ -0,0 +1,33 @@ | ||
| 1 | +import { migrate } from 'drizzle-orm/postgres-js/migrator'; | |
| 2 | +import { fileURLToPath } from 'node:url'; | |
| 3 | +import path from 'node:path'; | |
| 4 | +import { getDb, getSql, closeDb } from './client.js'; | |
| 5 | + | |
| 6 | +/** | |
| 7 | + * Runs SQL migrations from ./migrations. Extensions are created first (idempotent) because | |
| 8 | + * drizzle-kit does not manage them; `vector` is optional and only enabled when available. | |
| 9 | + */ | |
| 10 | +export async function runMigrations(): Promise<void> { | |
| 11 | + const sql = getSql({ max: 1 }); | |
| 12 | + await sql`CREATE EXTENSION IF NOT EXISTS pg_trgm`; | |
| 13 | + await sql`CREATE EXTENSION IF NOT EXISTS unaccent`; | |
| 14 | + const [vec] = await sql`SELECT 1 AS ok FROM pg_available_extensions WHERE name = 'vector'`; | |
| 15 | + if (vec) await sql`CREATE EXTENSION IF NOT EXISTS vector`; | |
| 16 | + else console.warn('[migrate] pgvector not available: embedding columns will fail — install pgvector'); | |
| 17 | + const here = path.dirname(fileURLToPath(import.meta.url)); | |
| 18 | + await migrate(getDb({ max: 1 }), { migrationsFolder: path.resolve(here, '../migrations') }); | |
| 19 | +} | |
| 20 | + | |
| 21 | +const isMain = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url); | |
| 22 | +if (isMain) { | |
| 23 | + runMigrations() | |
| 24 | + .then(async () => { | |
| 25 | + console.log('[migrate] done'); | |
| 26 | + await closeDb(); | |
| 27 | + }) | |
| 28 | + .catch(async (err) => { | |
| 29 | + console.error('[migrate] failed', err); | |
| 30 | + await closeDb(); | |
| 31 | + process.exit(1); | |
| 32 | + }); | |
| 33 | +} | |
added
packages/database/src/schema/_common.ts
+23 −0
@@ -0,0 +1,23 @@ | ||
| 1 | +import { customType, numeric, timestamp, text, jsonb } from 'drizzle-orm/pg-core'; | |
| 2 | +import { sql } from 'drizzle-orm'; | |
| 3 | + | |
| 4 | +/** NUMERIC(18,4) mapped to JS number (values above 2^53 are not expected for collectibles). */ | |
| 5 | +export const money = (name: string) => | |
| 6 | + numeric(name, { precision: 18, scale: 4, mode: 'number' }); | |
| 7 | + | |
| 8 | +export const ratio = (name: string) => numeric(name, { precision: 8, scale: 6, mode: 'number' }); | |
| 9 | + | |
| 10 | +export const ts = (name: string) => timestamp(name, { withTimezone: true, mode: 'date' }); | |
| 11 | + | |
| 12 | +export const createdAt = () => ts('created_at').notNull().defaultNow(); | |
| 13 | +export const updatedAt = () => ts('updated_at').notNull().defaultNow(); | |
| 14 | + | |
| 15 | +export const tsvector = customType<{ data: string }>({ | |
| 16 | + dataType() { | |
| 17 | + return 'tsvector'; | |
| 18 | + }, | |
| 19 | +}); | |
| 20 | + | |
| 21 | +export const textArray = (name: string) => text(name).array().notNull().default(sql`'{}'::text[]`); | |
| 22 | +export const jsonObject = <T extends Record<string, unknown>>(name: string) => jsonb(name).$type<T>().notNull().default(sql`'{}'::jsonb`); | |
| 23 | +export const jsonArray = <T>(name: string) => jsonb(name).$type<T[]>().notNull().default(sql`'[]'::jsonb`); | |
added
packages/database/src/schema/analytics.ts
+168 −0
@@ -0,0 +1,168 @@ | ||
| 1 | +import { pgTable, text, integer, boolean, real, index, uniqueIndex, jsonb, date, primaryKey } from 'drizzle-orm/pg-core'; | |
| 2 | +import { createdAt, ts, money, ratio, jsonObject, textArray } from './_common.js'; | |
| 3 | + | |
| 4 | +/** Full valuation record with method breakdown (§115, §191). */ | |
| 5 | +export const valuations = pgTable( | |
| 6 | + 'valuations', | |
| 7 | + { | |
| 8 | + id: text('id').primaryKey(), | |
| 9 | + assetId: text('asset_id').notNull(), | |
| 10 | + variantId: text('variant_id'), | |
| 11 | + computedAt: ts('computed_at').notNull(), | |
| 12 | + rivUsd: money('riv_usd'), | |
| 13 | + lowUsd: money('low_usd'), | |
| 14 | + highUsd: money('high_usd'), | |
| 15 | + confidence: ratio('confidence').notNull().default(0), | |
| 16 | + confidenceLabel: text('confidence_label').notNull().default('insufficient'), // high | medium | low | insufficient | |
| 17 | + sampleSize: integer('sample_size').notNull().default(0), | |
| 18 | + windowDays: integer('window_days').notNull().default(365), | |
| 19 | + methods: jsonObject<Record<string, number | null>>('methods'), | |
| 20 | + salesUsed: textArray('sales_used'), | |
| 21 | + observationsUsed: integer('observations_used').notNull().default(0), | |
| 22 | + method: text('method').notNull().default('ensemble_v1'), | |
| 23 | + notes: textArray('notes'), | |
| 24 | + }, | |
| 25 | + (t) => [index('valuations_asset_idx').on(t.assetId, t.computedAt), index('valuations_variant_idx').on(t.variantId, t.computedAt)], | |
| 26 | +); | |
| 27 | + | |
| 28 | +/** Daily price series per asset/variant (repeat-sales friendly; §126 charts). */ | |
| 29 | +export const priceSnapshots = pgTable( | |
| 30 | + 'price_snapshots', | |
| 31 | + { | |
| 32 | + assetId: text('asset_id').notNull(), | |
| 33 | + variantId: text('variant_id').notNull().default(''), | |
| 34 | + date: date('date').notNull(), | |
| 35 | + rivUsd: money('riv_usd'), | |
| 36 | + latestSaleUsd: money('latest_sale_usd'), | |
| 37 | + medianUsd: money('median_usd'), | |
| 38 | + salesCount: integer('sales_count').notNull().default(0), | |
| 39 | + volumeUsd: money('volume_usd'), | |
| 40 | + listingsCount: integer('listings_count').notNull().default(0), | |
| 41 | + minAskUsd: money('min_ask_usd'), | |
| 42 | + observationUsd: money('observation_usd'), | |
| 43 | + }, | |
| 44 | + (t) => [primaryKey({ columns: [t.assetId, t.variantId, t.date] }), index('price_snapshots_date_idx').on(t.date)], | |
| 45 | +); | |
| 46 | + | |
| 47 | +/** Index definitions (§3). */ | |
| 48 | +export const indices = pgTable('indices', { | |
| 49 | + id: text('id').primaryKey(), | |
| 50 | + ticker: text('ticker').notNull().unique(), | |
| 51 | + name: text('name').notNull(), | |
| 52 | + description: text('description'), | |
| 53 | + categorySlugs: textArray('category_slugs'), | |
| 54 | + familySlugs: textArray('family_slugs'), | |
| 55 | + parentTicker: text('parent_ticker'), | |
| 56 | + methodology: text('methodology').notNull().default('chain_linked_equal_weight_v1'), | |
| 57 | + weighting: text('weighting').notNull().default('equal'), // equal | liquidity | value | |
| 58 | + baseDate: date('base_date').notNull(), | |
| 59 | + baseValue: real('base_value').notNull().default(1000), | |
| 60 | + minConstituents: integer('min_constituents').notNull().default(10), | |
| 61 | + active: boolean('active').notNull().default(true), | |
| 62 | + isFlagship: boolean('is_flagship').notNull().default(false), | |
| 63 | + color: text('color'), | |
| 64 | + createdAt: createdAt(), | |
| 65 | +}); | |
| 66 | + | |
| 67 | +export const indexValues = pgTable( | |
| 68 | + 'index_values', | |
| 69 | + { | |
| 70 | + indexId: text('index_id').notNull(), | |
| 71 | + date: date('date').notNull(), | |
| 72 | + value: real('value').notNull(), | |
| 73 | + constituentsCount: integer('constituents_count').notNull().default(0), | |
| 74 | + transactions: integer('transactions').notNull().default(0), | |
| 75 | + volumeUsd: money('volume_usd'), | |
| 76 | + medianSaleUsd: money('median_sale_usd'), | |
| 77 | + avgSaleUsd: money('avg_sale_usd'), | |
| 78 | + marketCapEstUsd: money('market_cap_est_usd'), | |
| 79 | + marketCapConfidence: text('market_cap_confidence'), | |
| 80 | + liquidityScore: real('liquidity_score'), | |
| 81 | + momentum: real('momentum'), | |
| 82 | + breadth: integer('breadth'), | |
| 83 | + trackedAssets: integer('tracked_assets'), | |
| 84 | + /** fraction of constituents with a fresh valuation that day */ | |
| 85 | + coverage: real('coverage'), | |
| 86 | + }, | |
| 87 | + (t) => [primaryKey({ columns: [t.indexId, t.date] })], | |
| 88 | +); | |
| 89 | + | |
| 90 | +export const indexConstituents = pgTable( | |
| 91 | + 'index_constituents', | |
| 92 | + { | |
| 93 | + indexId: text('index_id').notNull(), | |
| 94 | + assetId: text('asset_id').notNull(), | |
| 95 | + variantId: text('variant_id').notNull().default(''), | |
| 96 | + weight: real('weight').notNull().default(1), | |
| 97 | + addedAt: date('added_at').notNull(), | |
| 98 | + removedAt: date('removed_at'), | |
| 99 | + reason: text('reason'), | |
| 100 | + }, | |
| 101 | + (t) => [primaryKey({ columns: [t.indexId, t.assetId, t.variantId, t.addedAt] }), index('index_constituents_asset_idx').on(t.assetId)], | |
| 102 | +); | |
| 103 | + | |
| 104 | +/** Category-level daily aggregates for market pages & heatmap (§125, §151). */ | |
| 105 | +export const categorySnapshots = pgTable( | |
| 106 | + 'category_snapshots', | |
| 107 | + { | |
| 108 | + categorySlug: text('category_slug').notNull(), | |
| 109 | + date: date('date').notNull(), | |
| 110 | + indexValue: real('index_value'), | |
| 111 | + trackedAssets: integer('tracked_assets').notNull().default(0), | |
| 112 | + assetsWithValuation: integer('assets_with_valuation').notNull().default(0), | |
| 113 | + sales: integer('sales').notNull().default(0), | |
| 114 | + volumeUsd: money('volume_usd'), | |
| 115 | + medianSaleUsd: money('median_sale_usd'), | |
| 116 | + activeListings: integer('active_listings').notNull().default(0), | |
| 117 | + marketCapEstUsd: money('market_cap_est_usd'), | |
| 118 | + liquidityScore: real('liquidity_score'), | |
| 119 | + change1d: ratio('change_1d'), | |
| 120 | + change7d: ratio('change_7d'), | |
| 121 | + change30d: ratio('change_30d'), | |
| 122 | + change1y: ratio('change_1y'), | |
| 123 | + }, | |
| 124 | + (t) => [primaryKey({ columns: [t.categorySlug, t.date] })], | |
| 125 | +); | |
| 126 | + | |
| 127 | +/** Rare Radar findings (§155) and record sales (§154) are derived views persisted for speed. */ | |
| 128 | +export const radarFindings = pgTable( | |
| 129 | + 'radar_findings', | |
| 130 | + { | |
| 131 | + id: text('id').primaryKey(), | |
| 132 | + assetId: text('asset_id').notNull(), | |
| 133 | + kind: text('kind').notNull(), // first_listing_in_years | ultra_low_population | rare_auction_appearance | price_discrepancy | undocumented_variation | record_sale | |
| 134 | + score: real('score').notNull(), | |
| 135 | + evidence: jsonb('evidence').$type<Record<string, unknown>>().notNull().default({}), | |
| 136 | + entityType: text('entity_type'), | |
| 137 | + entityId: text('entity_id'), | |
| 138 | + detectedAt: ts('detected_at').notNull(), | |
| 139 | + expiresAt: ts('expires_at'), | |
| 140 | + }, | |
| 141 | + (t) => [index('radar_kind_idx').on(t.kind, t.detectedAt), uniqueIndex('radar_entity_uq').on(t.kind, t.entityType, t.entityId)], | |
| 142 | +); | |
| 143 | + | |
| 144 | +/** Correlation matrix cache (§186). */ | |
| 145 | +export const correlations = pgTable( | |
| 146 | + 'correlations', | |
| 147 | + { | |
| 148 | + a: text('a').notNull(), | |
| 149 | + b: text('b').notNull(), | |
| 150 | + windowDays: integer('window_days').notNull(), | |
| 151 | + coefficient: real('coefficient').notNull(), | |
| 152 | + observations: integer('observations').notNull(), | |
| 153 | + computedAt: ts('computed_at').notNull(), | |
| 154 | + }, | |
| 155 | + (t) => [primaryKey({ columns: [t.a, t.b, t.windowDays] })], | |
| 156 | +); | |
| 157 | + | |
| 158 | +/** Benchmark series (S&P 500, gold, BTC, CPI) fetched from official/free datasets (§187). */ | |
| 159 | +export const benchmarks = pgTable( | |
| 160 | + 'benchmarks', | |
| 161 | + { | |
| 162 | + ticker: text('ticker').notNull(), | |
| 163 | + date: date('date').notNull(), | |
| 164 | + value: real('value').notNull(), | |
| 165 | + source: text('source').notNull(), | |
| 166 | + }, | |
| 167 | + (t) => [primaryKey({ columns: [t.ticker, t.date] })], | |
| 168 | +); | |
added
packages/database/src/schema/assets.ts
+216 −0
@@ -0,0 +1,216 @@ | ||
| 1 | +import { pgTable, text, integer, boolean, real, index, uniqueIndex, jsonb, vector } from 'drizzle-orm/pg-core'; | |
| 2 | +import { sql } from 'drizzle-orm'; | |
| 3 | +import { createdAt, updatedAt, ts, money, ratio, jsonObject, textArray, tsvector } from './_common.js'; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * Canonical asset (§109): the collectible object independent of grade/condition. | |
| 7 | + * `canonical_key` is a deterministic normalised key (category|set|number|name|variant|language|year…) | |
| 8 | + * used for entity resolution; `identifiers` hold deterministic external ids. | |
| 9 | + */ | |
| 10 | +export const assets = pgTable( | |
| 11 | + 'assets', | |
| 12 | + { | |
| 13 | + id: text('id').primaryKey(), | |
| 14 | + slug: text('slug').notNull(), | |
| 15 | + canonicalKey: text('canonical_key').notNull(), | |
| 16 | + categorySlug: text('category_slug').notNull(), | |
| 17 | + subcategorySlug: text('subcategory_slug'), | |
| 18 | + familySlug: text('family_slug').notNull(), | |
| 19 | + franchise: text('franchise'), | |
| 20 | + brand: text('brand'), | |
| 21 | + series: text('series'), | |
| 22 | + setSlug: text('set_slug'), | |
| 23 | + setName: text('set_name'), | |
| 24 | + setCode: text('set_code'), | |
| 25 | + name: text('name').notNull(), | |
| 26 | + /** full display title, e.g. "Charizard #4/102 — Base Set 1st Edition Holo (1999)" */ | |
| 27 | + title: text('title').notNull(), | |
| 28 | + model: text('model'), | |
| 29 | + reference: text('reference'), | |
| 30 | + number: text('number'), | |
| 31 | + year: integer('year'), | |
| 32 | + edition: text('edition'), | |
| 33 | + variant: text('variant'), | |
| 34 | + language: text('language'), | |
| 35 | + region: text('region'), | |
| 36 | + country: text('country'), | |
| 37 | + material: text('material'), | |
| 38 | + size: text('size'), | |
| 39 | + color: text('color'), | |
| 40 | + rarity: text('rarity'), | |
| 41 | + productionQuantity: integer('production_quantity'), | |
| 42 | + originalMsrp: money('original_msrp'), | |
| 43 | + originalMsrpCurrency: text('original_msrp_currency'), | |
| 44 | + releaseDate: text('release_date'), | |
| 45 | + description: text('description'), | |
| 46 | + heroImageUrl: text('hero_image_url'), | |
| 47 | + identifiers: jsonObject<Record<string, string>>('identifiers'), | |
| 48 | + metadata: jsonObject<Record<string, unknown>>('metadata'), | |
| 49 | + /** ids of assets merged into this one (audit trail) */ | |
| 50 | + mergedFrom: textArray('merged_from'), | |
| 51 | + /** 0–100 (§150) */ | |
| 52 | + dataQuality: real('data_quality').notNull().default(0), | |
| 53 | + verified: boolean('verified').notNull().default(false), | |
| 54 | + search: tsvector('search').generatedAlwaysAs( | |
| 55 | + (): ReturnType<typeof sql> => | |
| 56 | + sql`setweight(to_tsvector('simple', coalesce(name, '')), 'A') || setweight(to_tsvector('simple', coalesce(set_name, '') || ' ' || coalesce(number, '') || ' ' || coalesce(variant, '') || ' ' || coalesce(edition, '')), 'B') || setweight(to_tsvector('simple', coalesce(brand, '') || ' ' || coalesce(franchise, '') || ' ' || coalesce(reference, '') || ' ' || coalesce(model, '') || ' ' || coalesce(year::text, '') || ' ' || coalesce(category_slug, '')), 'C')`, | |
| 57 | + ), | |
| 58 | + createdAt: createdAt(), | |
| 59 | + updatedAt: updatedAt(), | |
| 60 | + }, | |
| 61 | + (t) => [ | |
| 62 | + uniqueIndex('assets_canonical_key_uq').on(t.canonicalKey), | |
| 63 | + uniqueIndex('assets_slug_uq').on(t.slug), | |
| 64 | + index('assets_category_idx').on(t.categorySlug), | |
| 65 | + index('assets_family_idx').on(t.familySlug), | |
| 66 | + index('assets_set_idx').on(t.setSlug), | |
| 67 | + index('assets_search_gin').using('gin', t.search), | |
| 68 | + index('assets_title_trgm').using('gin', sql`${t.title} gin_trgm_ops`), | |
| 69 | + index('assets_identifiers_gin').using('gin', t.identifiers), | |
| 70 | + ], | |
| 71 | +); | |
| 72 | + | |
| 73 | +/** Grade/condition-specific variant of an asset (PSA 10, CIB, deadstock size 10…) — §112, §117, §118. */ | |
| 74 | +export const assetVariants = pgTable( | |
| 75 | + 'asset_variants', | |
| 76 | + { | |
| 77 | + id: text('id').primaryKey(), | |
| 78 | + assetId: text('asset_id').notNull(), | |
| 79 | + variantKey: text('variant_key').notNull(), // e.g. "psa|10", "raw|near_mint", "sealed", "bgs|9.5|black_label", "size|10" | |
| 80 | + grader: text('grader'), | |
| 81 | + grade: text('grade'), | |
| 82 | + qualifier: text('qualifier'), | |
| 83 | + condition: text('condition'), | |
| 84 | + completeness: text('completeness'), | |
| 85 | + sizeLabel: text('size_label'), | |
| 86 | + label: text('label').notNull(), // human label "PSA 10" | |
| 87 | + isDefault: boolean('is_default').notNull().default(false), | |
| 88 | + createdAt: createdAt(), | |
| 89 | + }, | |
| 90 | + (t) => [uniqueIndex('asset_variants_uq').on(t.assetId, t.variantKey), index('asset_variants_asset_idx').on(t.assetId)], | |
| 91 | +); | |
| 92 | + | |
| 93 | +/** Denormalised, frequently read metrics per asset (rebuilt by valuation/indices workers). */ | |
| 94 | +export const assetStats = pgTable( | |
| 95 | + 'asset_stats', | |
| 96 | + { | |
| 97 | + assetId: text('asset_id').primaryKey(), | |
| 98 | + rivUsd: money('riv_usd'), | |
| 99 | + rivLowUsd: money('riv_low_usd'), | |
| 100 | + rivHighUsd: money('riv_high_usd'), | |
| 101 | + rivConfidence: ratio('riv_confidence'), | |
| 102 | + rivSampleSize: integer('riv_sample_size').notNull().default(0), | |
| 103 | + rivVariantId: text('riv_variant_id'), | |
| 104 | + latestSaleUsd: money('latest_sale_usd'), | |
| 105 | + latestSaleAt: ts('latest_sale_at'), | |
| 106 | + change1d: ratio('change_1d'), | |
| 107 | + change7d: ratio('change_7d'), | |
| 108 | + change30d: ratio('change_30d'), | |
| 109 | + change90d: ratio('change_90d'), | |
| 110 | + change1y: ratio('change_1y'), | |
| 111 | + athUsd: money('ath_usd'), | |
| 112 | + athAt: ts('ath_at'), | |
| 113 | + atlUsd: money('atl_usd'), | |
| 114 | + atlAt: ts('atl_at'), | |
| 115 | + salesCount: integer('sales_count').notNull().default(0), | |
| 116 | + sales30d: integer('sales_30d').notNull().default(0), | |
| 117 | + sales1y: integer('sales_1y').notNull().default(0), | |
| 118 | + volume30dUsd: money('volume_30d_usd'), | |
| 119 | + activeListings: integer('active_listings').notNull().default(0), | |
| 120 | + minAskUsd: money('min_ask_usd'), | |
| 121 | + observationsCount: integer('observations_count').notNull().default(0), | |
| 122 | + sourcesCount: integer('sources_count').notNull().default(0), | |
| 123 | + liquidityScore: real('liquidity_score'), | |
| 124 | + rarityScore: real('rarity_score'), | |
| 125 | + momentum7d: real('momentum_7d'), | |
| 126 | + momentum30d: real('momentum_30d'), | |
| 127 | + momentum90d: real('momentum_90d'), | |
| 128 | + momentum1y: real('momentum_1y'), | |
| 129 | + trendingScore: real('trending_score'), | |
| 130 | + valueOpportunity: real('value_opportunity'), | |
| 131 | + dataQuality: real('data_quality'), | |
| 132 | + watchers: integer('watchers').notNull().default(0), | |
| 133 | + views30d: integer('views_30d').notNull().default(0), | |
| 134 | + updatedAt: updatedAt(), | |
| 135 | + }, | |
| 136 | + (t) => [index('asset_stats_riv_idx').on(t.rivUsd), index('asset_stats_trending_idx').on(t.trendingScore), index('asset_stats_liquidity_idx').on(t.liquidityScore)], | |
| 137 | +); | |
| 138 | + | |
| 139 | +export const variantStats = pgTable('variant_stats', { | |
| 140 | + variantId: text('variant_id').primaryKey(), | |
| 141 | + assetId: text('asset_id').notNull(), | |
| 142 | + rivUsd: money('riv_usd'), | |
| 143 | + rivLowUsd: money('riv_low_usd'), | |
| 144 | + rivHighUsd: money('riv_high_usd'), | |
| 145 | + rivConfidence: ratio('riv_confidence'), | |
| 146 | + rivSampleSize: integer('riv_sample_size').notNull().default(0), | |
| 147 | + latestSaleUsd: money('latest_sale_usd'), | |
| 148 | + latestSaleAt: ts('latest_sale_at'), | |
| 149 | + change30d: ratio('change_30d'), | |
| 150 | + change1y: ratio('change_1y'), | |
| 151 | + salesCount: integer('sales_count').notNull().default(0), | |
| 152 | + sales30d: integer('sales_30d').notNull().default(0), | |
| 153 | + activeListings: integer('active_listings').notNull().default(0), | |
| 154 | + minAskUsd: money('min_ask_usd'), | |
| 155 | + liquidityScore: real('liquidity_score'), | |
| 156 | + updatedAt: updatedAt(), | |
| 157 | +}); | |
| 158 | + | |
| 159 | +export const images = pgTable( | |
| 160 | + 'images', | |
| 161 | + { | |
| 162 | + id: text('id').primaryKey(), | |
| 163 | + assetId: text('asset_id'), | |
| 164 | + listingId: text('listing_id'), | |
| 165 | + saleId: text('sale_id'), | |
| 166 | + sourceId: text('source_id'), | |
| 167 | + url: text('url').notNull(), | |
| 168 | + role: text('role').notNull().default('gallery'), // hero | gallery | source | |
| 169 | + width: integer('width'), | |
| 170 | + height: integer('height'), | |
| 171 | + phash: text('phash'), | |
| 172 | + embedding: vector('embedding', { dimensions: 512 }), | |
| 173 | + attribution: text('attribution'), | |
| 174 | + createdAt: createdAt(), | |
| 175 | + }, | |
| 176 | + (t) => [index('images_asset_idx').on(t.assetId), index('images_phash_idx').on(t.phash), uniqueIndex('images_url_uq').on(t.url)], | |
| 177 | +); | |
| 178 | + | |
| 179 | +/** Text embeddings for hybrid search / entity resolution (§112, §138). */ | |
| 180 | +export const assetEmbeddings = pgTable('asset_embeddings', { | |
| 181 | + assetId: text('asset_id').primaryKey(), | |
| 182 | + model: text('model').notNull(), | |
| 183 | + embedding: vector('embedding', { dimensions: 1536 }).notNull(), | |
| 184 | + updatedAt: updatedAt(), | |
| 185 | +}); | |
| 186 | + | |
| 187 | +export const populationReports = pgTable( | |
| 188 | + 'population_reports', | |
| 189 | + { | |
| 190 | + id: text('id').primaryKey(), | |
| 191 | + assetId: text('asset_id').notNull(), | |
| 192 | + grader: text('grader').notNull(), | |
| 193 | + sourceId: text('source_id').notNull(), | |
| 194 | + sourceUrl: text('source_url'), | |
| 195 | + reportDate: text('report_date').notNull(), | |
| 196 | + total: integer('total').notNull(), | |
| 197 | + byGrade: jsonb('by_grade').$type<Record<string, number>>().notNull(), | |
| 198 | + createdAt: createdAt(), | |
| 199 | + }, | |
| 200 | + (t) => [uniqueIndex('population_reports_uq').on(t.assetId, t.grader, t.reportDate)], | |
| 201 | +); | |
| 202 | + | |
| 203 | +/** Empirical grade premiums (§118). */ | |
| 204 | +export const gradePremiums = pgTable( | |
| 205 | + 'grade_premiums', | |
| 206 | + { | |
| 207 | + id: text('id').primaryKey(), | |
| 208 | + categorySlug: text('category_slug').notNull(), | |
| 209 | + grader: text('grader').notNull(), | |
| 210 | + grade: text('grade').notNull(), | |
| 211 | + marketMultiplier: real('market_multiplier').notNull(), | |
| 212 | + sampleSize: integer('sample_size').notNull(), | |
| 213 | + computedAt: ts('computed_at').notNull(), | |
| 214 | + }, | |
| 215 | + (t) => [uniqueIndex('grade_premiums_uq').on(t.categorySlug, t.grader, t.grade)], | |
| 216 | +); | |
added
packages/database/src/schema/index.ts
+7 −0
@@ -0,0 +1,7 @@ | ||
| 1 | +export * from './taxonomy.js'; | |
| 2 | +export * from './sources.js'; | |
| 3 | +export * from './ingestion.js'; | |
| 4 | +export * from './assets.js'; | |
| 5 | +export * from './market.js'; | |
| 6 | +export * from './analytics.js'; | |
| 7 | +export * from './users.js'; | |
added
packages/database/src/schema/ingestion.ts
+94 −0
@@ -0,0 +1,94 @@ | ||
| 1 | +import { pgTable, text, integer, index, uniqueIndex, jsonb } from 'drizzle-orm/pg-core'; | |
| 2 | +import { createdAt, ts, ratio } from './_common.js'; | |
| 3 | + | |
| 4 | +/** | |
| 5 | + * Immutable raw capture (§108, §142). Rows are never updated except `processed_at`/`process_error` | |
| 6 | + * bookkeeping columns. Payload is the parsed source payload (JSON from API, or extracted fields); | |
| 7 | + * large HTML snapshots live in RI_DATA_DIR/raw/<connector>/<hash>.html referenced by snapshot_ref. | |
| 8 | + */ | |
| 9 | +export const rawRecords = pgTable( | |
| 10 | + 'raw_records', | |
| 11 | + { | |
| 12 | + id: text('id').primaryKey(), | |
| 13 | + connectorId: text('connector_id').notNull(), | |
| 14 | + sourceId: text('source_id').notNull(), | |
| 15 | + runId: text('run_id'), | |
| 16 | + engine: text('engine').notNull(), | |
| 17 | + url: text('url').notNull(), | |
| 18 | + externalId: text('external_id'), | |
| 19 | + kind: text('kind').notNull(), | |
| 20 | + fetchedAt: ts('fetched_at').notNull(), | |
| 21 | + contentHash: text('content_hash').notNull(), | |
| 22 | + httpStatus: integer('http_status'), | |
| 23 | + payload: jsonb('payload').notNull(), | |
| 24 | + snapshotRef: text('snapshot_ref'), | |
| 25 | + parserVersion: text('parser_version').notNull(), | |
| 26 | + connectorVersion: text('connector_version').notNull(), | |
| 27 | + processedAt: ts('processed_at'), | |
| 28 | + processError: text('process_error'), | |
| 29 | + createdAt: createdAt(), | |
| 30 | + }, | |
| 31 | + (t) => [ | |
| 32 | + uniqueIndex('raw_records_connector_hash_uq').on(t.connectorId, t.contentHash), | |
| 33 | + index('raw_records_connector_fetched_idx').on(t.connectorId, t.fetchedAt), | |
| 34 | + index('raw_records_unprocessed_idx').on(t.processedAt), | |
| 35 | + index('raw_records_external_idx').on(t.connectorId, t.externalId), | |
| 36 | + ], | |
| 37 | +); | |
| 38 | + | |
| 39 | +/** Staging between normalisation and canonical tables; keeps the match decision auditable (§112). */ | |
| 40 | +export const normalizedRecords = pgTable( | |
| 41 | + 'normalized_records', | |
| 42 | + { | |
| 43 | + id: text('id').primaryKey(), | |
| 44 | + rawRecordId: text('raw_record_id').notNull(), | |
| 45 | + connectorId: text('connector_id').notNull(), | |
| 46 | + sourceId: text('source_id').notNull(), | |
| 47 | + kind: text('kind').notNull(), | |
| 48 | + payload: jsonb('payload').notNull(), | |
| 49 | + assetId: text('asset_id'), | |
| 50 | + variantId: text('variant_id'), | |
| 51 | + matchMethod: text('match_method'), // identifier | canonical_key | fuzzy | embedding | llm | manual | |
| 52 | + matchConfidence: ratio('match_confidence'), | |
| 53 | + status: text('status').notNull().default('pending'), // pending | matched | unmatched | rejected | applied | |
| 54 | + rejectReason: text('reject_reason'), | |
| 55 | + targetId: text('target_id'), // resulting sale/listing/observation id | |
| 56 | + createdAt: createdAt(), | |
| 57 | + processedAt: ts('processed_at'), | |
| 58 | + }, | |
| 59 | + (t) => [ | |
| 60 | + index('normalized_records_status_idx').on(t.status, t.createdAt), | |
| 61 | + index('normalized_records_asset_idx').on(t.assetId), | |
| 62 | + uniqueIndex('normalized_records_raw_uq').on(t.rawRecordId), | |
| 63 | + ], | |
| 64 | +); | |
| 65 | + | |
| 66 | +/** Pipeline/event log (§140). Queue itself is pg-boss; this is the durable domain event stream. */ | |
| 67 | +export const events = pgTable( | |
| 68 | + 'events', | |
| 69 | + { | |
| 70 | + id: text('id').primaryKey(), | |
| 71 | + type: text('type').notNull(), // page_discovered | page_crawled | listing_created | listing_updated | sale_detected | entity_matched | valuation_updated | index_updated | |
| 72 | + entityType: text('entity_type'), | |
| 73 | + entityId: text('entity_id'), | |
| 74 | + payload: jsonb('payload').$type<Record<string, unknown>>().notNull().default({}), | |
| 75 | + createdAt: createdAt(), | |
| 76 | + }, | |
| 77 | + (t) => [index('events_type_created_idx').on(t.type, t.createdAt), index('events_entity_idx').on(t.entityType, t.entityId)], | |
| 78 | +); | |
| 79 | + | |
| 80 | +/** Audit log — never silently delete or alter data (§116). */ | |
| 81 | +export const auditLog = pgTable( | |
| 82 | + 'audit_log', | |
| 83 | + { | |
| 84 | + id: text('id').primaryKey(), | |
| 85 | + entityType: text('entity_type').notNull(), | |
| 86 | + entityId: text('entity_id').notNull(), | |
| 87 | + action: text('action').notNull(), // flagged | excluded | restored | merged | edited | rejected | |
| 88 | + reason: text('reason').notNull(), | |
| 89 | + actor: text('actor').notNull().default('system'), | |
| 90 | + details: jsonb('details').$type<Record<string, unknown>>().notNull().default({}), | |
| 91 | + createdAt: createdAt(), | |
| 92 | + }, | |
| 93 | + (t) => [index('audit_entity_idx').on(t.entityType, t.entityId)], | |
| 94 | +); | |
added
packages/database/src/schema/market.ts
+230 −0
@@ -0,0 +1,230 @@ | ||
| 1 | +import { pgTable, text, integer, boolean, real, index, uniqueIndex, jsonb, date } from 'drizzle-orm/pg-core'; | |
| 2 | +import { createdAt, updatedAt, ts, money, ratio, jsonObject, textArray } from './_common.js'; | |
| 3 | + | |
| 4 | +/** Verified/observed transactions (§110). Prices keep native currency + USD at historical FX (§136). */ | |
| 5 | +export const sales = pgTable( | |
| 6 | + 'sales', | |
| 7 | + { | |
| 8 | + id: text('id').primaryKey(), | |
| 9 | + assetId: text('asset_id').notNull(), | |
| 10 | + variantId: text('variant_id'), | |
| 11 | + sourceId: text('source_id').notNull(), | |
| 12 | + connectorId: text('connector_id').notNull(), | |
| 13 | + rawRecordId: text('raw_record_id'), | |
| 14 | + normalizedRecordId: text('normalized_record_id'), | |
| 15 | + sourceUrl: text('source_url').notNull(), | |
| 16 | + externalId: text('external_id'), | |
| 17 | + saleType: text('sale_type').notNull().default('unknown'), | |
| 18 | + saleDate: ts('sale_date').notNull(), | |
| 19 | + price: money('price').notNull(), | |
| 20 | + currency: text('currency').notNull(), | |
| 21 | + priceUsd: money('price_usd').notNull(), | |
| 22 | + fxRate: real('fx_rate'), | |
| 23 | + fxDate: date('fx_date'), | |
| 24 | + buyerPremiumIncluded: boolean('buyer_premium_included'), | |
| 25 | + quantity: integer('quantity').notNull().default(1), | |
| 26 | + isBundle: boolean('is_bundle').notNull().default(false), | |
| 27 | + condition: text('condition'), | |
| 28 | + grader: text('grader'), | |
| 29 | + grade: text('grade'), | |
| 30 | + certificationNumber: text('certification_number'), | |
| 31 | + location: text('location'), | |
| 32 | + auctionHouse: text('auction_house'), | |
| 33 | + lotNumber: text('lot_number'), | |
| 34 | + imageUrls: jsonb('image_urls').$type<string[]>().notNull().default([]), | |
| 35 | + rawTitle: text('raw_title').notNull(), | |
| 36 | + confidence: ratio('confidence').notNull().default(0.8), | |
| 37 | + dataQuality: real('data_quality').notNull().default(0), | |
| 38 | + /** valid | flagged | excluded (never deleted, §116) */ | |
| 39 | + status: text('status').notNull().default('valid'), | |
| 40 | + flags: textArray('flags'), | |
| 41 | + dedupeKey: text('dedupe_key').notNull(), | |
| 42 | + createdAt: createdAt(), | |
| 43 | + }, | |
| 44 | + (t) => [ | |
| 45 | + uniqueIndex('sales_dedupe_uq').on(t.dedupeKey), | |
| 46 | + index('sales_asset_date_idx').on(t.assetId, t.saleDate), | |
| 47 | + index('sales_variant_date_idx').on(t.variantId, t.saleDate), | |
| 48 | + index('sales_source_idx').on(t.sourceId, t.saleDate), | |
| 49 | + index('sales_date_idx').on(t.saleDate), | |
| 50 | + index('sales_price_idx').on(t.priceUsd), | |
| 51 | + ], | |
| 52 | +); | |
| 53 | + | |
| 54 | +/** Current and historical listings (§111). Listing price is never treated as market value. */ | |
| 55 | +export const listings = pgTable( | |
| 56 | + 'listings', | |
| 57 | + { | |
| 58 | + id: text('id').primaryKey(), | |
| 59 | + assetId: text('asset_id').notNull(), | |
| 60 | + variantId: text('variant_id'), | |
| 61 | + sourceId: text('source_id').notNull(), | |
| 62 | + connectorId: text('connector_id').notNull(), | |
| 63 | + rawRecordId: text('raw_record_id'), | |
| 64 | + sourceUrl: text('source_url').notNull(), | |
| 65 | + externalId: text('external_id').notNull(), | |
| 66 | + listingType: text('listing_type').notNull().default('unknown'), | |
| 67 | + price: money('price'), | |
| 68 | + currency: text('currency'), | |
| 69 | + priceUsd: money('price_usd'), | |
| 70 | + seller: text('seller'), | |
| 71 | + sellerReputation: text('seller_reputation'), | |
| 72 | + location: text('location'), | |
| 73 | + shippingCost: money('shipping_cost'), | |
| 74 | + quantity: integer('quantity'), | |
| 75 | + condition: text('condition'), | |
| 76 | + grader: text('grader'), | |
| 77 | + grade: text('grade'), | |
| 78 | + certificationNumber: text('certification_number'), | |
| 79 | + imageUrls: jsonb('image_urls').$type<string[]>().notNull().default([]), | |
| 80 | + rawTitle: text('raw_title').notNull(), | |
| 81 | + description: text('description'), | |
| 82 | + listedAt: ts('listed_at'), | |
| 83 | + endsAt: ts('ends_at'), | |
| 84 | + availability: text('availability').notNull().default('available'), | |
| 85 | + bidCount: integer('bid_count'), | |
| 86 | + firstSeenAt: ts('first_seen_at').notNull(), | |
| 87 | + lastSeenAt: ts('last_seen_at').notNull(), | |
| 88 | + priceChangedAt: ts('price_changed_at'), | |
| 89 | + crossListingGroupId: text('cross_listing_group_id'), | |
| 90 | + confidence: ratio('confidence').notNull().default(0.8), | |
| 91 | + dataQuality: real('data_quality').notNull().default(0), | |
| 92 | + flags: textArray('flags'), | |
| 93 | + /** value opportunity vs RIV, computed (§123) */ | |
| 94 | + discountToRiv: ratio('discount_to_riv'), | |
| 95 | + createdAt: createdAt(), | |
| 96 | + updatedAt: updatedAt(), | |
| 97 | + }, | |
| 98 | + (t) => [ | |
| 99 | + uniqueIndex('listings_source_external_uq').on(t.sourceId, t.externalId), | |
| 100 | + index('listings_asset_avail_idx').on(t.assetId, t.availability), | |
| 101 | + index('listings_avail_price_idx').on(t.availability, t.priceUsd), | |
| 102 | + index('listings_ends_idx').on(t.endsAt), | |
| 103 | + index('listings_last_seen_idx').on(t.lastSeenAt), | |
| 104 | + ], | |
| 105 | +); | |
| 106 | + | |
| 107 | +export const listingEvents = pgTable( | |
| 108 | + 'listing_events', | |
| 109 | + { | |
| 110 | + id: text('id').primaryKey(), | |
| 111 | + listingId: text('listing_id').notNull(), | |
| 112 | + eventType: text('event_type').notNull(), // new | price_changed | sold | removed | relisted | auction_ended | |
| 113 | + oldPrice: money('old_price'), | |
| 114 | + newPrice: money('new_price'), | |
| 115 | + currency: text('currency'), | |
| 116 | + occurredAt: ts('occurred_at').notNull(), | |
| 117 | + }, | |
| 118 | + (t) => [index('listing_events_listing_idx').on(t.listingId, t.occurredAt)], | |
| 119 | +); | |
| 120 | + | |
| 121 | +export const auctions = pgTable( | |
| 122 | + 'auctions', | |
| 123 | + { | |
| 124 | + id: text('id').primaryKey(), | |
| 125 | + sourceId: text('source_id').notNull(), | |
| 126 | + auctionHouse: text('auction_house').notNull(), | |
| 127 | + name: text('name').notNull(), | |
| 128 | + url: text('url').notNull(), | |
| 129 | + startsAt: ts('starts_at'), | |
| 130 | + endsAt: ts('ends_at'), | |
| 131 | + location: text('location'), | |
| 132 | + categorySlugs: textArray('category_slugs'), | |
| 133 | + lotCount: integer('lot_count'), | |
| 134 | + status: text('status').notNull().default('upcoming'), // upcoming | live | ended | |
| 135 | + currency: text('currency'), | |
| 136 | + createdAt: createdAt(), | |
| 137 | + updatedAt: updatedAt(), | |
| 138 | + }, | |
| 139 | + (t) => [uniqueIndex('auctions_url_uq').on(t.url), index('auctions_ends_idx').on(t.endsAt)], | |
| 140 | +); | |
| 141 | + | |
| 142 | +export const auctionLots = pgTable( | |
| 143 | + 'auction_lots', | |
| 144 | + { | |
| 145 | + id: text('id').primaryKey(), | |
| 146 | + auctionId: text('auction_id').notNull(), | |
| 147 | + assetId: text('asset_id'), | |
| 148 | + variantId: text('variant_id'), | |
| 149 | + sourceId: text('source_id').notNull(), | |
| 150 | + lotNumber: text('lot_number'), | |
| 151 | + title: text('title').notNull(), | |
| 152 | + url: text('url').notNull(), | |
| 153 | + estimateLow: money('estimate_low'), | |
| 154 | + estimateHigh: money('estimate_high'), | |
| 155 | + currentBid: money('current_bid'), | |
| 156 | + hammerPrice: money('hammer_price'), | |
| 157 | + currency: text('currency'), | |
| 158 | + bidCount: integer('bid_count'), | |
| 159 | + startsAt: ts('starts_at'), | |
| 160 | + endsAt: ts('ends_at'), | |
| 161 | + status: text('status').notNull().default('upcoming'), | |
| 162 | + imageUrls: jsonb('image_urls').$type<string[]>().notNull().default([]), | |
| 163 | + grader: text('grader'), | |
| 164 | + grade: text('grade'), | |
| 165 | + createdAt: createdAt(), | |
| 166 | + updatedAt: updatedAt(), | |
| 167 | + }, | |
| 168 | + (t) => [uniqueIndex('auction_lots_url_uq').on(t.url), index('auction_lots_auction_idx').on(t.auctionId), index('auction_lots_asset_idx').on(t.assetId), index('auction_lots_ends_idx').on(t.endsAt)], | |
| 169 | +); | |
| 170 | + | |
| 171 | +/** Price-guide observations (market/low/mid/high) — informative, weighted below transactions. */ | |
| 172 | +export const priceObservations = pgTable( | |
| 173 | + 'price_observations', | |
| 174 | + { | |
| 175 | + id: text('id').primaryKey(), | |
| 176 | + assetId: text('asset_id').notNull(), | |
| 177 | + variantId: text('variant_id'), | |
| 178 | + sourceId: text('source_id').notNull(), | |
| 179 | + connectorId: text('connector_id').notNull(), | |
| 180 | + rawRecordId: text('raw_record_id'), | |
| 181 | + sourceUrl: text('source_url').notNull(), | |
| 182 | + priceKind: text('price_kind').notNull(), | |
| 183 | + price: money('price').notNull(), | |
| 184 | + currency: text('currency').notNull(), | |
| 185 | + priceUsd: money('price_usd').notNull(), | |
| 186 | + observationDate: date('observation_date').notNull(), | |
| 187 | + sampleSize: integer('sample_size'), | |
| 188 | + dedupeKey: text('dedupe_key').notNull(), | |
| 189 | + createdAt: createdAt(), | |
| 190 | + }, | |
| 191 | + (t) => [uniqueIndex('price_observations_dedupe_uq').on(t.dedupeKey), index('price_observations_asset_date_idx').on(t.assetId, t.observationDate)], | |
| 192 | +); | |
| 193 | + | |
| 194 | +export const crossListingGroups = pgTable('cross_listing_groups', { | |
| 195 | + id: text('id').primaryKey(), | |
| 196 | + assetId: text('asset_id'), | |
| 197 | + signals: jsonObject<Record<string, unknown>>('signals'), | |
| 198 | + createdAt: createdAt(), | |
| 199 | +}); | |
| 200 | + | |
| 201 | +/** Daily FX rates from an official dataset (ECB via frankfurter); base USD (§136). */ | |
| 202 | +export const fxRates = pgTable( | |
| 203 | + 'fx_rates', | |
| 204 | + { | |
| 205 | + date: date('date').notNull(), | |
| 206 | + base: text('base').notNull(), | |
| 207 | + quote: text('quote').notNull(), | |
| 208 | + rate: real('rate').notNull(), | |
| 209 | + source: text('source').notNull().default('ecb'), | |
| 210 | + }, | |
| 211 | + (t) => [uniqueIndex('fx_rates_uq').on(t.date, t.base, t.quote)], | |
| 212 | +); | |
| 213 | + | |
| 214 | +export const news = pgTable( | |
| 215 | + 'news', | |
| 216 | + { | |
| 217 | + id: text('id').primaryKey(), | |
| 218 | + sourceId: text('source_id').notNull(), | |
| 219 | + url: text('url').notNull(), | |
| 220 | + title: text('title').notNull(), | |
| 221 | + summary: text('summary'), | |
| 222 | + aiSummary: text('ai_summary'), | |
| 223 | + publishedAt: ts('published_at'), | |
| 224 | + categorySlugs: textArray('category_slugs'), | |
| 225 | + newsType: text('news_type'), // auction_results | record_sales | grading | releases | trends | discoveries | events | |
| 226 | + imageUrl: text('image_url'), | |
| 227 | + fetchedAt: ts('fetched_at').notNull(), | |
| 228 | + }, | |
| 229 | + (t) => [uniqueIndex('news_url_uq').on(t.url), index('news_published_idx').on(t.publishedAt)], | |
| 230 | +); | |
added
packages/database/src/schema/sources.ts
+127 −0
@@ -0,0 +1,127 @@ | ||
| 1 | +import { pgTable, text, integer, boolean, real, index, jsonb } from 'drizzle-orm/pg-core'; | |
| 2 | +import { createdAt, updatedAt, ts, jsonObject, textArray, ratio } from './_common.js'; | |
| 3 | + | |
| 4 | +/** A data source (marketplace, auction house, price guide…) — §107, §143. */ | |
| 5 | +export const sources = pgTable('sources', { | |
| 6 | + id: text('id').primaryKey(), // slug-like, e.g. "scryfall", "psa" | |
| 7 | + name: text('name').notNull(), | |
| 8 | + sourceType: text('source_type').notNull(), | |
| 9 | + url: text('url'), | |
| 10 | + countries: textArray('countries'), | |
| 11 | + languages: textArray('languages'), | |
| 12 | + currencies: textArray('currencies'), | |
| 13 | + /** 0–1 (§143) */ | |
| 14 | + trustScore: ratio('trust_score').notNull().default(0.5), | |
| 15 | + trustFactors: jsonObject<Record<string, number>>('trust_factors'), | |
| 16 | + attributionRequired: boolean('attribution_required').notNull().default(true), | |
| 17 | + termsUrl: text('terms_url'), | |
| 18 | + active: boolean('active').notNull().default(true), | |
| 19 | + createdAt: createdAt(), | |
| 20 | + updatedAt: updatedAt(), | |
| 21 | +}); | |
| 22 | + | |
| 23 | +/** Connector registry mirror (connectors/registry.json is the source of truth for metadata; DB holds state). */ | |
| 24 | +export const connectors = pgTable('connectors', { | |
| 25 | + id: text('id').primaryKey(), | |
| 26 | + sourceId: text('source_id').notNull(), | |
| 27 | + displayName: text('display_name').notNull(), | |
| 28 | + enginePriority: textArray('engine_priority'), | |
| 29 | + categories: textArray('categories'), | |
| 30 | + regions: textArray('regions'), | |
| 31 | + languages: textArray('languages'), | |
| 32 | + currency: textArray('currency'), | |
| 33 | + supportsListings: boolean('supports_listings').notNull().default(false), | |
| 34 | + supportsSold: boolean('supports_sold').notNull().default(false), | |
| 35 | + supportsAuctions: boolean('supports_auctions').notNull().default(false), | |
| 36 | + supportsImages: boolean('supports_images').notNull().default(true), | |
| 37 | + supportsCatalog: boolean('supports_catalog').notNull().default(false), | |
| 38 | + supportsPopulation: boolean('supports_population').notNull().default(false), | |
| 39 | + refreshFrequencyMinutes: integer('refresh_frequency_minutes').notNull().default(1440), | |
| 40 | + priority: text('priority').notNull().default('medium'), // high | medium | low (§141) | |
| 41 | + status: text('status').notNull().default('active'), // active | paused | disabled | |
| 42 | + schemaVersion: text('schema_version').notNull().default('1.0'), | |
| 43 | + connectorVersion: text('connector_version').notNull().default('1.0.0'), | |
| 44 | + config: jsonObject<Record<string, unknown>>('config'), | |
| 45 | + lastRunAt: ts('last_run_at'), | |
| 46 | + lastSuccessAt: ts('last_success_at'), | |
| 47 | + nextRunAt: ts('next_run_at'), | |
| 48 | + createdAt: createdAt(), | |
| 49 | + updatedAt: updatedAt(), | |
| 50 | +}); | |
| 51 | + | |
| 52 | +export const connectorRuns = pgTable( | |
| 53 | + 'connector_runs', | |
| 54 | + { | |
| 55 | + id: text('id').primaryKey(), | |
| 56 | + connectorId: text('connector_id').notNull(), | |
| 57 | + trigger: text('trigger').notNull().default('schedule'), // schedule | manual | backfill | repair | |
| 58 | + startedAt: ts('started_at').notNull(), | |
| 59 | + finishedAt: ts('finished_at'), | |
| 60 | + status: text('status').notNull().default('running'), // running | success | partial | failed | |
| 61 | + pagesAttempted: integer('pages_attempted').notNull().default(0), | |
| 62 | + pagesSuccess: integer('pages_success').notNull().default(0), | |
| 63 | + recordsRaw: integer('records_raw').notNull().default(0), | |
| 64 | + recordsNormalized: integer('records_normalized').notNull().default(0), | |
| 65 | + recordsDuplicate: integer('records_duplicate').notNull().default(0), | |
| 66 | + recordsRejected: integer('records_rejected').notNull().default(0), | |
| 67 | + /** per engine: {firecrawl:{attempts,success,credits}, scrapfly:{…}} */ | |
| 68 | + engineStats: jsonObject<Record<string, { attempts: number; success: number; credits: number; ms: number }>>('engine_stats'), | |
| 69 | + anomalies: jsonb('anomalies').$type<string[]>().notNull().default([]), | |
| 70 | + error: text('error'), | |
| 71 | + costCredits: real('cost_credits').notNull().default(0), | |
| 72 | + costUsdEst: real('cost_usd_est').notNull().default(0), | |
| 73 | + cursor: jsonObject<Record<string, unknown>>('cursor'), | |
| 74 | + }, | |
| 75 | + (t) => [index('connector_runs_connector_started_idx').on(t.connectorId, t.startedAt)], | |
| 76 | +); | |
| 77 | + | |
| 78 | +/** Latest computed health snapshot per connector (§105). */ | |
| 79 | +export const connectorHealth = pgTable('connector_health', { | |
| 80 | + connectorId: text('connector_id').primaryKey(), | |
| 81 | + computedAt: ts('computed_at').notNull(), | |
| 82 | + status: text('status').notNull(), | |
| 83 | + health: jsonObject<Record<string, unknown>>('health'), | |
| 84 | +}); | |
| 85 | + | |
| 86 | +/** Per-URL crawl budget state (§170). */ | |
| 87 | +export const crawlState = pgTable( | |
| 88 | + 'crawl_state', | |
| 89 | + { | |
| 90 | + urlHash: text('url_hash').primaryKey(), | |
| 91 | + connectorId: text('connector_id').notNull(), | |
| 92 | + url: text('url').notNull(), | |
| 93 | + etag: text('etag'), | |
| 94 | + lastModified: text('last_modified'), | |
| 95 | + contentHash: text('content_hash'), | |
| 96 | + lastFetchedAt: ts('last_fetched_at'), | |
| 97 | + lastChangedAt: ts('last_changed_at'), | |
| 98 | + fetchCount: integer('fetch_count').notNull().default(0), | |
| 99 | + changeCount: integer('change_count').notNull().default(0), | |
| 100 | + /** estimated hours between changes */ | |
| 101 | + changeIntervalHours: real('change_interval_hours'), | |
| 102 | + nextFetchAt: ts('next_fetch_at'), | |
| 103 | + lastStatus: integer('last_status'), | |
| 104 | + failures: integer('failures').notNull().default(0), | |
| 105 | + }, | |
| 106 | + (t) => [index('crawl_state_next_idx').on(t.connectorId, t.nextFetchAt)], | |
| 107 | +); | |
| 108 | + | |
| 109 | +/** Cost ledger for crawlers and AI (§169). */ | |
| 110 | +export const costs = pgTable( | |
| 111 | + 'costs', | |
| 112 | + { | |
| 113 | + id: text('id').primaryKey(), | |
| 114 | + occurredAt: ts('occurred_at').notNull(), | |
| 115 | + kind: text('kind').notNull(), // firecrawl | scrapfly | ai | storage | |
| 116 | + provider: text('provider'), | |
| 117 | + connectorId: text('connector_id'), | |
| 118 | + categorySlug: text('category_slug'), | |
| 119 | + endpoint: text('endpoint'), | |
| 120 | + userId: text('user_id'), | |
| 121 | + units: real('units').notNull().default(1), | |
| 122 | + credits: real('credits').notNull().default(0), | |
| 123 | + usdEst: real('usd_est').notNull().default(0), | |
| 124 | + metadata: jsonObject<Record<string, unknown>>('metadata'), | |
| 125 | + }, | |
| 126 | + (t) => [index('costs_occurred_idx').on(t.occurredAt), index('costs_connector_idx').on(t.connectorId)], | |
| 127 | +); | |
added
packages/database/src/schema/taxonomy.ts
+106 −0
@@ -0,0 +1,106 @@ | ||
| 1 | +import { pgTable, text, integer, boolean, index, uniqueIndex } from 'drizzle-orm/pg-core'; | |
| 2 | +import { createdAt, updatedAt, jsonObject, textArray } from './_common.js'; | |
| 3 | + | |
| 4 | +/** | |
| 5 | + * Extensible taxonomy (CLAUDE.md §4, §101). Rows are seeded from data/taxonomy/*.json and can be | |
| 6 | + * extended at runtime through approved taxonomy_proposals. Never hardcode categories in app code. | |
| 7 | + */ | |
| 8 | +export const categories = pgTable( | |
| 9 | + 'categories', | |
| 10 | + { | |
| 11 | + slug: text('slug').primaryKey(), | |
| 12 | + parentSlug: text('parent_slug'), | |
| 13 | + /** top-level family slug (e.g. trading_cards) for fast grouping */ | |
| 14 | + familySlug: text('family_slug').notNull(), | |
| 15 | + name: text('name').notNull(), | |
| 16 | + shortName: text('short_name'), | |
| 17 | + description: text('description'), | |
| 18 | + level: integer('level').notNull().default(0), | |
| 19 | + /** 1 = launch wedge, 2, 3 = later phases (§180–182) */ | |
| 20 | + phase: integer('phase').notNull().default(3), | |
| 21 | + active: boolean('active').notNull().default(true), | |
| 22 | + /** slug of the condition scale in data/taxonomy/conditions.json */ | |
| 23 | + conditionScale: text('condition_scale'), | |
| 24 | + /** grader slugs relevant to this category */ | |
| 25 | + graders: textArray('graders'), | |
| 26 | + /** subindex ticker this category rolls into (e.g. RARE-TCG) */ | |
| 27 | + indexTicker: text('index_ticker'), | |
| 28 | + /** JSON schema fragment describing category-specific attributes */ | |
| 29 | + attributeSchema: jsonObject<Record<string, unknown>>('attribute_schema'), | |
| 30 | + sortOrder: integer('sort_order').notNull().default(0), | |
| 31 | + /** compliance flags: e.g. ["jurisdiction_check", "neutral_presentation"] */ | |
| 32 | + complianceFlags: textArray('compliance_flags'), | |
| 33 | + icon: text('icon'), | |
| 34 | + createdAt: createdAt(), | |
| 35 | + updatedAt: updatedAt(), | |
| 36 | + }, | |
| 37 | + (t) => [index('categories_parent_idx').on(t.parentSlug), index('categories_family_idx').on(t.familySlug)], | |
| 38 | +); | |
| 39 | + | |
| 40 | +export const brands = pgTable( | |
| 41 | + 'brands', | |
| 42 | + { | |
| 43 | + slug: text('slug').primaryKey(), | |
| 44 | + name: text('name').notNull(), | |
| 45 | + categorySlugs: textArray('category_slugs'), | |
| 46 | + country: text('country'), | |
| 47 | + foundedYear: integer('founded_year'), | |
| 48 | + metadata: jsonObject<Record<string, unknown>>('metadata'), | |
| 49 | + createdAt: createdAt(), | |
| 50 | + }, | |
| 51 | + (t) => [index('brands_name_idx').on(t.name)], | |
| 52 | +); | |
| 53 | + | |
| 54 | +export const franchises = pgTable('franchises', { | |
| 55 | + slug: text('slug').primaryKey(), | |
| 56 | + name: text('name').notNull(), | |
| 57 | + owner: text('owner'), | |
| 58 | + categorySlugs: textArray('category_slugs'), | |
| 59 | + metadata: jsonObject<Record<string, unknown>>('metadata'), | |
| 60 | + createdAt: createdAt(), | |
| 61 | +}); | |
| 62 | + | |
| 63 | +/** Sets / series / releases (Base Set, Alpha, Series 1 Prizm, LEGO theme year…). */ | |
| 64 | +export const sets = pgTable( | |
| 65 | + 'sets', | |
| 66 | + { | |
| 67 | + slug: text('slug').primaryKey(), | |
| 68 | + name: text('name').notNull(), | |
| 69 | + code: text('code'), | |
| 70 | + categorySlug: text('category_slug').notNull(), | |
| 71 | + franchiseSlug: text('franchise_slug'), | |
| 72 | + brandSlug: text('brand_slug'), | |
| 73 | + releaseYear: integer('release_year'), | |
| 74 | + releaseDate: text('release_date'), | |
| 75 | + language: text('language'), | |
| 76 | + totalItems: integer('total_items'), | |
| 77 | + identifiers: jsonObject<Record<string, string>>('identifiers'), | |
| 78 | + metadata: jsonObject<Record<string, unknown>>('metadata'), | |
| 79 | + createdAt: createdAt(), | |
| 80 | + }, | |
| 81 | + (t) => [index('sets_category_idx').on(t.categorySlug), uniqueIndex('sets_category_code_uq').on(t.categorySlug, t.code)], | |
| 82 | +); | |
| 83 | + | |
| 84 | +export const graders = pgTable('graders', { | |
| 85 | + slug: text('slug').primaryKey(), // psa, bgs, cgc, sgc, tag, wata, vga, pcgs, ngc, cbcs, anacs, iccs | |
| 86 | + name: text('name').notNull(), | |
| 87 | + categorySlugs: textArray('category_slugs'), | |
| 88 | + /** ordered scale values e.g. ["1","1.5",…,"10"] */ | |
| 89 | + scale: jsonObject<{ values: string[]; top: string; type: 'numeric' | 'sheldon' | 'descriptive' }>('scale'), | |
| 90 | + populationUrl: text('population_url'), | |
| 91 | + verifyUrl: text('verify_url'), | |
| 92 | + active: boolean('active').notNull().default(true), | |
| 93 | +}); | |
| 94 | + | |
| 95 | +export const taxonomyProposals = pgTable('taxonomy_proposals', { | |
| 96 | + id: text('id').primaryKey(), | |
| 97 | + proposedSlug: text('proposed_slug').notNull(), | |
| 98 | + name: text('name').notNull(), | |
| 99 | + parentSlug: text('parent_slug'), | |
| 100 | + evidence: jsonObject<Record<string, unknown>>('evidence'), | |
| 101 | + volumeEstimate: integer('volume_estimate'), | |
| 102 | + status: text('status').notNull().default('pending'), // pending | approved | rejected | |
| 103 | + decidedBy: text('decided_by'), | |
| 104 | + decidedAt: text('decided_at'), | |
| 105 | + createdAt: createdAt(), | |
| 106 | +}); | |
added
packages/database/src/schema/users.ts
+191 −0
@@ -0,0 +1,191 @@ | ||
| 1 | +import { pgTable, text, integer, boolean, real, index, uniqueIndex, jsonb, date, primaryKey } from 'drizzle-orm/pg-core'; | |
| 2 | +import { createdAt, updatedAt, ts, money, jsonObject } from './_common.js'; | |
| 3 | + | |
| 4 | +export const users = pgTable('users', { | |
| 5 | + id: text('id').primaryKey(), | |
| 6 | + email: text('email').notNull().unique(), | |
| 7 | + emailVerifiedAt: ts('email_verified_at'), | |
| 8 | + passwordHash: text('password_hash'), | |
| 9 | + name: text('name'), | |
| 10 | + role: text('role').notNull().default('user'), // user | pro | admin | |
| 11 | + displayCurrency: text('display_currency').notNull().default('USD'), | |
| 12 | + /** oauth/passkey providers linked (§175) */ | |
| 13 | + providers: jsonb('providers').$type<Array<{ provider: string; subject: string }>>().notNull().default([]), | |
| 14 | + preferences: jsonObject<Record<string, unknown>>('preferences'), | |
| 15 | + createdAt: createdAt(), | |
| 16 | + lastLoginAt: ts('last_login_at'), | |
| 17 | +}); | |
| 18 | + | |
| 19 | +export const sessions = pgTable( | |
| 20 | + 'sessions', | |
| 21 | + { | |
| 22 | + id: text('id').primaryKey(), | |
| 23 | + userId: text('user_id').notNull(), | |
| 24 | + expiresAt: ts('expires_at').notNull(), | |
| 25 | + userAgent: text('user_agent'), | |
| 26 | + createdAt: createdAt(), | |
| 27 | + }, | |
| 28 | + (t) => [index('sessions_user_idx').on(t.userId)], | |
| 29 | +); | |
| 30 | + | |
| 31 | +export const collections = pgTable( | |
| 32 | + 'collections', | |
| 33 | + { | |
| 34 | + id: text('id').primaryKey(), | |
| 35 | + userId: text('user_id').notNull(), | |
| 36 | + name: text('name').notNull(), | |
| 37 | + description: text('description'), | |
| 38 | + isPublic: boolean('is_public').notNull().default(false), | |
| 39 | + publicSlug: text('public_slug'), | |
| 40 | + createdAt: createdAt(), | |
| 41 | + updatedAt: updatedAt(), | |
| 42 | + }, | |
| 43 | + (t) => [index('collections_user_idx').on(t.userId), uniqueIndex('collections_public_slug_uq').on(t.publicSlug)], | |
| 44 | +); | |
| 45 | + | |
| 46 | +export const collectionItems = pgTable( | |
| 47 | + 'collection_items', | |
| 48 | + { | |
| 49 | + id: text('id').primaryKey(), | |
| 50 | + collectionId: text('collection_id').notNull(), | |
| 51 | + assetId: text('asset_id').notNull(), | |
| 52 | + variantId: text('variant_id'), | |
| 53 | + quantity: integer('quantity').notNull().default(1), | |
| 54 | + acquiredAt: date('acquired_at'), | |
| 55 | + purchasePrice: money('purchase_price'), | |
| 56 | + purchaseCurrency: text('purchase_currency'), | |
| 57 | + purchasePriceUsd: money('purchase_price_usd'), | |
| 58 | + source: text('source'), | |
| 59 | + grader: text('grader'), | |
| 60 | + grade: text('grade'), | |
| 61 | + certificationNumber: text('certification_number'), | |
| 62 | + serial: text('serial'), | |
| 63 | + photos: jsonb('photos').$type<string[]>().notNull().default([]), | |
| 64 | + notes: text('notes'), | |
| 65 | + createdAt: createdAt(), | |
| 66 | + updatedAt: updatedAt(), | |
| 67 | + }, | |
| 68 | + (t) => [index('collection_items_collection_idx').on(t.collectionId), index('collection_items_asset_idx').on(t.assetId)], | |
| 69 | +); | |
| 70 | + | |
| 71 | +/** Daily portfolio value history (§130). */ | |
| 72 | +export const collectionSnapshots = pgTable( | |
| 73 | + 'collection_snapshots', | |
| 74 | + { | |
| 75 | + collectionId: text('collection_id').notNull(), | |
| 76 | + date: date('date').notNull(), | |
| 77 | + valueUsd: money('value_usd').notNull(), | |
| 78 | + costBasisUsd: money('cost_basis_usd').notNull(), | |
| 79 | + items: integer('items').notNull(), | |
| 80 | + }, | |
| 81 | + (t) => [primaryKey({ columns: [t.collectionId, t.date] })], | |
| 82 | +); | |
| 83 | + | |
| 84 | +export const watchlists = pgTable( | |
| 85 | + 'watchlists', | |
| 86 | + { | |
| 87 | + id: text('id').primaryKey(), | |
| 88 | + userId: text('user_id').notNull(), | |
| 89 | + name: text('name').notNull().default('Watchlist'), | |
| 90 | + createdAt: createdAt(), | |
| 91 | + }, | |
| 92 | + (t) => [index('watchlists_user_idx').on(t.userId)], | |
| 93 | +); | |
| 94 | + | |
| 95 | +export const watchlistItems = pgTable( | |
| 96 | + 'watchlist_items', | |
| 97 | + { | |
| 98 | + id: text('id').primaryKey(), | |
| 99 | + watchlistId: text('watchlist_id').notNull(), | |
| 100 | + targetType: text('target_type').notNull(), // asset | category | brand | set | source | auction | |
| 101 | + targetId: text('target_id').notNull(), | |
| 102 | + createdAt: createdAt(), | |
| 103 | + }, | |
| 104 | + (t) => [uniqueIndex('watchlist_items_uq').on(t.watchlistId, t.targetType, t.targetId)], | |
| 105 | +); | |
| 106 | + | |
| 107 | +export const alerts = pgTable( | |
| 108 | + 'alerts', | |
| 109 | + { | |
| 110 | + id: text('id').primaryKey(), | |
| 111 | + userId: text('user_id').notNull(), | |
| 112 | + alertType: text('alert_type').notNull(), // price_below | price_above | new_listing | new_auction | auction_ending | record_sale | unusual_volume | market_move | rare_item | population_update | |
| 113 | + targetType: text('target_type').notNull(), | |
| 114 | + targetId: text('target_id').notNull(), | |
| 115 | + threshold: money('threshold'), | |
| 116 | + currency: text('currency'), | |
| 117 | + params: jsonObject<Record<string, unknown>>('params'), | |
| 118 | + channel: text('channel').notNull().default('inapp'), // inapp | email | |
| 119 | + active: boolean('active').notNull().default(true), | |
| 120 | + lastTriggeredAt: ts('last_triggered_at'), | |
| 121 | + createdAt: createdAt(), | |
| 122 | + }, | |
| 123 | + (t) => [index('alerts_user_idx').on(t.userId), index('alerts_target_idx').on(t.targetType, t.targetId, t.active)], | |
| 124 | +); | |
| 125 | + | |
| 126 | +export const alertEvents = pgTable( | |
| 127 | + 'alert_events', | |
| 128 | + { | |
| 129 | + id: text('id').primaryKey(), | |
| 130 | + alertId: text('alert_id').notNull(), | |
| 131 | + userId: text('user_id').notNull(), | |
| 132 | + message: text('message').notNull(), | |
| 133 | + payload: jsonObject<Record<string, unknown>>('payload'), | |
| 134 | + readAt: ts('read_at'), | |
| 135 | + createdAt: createdAt(), | |
| 136 | + }, | |
| 137 | + (t) => [index('alert_events_user_idx').on(t.userId, t.createdAt)], | |
| 138 | +); | |
| 139 | + | |
| 140 | +export const apiKeys = pgTable( | |
| 141 | + 'api_keys', | |
| 142 | + { | |
| 143 | + id: text('id').primaryKey(), | |
| 144 | + userId: text('user_id'), | |
| 145 | + name: text('name').notNull(), | |
| 146 | + prefix: text('prefix').notNull(), | |
| 147 | + keyHash: text('key_hash').notNull().unique(), | |
| 148 | + tier: text('tier').notNull().default('free'), // free | hobby | professional | research | enterprise | |
| 149 | + rateLimitPerMinute: integer('rate_limit_per_minute').notNull().default(60), | |
| 150 | + dailyQuota: integer('daily_quota').notNull().default(1000), | |
| 151 | + createdAt: createdAt(), | |
| 152 | + lastUsedAt: ts('last_used_at'), | |
| 153 | + revokedAt: ts('revoked_at'), | |
| 154 | + }, | |
| 155 | + (t) => [index('api_keys_user_idx').on(t.userId)], | |
| 156 | +); | |
| 157 | + | |
| 158 | +export const apiUsage = pgTable( | |
| 159 | + 'api_usage', | |
| 160 | + { | |
| 161 | + keyId: text('key_id').notNull(), | |
| 162 | + date: date('date').notNull(), | |
| 163 | + endpoint: text('endpoint').notNull(), | |
| 164 | + count: integer('count').notNull().default(0), | |
| 165 | + latencyMsAvg: real('latency_ms_avg'), | |
| 166 | + }, | |
| 167 | + (t) => [primaryKey({ columns: [t.keyId, t.date, t.endpoint] })], | |
| 168 | +); | |
| 169 | + | |
| 170 | +export const assetViews = pgTable( | |
| 171 | + 'asset_views', | |
| 172 | + { | |
| 173 | + assetId: text('asset_id').notNull(), | |
| 174 | + date: date('date').notNull(), | |
| 175 | + views: integer('views').notNull().default(0), | |
| 176 | + }, | |
| 177 | + (t) => [primaryKey({ columns: [t.assetId, t.date] })], | |
| 178 | +); | |
| 179 | + | |
| 180 | +export const searchLog = pgTable( | |
| 181 | + 'search_log', | |
| 182 | + { | |
| 183 | + id: text('id').primaryKey(), | |
| 184 | + query: text('query').notNull(), | |
| 185 | + normalized: text('normalized').notNull(), | |
| 186 | + results: integer('results').notNull(), | |
| 187 | + userId: text('user_id'), | |
| 188 | + createdAt: createdAt(), | |
| 189 | + }, | |
| 190 | + (t) => [index('search_log_created_idx').on(t.createdAt), index('search_log_normalized_idx').on(t.normalized)], | |
| 191 | +); | |
added
packages/database/src/seed.ts
+166 −0
@@ -0,0 +1,166 @@ | ||
| 1 | +import { fileURLToPath } from 'node:url'; | |
| 2 | +import path from 'node:path'; | |
| 3 | +import { readFileSync, existsSync } from 'node:fs'; | |
| 4 | +import { sql } from 'drizzle-orm'; | |
| 5 | +import { CATEGORIES, GRADERS, INDICES, INDEX_BASE_DATE, INDEX_BASE_VALUE } from '@rareindex/taxonomy'; | |
| 6 | +import { getDb, closeDb } from './client.js'; | |
| 7 | +import { categories, graders, indices, sources, connectors } from './schema/index.js'; | |
| 8 | + | |
| 9 | +/** Upsert taxonomy nodes + graders from data/taxonomy (idempotent). */ | |
| 10 | +export async function seedTaxonomy(): Promise<void> { | |
| 11 | + const db = getDb(); | |
| 12 | + for (const c of CATEGORIES) { | |
| 13 | + await db | |
| 14 | + .insert(categories) | |
| 15 | + .values({ | |
| 16 | + slug: c.slug, | |
| 17 | + parentSlug: c.parent ?? null, | |
| 18 | + familySlug: c.familySlug, | |
| 19 | + name: c.name, | |
| 20 | + shortName: c.short ?? null, | |
| 21 | + description: c.description ?? null, | |
| 22 | + level: c.level, | |
| 23 | + phase: c.phase, | |
| 24 | + conditionScale: c.conditionScale ?? 'general', | |
| 25 | + graders: c.graders ?? [], | |
| 26 | + indexTicker: c.index ?? null, | |
| 27 | + sortOrder: c.sortOrder, | |
| 28 | + complianceFlags: c.compliance ?? [], | |
| 29 | + icon: c.icon ?? null, | |
| 30 | + }) | |
| 31 | + .onConflictDoUpdate({ | |
| 32 | + target: categories.slug, | |
| 33 | + set: { | |
| 34 | + parentSlug: c.parent ?? null, | |
| 35 | + familySlug: c.familySlug, | |
| 36 | + name: c.name, | |
| 37 | + shortName: c.short ?? null, | |
| 38 | + description: c.description ?? null, | |
| 39 | + level: c.level, | |
| 40 | + phase: c.phase, | |
| 41 | + conditionScale: c.conditionScale ?? 'general', | |
| 42 | + graders: c.graders ?? [], | |
| 43 | + indexTicker: c.index ?? null, | |
| 44 | + sortOrder: c.sortOrder, | |
| 45 | + complianceFlags: c.compliance ?? [], | |
| 46 | + icon: c.icon ?? null, | |
| 47 | + updatedAt: new Date(), | |
| 48 | + }, | |
| 49 | + }); | |
| 50 | + } | |
| 51 | + for (const g of GRADERS) { | |
| 52 | + await db | |
| 53 | + .insert(graders) | |
| 54 | + .values({ slug: g.slug, name: g.name, categorySlugs: g.categories, scale: g.scale, populationUrl: g.populationUrl ?? null, verifyUrl: g.verifyUrl ?? null }) | |
| 55 | + .onConflictDoUpdate({ target: graders.slug, set: { name: g.name, categorySlugs: g.categories, scale: g.scale, populationUrl: g.populationUrl ?? null, verifyUrl: g.verifyUrl ?? null } }); | |
| 56 | + } | |
| 57 | +} | |
| 58 | + | |
| 59 | +/** Upsert index definitions (§3). */ | |
| 60 | +export async function seedIndices(): Promise<void> { | |
| 61 | + const db = getDb(); | |
| 62 | + for (const i of INDICES) { | |
| 63 | + const familySlugs = i.families; | |
| 64 | + const categorySlugs = CATEGORIES.filter((c) => familySlugs.includes(c.familySlug)).map((c) => c.slug); | |
| 65 | + await db | |
| 66 | + .insert(indices) | |
| 67 | + .values({ | |
| 68 | + id: `idx_${i.ticker.toLowerCase().replace(/[^a-z0-9]+/g, '_')}`, | |
| 69 | + ticker: i.ticker, | |
| 70 | + name: i.name, | |
| 71 | + description: i.description ?? null, | |
| 72 | + categorySlugs, | |
| 73 | + familySlugs, | |
| 74 | + parentTicker: i.flagship ? null : 'RARE', | |
| 75 | + baseDate: INDEX_BASE_DATE, | |
| 76 | + baseValue: INDEX_BASE_VALUE, | |
| 77 | + minConstituents: i.minConstituents, | |
| 78 | + isFlagship: Boolean(i.flagship), | |
| 79 | + color: i.color, | |
| 80 | + }) | |
| 81 | + .onConflictDoUpdate({ target: indices.ticker, set: { name: i.name, description: i.description ?? null, categorySlugs, familySlugs, minConstituents: i.minConstituents, color: i.color } }); | |
| 82 | + } | |
| 83 | +} | |
| 84 | + | |
| 85 | +/** Mirror connectors/registry.json into sources + connectors tables (state columns are preserved). */ | |
| 86 | +export async function seedRegistry(): Promise<void> { | |
| 87 | + const here = path.dirname(fileURLToPath(import.meta.url)); | |
| 88 | + const registryPath = path.resolve(here, '../../../connectors/registry.json'); | |
| 89 | + if (!existsSync(registryPath)) return; | |
| 90 | + const reg = JSON.parse(readFileSync(registryPath, 'utf8')) as { connectors: Array<Record<string, any>> }; | |
| 91 | + const db = getDb(); | |
| 92 | + for (const c of reg.connectors) { | |
| 93 | + await db | |
| 94 | + .insert(sources) | |
| 95 | + .values({ id: c.sourceId, name: c.sourceName, sourceType: c.sourceType, url: c.sourceUrl, countries: c.regions ?? [], languages: c.languages ?? ['en'], currencies: c.currency ?? ['USD'], trustScore: c.trustScore ?? 0.6, attributionRequired: c.attributionRequired ?? true, termsUrl: c.termsUrl ?? null }) | |
| 96 | + .onConflictDoUpdate({ target: sources.id, set: { name: c.sourceName, sourceType: c.sourceType, url: c.sourceUrl, trustScore: c.trustScore ?? 0.6, termsUrl: c.termsUrl ?? null, updatedAt: new Date() } }); | |
| 97 | + await db | |
| 98 | + .insert(connectors) | |
| 99 | + .values({ | |
| 100 | + id: c.id, | |
| 101 | + sourceId: c.sourceId, | |
| 102 | + displayName: c.displayName, | |
| 103 | + enginePriority: c.enginePriority, | |
| 104 | + categories: c.categories, | |
| 105 | + regions: c.regions ?? [], | |
| 106 | + languages: c.languages ?? ['en'], | |
| 107 | + currency: c.currency ?? ['USD'], | |
| 108 | + supportsListings: c.supportsListings ?? false, | |
| 109 | + supportsSold: c.supportsSold ?? false, | |
| 110 | + supportsAuctions: c.supportsAuctions ?? false, | |
| 111 | + supportsImages: c.supportsImages ?? true, | |
| 112 | + supportsCatalog: c.supportsCatalog ?? false, | |
| 113 | + supportsPopulation: c.supportsPopulation ?? false, | |
| 114 | + refreshFrequencyMinutes: c.refreshFrequencyMinutes ?? 1440, | |
| 115 | + priority: c.priority ?? 'medium', | |
| 116 | + status: c.enabled === false ? 'disabled' : 'active', | |
| 117 | + schemaVersion: c.schemaVersion ?? '1.0', | |
| 118 | + config: c.config ?? {}, | |
| 119 | + }) | |
| 120 | + .onConflictDoUpdate({ | |
| 121 | + target: connectors.id, | |
| 122 | + set: { | |
| 123 | + sourceId: c.sourceId, | |
| 124 | + displayName: c.displayName, | |
| 125 | + enginePriority: c.enginePriority, | |
| 126 | + categories: c.categories, | |
| 127 | + regions: c.regions ?? [], | |
| 128 | + languages: c.languages ?? ['en'], | |
| 129 | + currency: c.currency ?? ['USD'], | |
| 130 | + supportsListings: c.supportsListings ?? false, | |
| 131 | + supportsSold: c.supportsSold ?? false, | |
| 132 | + supportsAuctions: c.supportsAuctions ?? false, | |
| 133 | + supportsImages: c.supportsImages ?? true, | |
| 134 | + supportsCatalog: c.supportsCatalog ?? false, | |
| 135 | + supportsPopulation: c.supportsPopulation ?? false, | |
| 136 | + refreshFrequencyMinutes: c.refreshFrequencyMinutes ?? 1440, | |
| 137 | + priority: c.priority ?? 'medium', | |
| 138 | + schemaVersion: c.schemaVersion ?? '1.0', | |
| 139 | + config: c.config ?? {}, | |
| 140 | + updatedAt: new Date(), | |
| 141 | + // status is intentionally NOT overwritten (admin pause survives reseeds) except when disabled in registry | |
| 142 | + ...(c.enabled === false ? { status: 'disabled' } : {}), | |
| 143 | + }, | |
| 144 | + }); | |
| 145 | + } | |
| 146 | +} | |
| 147 | + | |
| 148 | +export async function seedAll(): Promise<void> { | |
| 149 | + await seedTaxonomy(); | |
| 150 | + await seedIndices(); | |
| 151 | + await seedRegistry(); | |
| 152 | + const db = getDb(); | |
| 153 | + const [{ n }] = (await db.execute(sql`select count(*)::int as n from categories`)) as unknown as [{ n: number }]; | |
| 154 | + console.log(`[seed] categories=${n} indices=${INDICES.length}`); | |
| 155 | +} | |
| 156 | + | |
| 157 | +const isMain = process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url); | |
| 158 | +if (isMain) { | |
| 159 | + seedAll() | |
| 160 | + .then(() => closeDb()) | |
| 161 | + .catch(async (e) => { | |
| 162 | + console.error(e); | |
| 163 | + await closeDb(); | |
| 164 | + process.exit(1); | |
| 165 | + }); | |
| 166 | +} | |
added
packages/database/tsconfig.json
+9 −0
@@ -0,0 +1,9 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.base.json", | |
| 3 | + "compilerOptions": { | |
| 4 | + "rootDir": "src", | |
| 5 | + "outDir": "dist", | |
| 6 | + "noEmit": true | |
| 7 | + }, | |
| 8 | + "include": ["src"] | |
| 9 | +} | |
added
packages/database/vitest.config.ts
+5 −0
@@ -0,0 +1,5 @@ | ||
| 1 | +import { defineConfig } from 'vitest/config'; | |
| 2 | + | |
| 3 | +export default defineConfig({ | |
| 4 | + test: { include: ['src/**/*.test.ts'] }, | |
| 5 | +}); | |
added
packages/shared/package.json
+26 −0
@@ -0,0 +1,26 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@rareindex/shared", | |
| 3 | + "version": "0.1.0", | |
| 4 | + "private": true, | |
| 5 | + "type": "module", | |
| 6 | + "exports": { | |
| 7 | + ".": { | |
| 8 | + "types": "./src/index.ts", | |
| 9 | + "default": "./src/index.ts" | |
| 10 | + } | |
| 11 | + }, | |
| 12 | + "scripts": { | |
| 13 | + "build": "tsc -p tsconfig.json --noEmit", | |
| 14 | + "typecheck": "tsc -p tsconfig.json --noEmit", | |
| 15 | + "test": "vitest run --passWithNoTests" | |
| 16 | + }, | |
| 17 | + "dependencies": { | |
| 18 | + "pino": "^9.7.0", | |
| 19 | + "zod": "^4.0.0" | |
| 20 | + }, | |
| 21 | + "devDependencies": { | |
| 22 | + "@types/node": "^24.0.0", | |
| 23 | + "typescript": "^5.9.3", | |
| 24 | + "vitest": "^3.2.0" | |
| 25 | + } | |
| 26 | +} | |
added
packages/shared/src/dates.ts
+64 −0
@@ -0,0 +1,64 @@ | ||
| 1 | +const MONTHS: Record<string, number> = { | |
| 2 | + jan: 0, feb: 1, mar: 2, apr: 3, may: 4, jun: 5, jul: 6, aug: 7, sep: 8, sept: 8, oct: 9, nov: 10, dec: 11, | |
| 3 | +}; | |
| 4 | + | |
| 5 | +/** | |
| 6 | + * Parse common marketplace/auction date formats into a UTC Date (midnight when no time). | |
| 7 | + * Returns null instead of guessing. Crawl time is never substituted for a sale date here. | |
| 8 | + */ | |
| 9 | +export function parseSourceDate(raw: string | null | undefined, opts: { dayFirst?: boolean } = {}): Date | null { | |
| 10 | + if (!raw) return null; | |
| 11 | + const s = raw.trim().replace(/ /g, ' '); | |
| 12 | + if (!s) return null; | |
| 13 | + | |
| 14 | + // ISO-ish | |
| 15 | + if (/^\d{4}-\d{2}-\d{2}/.test(s)) { | |
| 16 | + const d = new Date(s.length === 10 ? `${s}T00:00:00Z` : s); | |
| 17 | + return Number.isNaN(d.getTime()) ? null : d; | |
| 18 | + } | |
| 19 | + // "Jan 5, 2024", "5 Jan 2024", "January 05 2024", "Sept 12, 2023 10:31 AM" | |
| 20 | + const m1 = s.match(/\b([A-Za-z]{3,9})\.?\s+(\d{1,2})(?:st|nd|rd|th)?,?\s+(\d{4})/); | |
| 21 | + if (m1) { | |
| 22 | + const mo = MONTHS[m1[1]!.slice(0, 3).toLowerCase()]; | |
| 23 | + if (mo !== undefined) return new Date(Date.UTC(Number(m1[3]), mo, Number(m1[2]))); | |
| 24 | + } | |
| 25 | + const m2 = s.match(/\b(\d{1,2})(?:st|nd|rd|th)?\s+([A-Za-z]{3,9})\.?,?\s+(\d{4})/); | |
| 26 | + if (m2) { | |
| 27 | + const mo = MONTHS[m2[2]!.slice(0, 3).toLowerCase()]; | |
| 28 | + if (mo !== undefined) return new Date(Date.UTC(Number(m2[3]), mo, Number(m2[1]))); | |
| 29 | + } | |
| 30 | + // numeric 01/05/2024 or 05.01.2024 or 2024/01/05 | |
| 31 | + const m3 = s.match(/\b(\d{1,4})[./-](\d{1,2})[./-](\d{1,4})\b/); | |
| 32 | + if (m3) { | |
| 33 | + const a = Number(m3[1]); | |
| 34 | + const b = Number(m3[2]); | |
| 35 | + const c = Number(m3[3]); | |
| 36 | + if (m3[1]!.length === 4) return new Date(Date.UTC(a, b - 1, c)); | |
| 37 | + let year = c; | |
| 38 | + if (m3[3]!.length === 2) year = 2000 + c; | |
| 39 | + const dayFirst = opts.dayFirst ?? a > 12; | |
| 40 | + const [day, month] = dayFirst ? [a, b] : [b, a]; | |
| 41 | + if (month < 1 || month > 12 || day < 1 || day > 31) return null; | |
| 42 | + return new Date(Date.UTC(year, month - 1, day)); | |
| 43 | + } | |
| 44 | + // "Mar 2024" (month precision) | |
| 45 | + const m4 = s.match(/\b([A-Za-z]{3,9})\.?\s+(\d{4})\b/); | |
| 46 | + if (m4) { | |
| 47 | + const mo = MONTHS[m4[1]!.slice(0, 3).toLowerCase()]; | |
| 48 | + if (mo !== undefined) return new Date(Date.UTC(Number(m4[2]), mo, 1)); | |
| 49 | + } | |
| 50 | + const d = new Date(s); | |
| 51 | + return Number.isNaN(d.getTime()) ? null : d; | |
| 52 | +} | |
| 53 | + | |
| 54 | +export function toDateOnly(d: Date): string { | |
| 55 | + return d.toISOString().slice(0, 10); | |
| 56 | +} | |
| 57 | + | |
| 58 | +export function daysBetween(a: Date, b: Date): number { | |
| 59 | + return Math.abs(a.getTime() - b.getTime()) / 86_400_000; | |
| 60 | +} | |
| 61 | + | |
| 62 | +export function addDays(d: Date, days: number): Date { | |
| 63 | + return new Date(d.getTime() + days * 86_400_000); | |
| 64 | +} | |
added
packages/shared/src/env.ts
+37 −0
@@ -0,0 +1,37 @@ | ||
| 1 | +import { z } from 'zod'; | |
| 2 | + | |
| 3 | +/** | |
| 4 | + * Server-side environment. Loaded lazily so browser bundles never import it. | |
| 5 | + * Secrets are never logged (see logger redaction) and never exposed to the client. | |
| 6 | + */ | |
| 7 | +const EnvSchema = z.object({ | |
| 8 | + DATABASE_URL: z.string().default('postgres://localhost:5432/rareindex'), | |
| 9 | + FIRECRAWL_API_KEY: z.string().optional(), | |
| 10 | + SCRAPFLY_API_KEY: z.string().optional(), | |
| 11 | + ANTHROPIC_API_KEY: z.string().optional(), | |
| 12 | + OPENAI_API_KEY: z.string().optional(), | |
| 13 | + LOCAL_LLM_BASE_URL: z.string().optional(), | |
| 14 | + LOCAL_LLM_API_KEY: z.string().optional(), | |
| 15 | + POKEMONTCG_API_KEY: z.string().optional(), | |
| 16 | + NEXT_PUBLIC_SITE_URL: z.string().default('http://localhost:3000'), | |
| 17 | + SESSION_SECRET: z.string().default('dev-only-session-secret-change-me-please'), | |
| 18 | + ADMIN_TOKEN: z.string().optional(), | |
| 19 | + API_PORT: z.coerce.number().default(8211), | |
| 20 | + WEB_PORT: z.coerce.number().default(8210), | |
| 21 | + WORKER_CONCURRENCY: z.coerce.number().default(4), | |
| 22 | + LOG_LEVEL: z.string().default('info'), | |
| 23 | + NODE_ENV: z.enum(['development', 'test', 'production']).default('development'), | |
| 24 | + RI_DATA_DIR: z.string().default('./data'), | |
| 25 | +}); | |
| 26 | + | |
| 27 | +export type Env = z.infer<typeof EnvSchema>; | |
| 28 | + | |
| 29 | +let cached: Env | null = null; | |
| 30 | +export function env(): Env { | |
| 31 | + if (!cached) cached = EnvSchema.parse(process.env); | |
| 32 | + return cached; | |
| 33 | +} | |
| 34 | + | |
| 35 | +export function isProduction(): boolean { | |
| 36 | + return env().NODE_ENV === 'production'; | |
| 37 | +} | |
added
packages/shared/src/ids.ts
+0 −0
Binary file not shown.
added
packages/shared/src/index.ts
+8 −0
@@ -0,0 +1,8 @@ | ||
| 1 | +export * from './ids.js'; | |
| 2 | +export * from './money.js'; | |
| 3 | +export * from './text.js'; | |
| 4 | +export * from './dates.js'; | |
| 5 | +export * from './logger.js'; | |
| 6 | +export * from './env.js'; | |
| 7 | +export * from './schemas.js'; | |
| 8 | +export * from './stats.js'; | |
added
packages/shared/src/logger.ts
+19 −0
@@ -0,0 +1,19 @@ | ||
| 1 | +import pino from 'pino'; | |
| 2 | + | |
| 3 | +const level = process.env.LOG_LEVEL ?? 'info'; | |
| 4 | + | |
| 5 | +export const logger = pino({ | |
| 6 | + level, | |
| 7 | + base: { service: process.env.RI_SERVICE ?? 'rareindex' }, | |
| 8 | + timestamp: pino.stdTimeFunctions.isoTime, | |
| 9 | + redact: { | |
| 10 | + paths: ['*.apiKey', '*.api_key', '*.authorization', 'req.headers.authorization', 'FIRECRAWL_API_KEY', 'SCRAPFLY_API_KEY', 'ANTHROPIC_API_KEY', 'OPENAI_API_KEY'], | |
| 11 | + censor: '[redacted]', | |
| 12 | + }, | |
| 13 | +}); | |
| 14 | + | |
| 15 | +export type Logger = typeof logger; | |
| 16 | + | |
| 17 | +export function childLogger(bindings: Record<string, unknown>): Logger { | |
| 18 | + return logger.child(bindings); | |
| 19 | +} | |
added
packages/shared/src/money.test.ts
+65 −0
@@ -0,0 +1,65 @@ | ||
| 1 | +import { describe, expect, it } from 'vitest'; | |
| 2 | +import { parsePrice, formatMoney } from './money.js'; | |
| 3 | +import { parseSourceDate } from './dates.js'; | |
| 4 | +import { median, trimmedMean, ewMean, maxDrawdown } from './stats.js'; | |
| 5 | +import { normalizeForMatch, jaccard, slugify } from './text.js'; | |
| 6 | + | |
| 7 | +describe('parsePrice', () => { | |
| 8 | + it('parses US formats', () => { | |
| 9 | + expect(parsePrice('$1,234.56')).toMatchObject({ amount: 1234.56, currency: 'USD' }); | |
| 10 | + expect(parsePrice('US $2,500.00')).toMatchObject({ amount: 2500, currency: 'USD' }); | |
| 11 | + expect(parsePrice('Sold for $420,000')).toMatchObject({ amount: 420000, currency: 'USD' }); | |
| 12 | + }); | |
| 13 | + it('parses EU formats', () => { | |
| 14 | + expect(parsePrice('1.234,56 €')).toMatchObject({ amount: 1234.56, currency: 'EUR' }); | |
| 15 | + expect(parsePrice('EUR 12,50')).toMatchObject({ amount: 12.5, currency: 'EUR' }); | |
| 16 | + expect(parsePrice('2.500 €')).toMatchObject({ amount: 2500, currency: 'EUR' }); | |
| 17 | + }); | |
| 18 | + it('parses GBP/JPY/CAD', () => { | |
| 19 | + expect(parsePrice('£12.99')).toMatchObject({ amount: 12.99, currency: 'GBP' }); | |
| 20 | + expect(parsePrice('¥15,000')).toMatchObject({ amount: 15000, currency: 'JPY' }); | |
| 21 | + expect(parsePrice('CA$1 200,00')).toMatchObject({ amount: 1200, currency: 'CAD' }); | |
| 22 | + expect(parsePrice('C$99')).toMatchObject({ amount: 99, currency: 'CAD' }); | |
| 23 | + }); | |
| 24 | + it('does not invent a currency', () => { | |
| 25 | + expect(parsePrice('1500')).toMatchObject({ amount: 1500, currency: null }); | |
| 26 | + expect(parsePrice('1500', 'GBP')).toMatchObject({ amount: 1500, currency: 'GBP' }); | |
| 27 | + expect(parsePrice('no price')).toBeNull(); | |
| 28 | + }); | |
| 29 | + it('formats', () => { | |
| 30 | + expect(formatMoney(8450)).toBe('$8,450'); | |
| 31 | + expect(formatMoney(12.5)).toBe('$12.50'); | |
| 32 | + expect(formatMoney(null)).toBe('—'); | |
| 33 | + }); | |
| 34 | +}); | |
| 35 | + | |
| 36 | +describe('parseSourceDate', () => { | |
| 37 | + it('handles common formats', () => { | |
| 38 | + expect(parseSourceDate('2024-03-05')?.toISOString()).toBe('2024-03-05T00:00:00.000Z'); | |
| 39 | + expect(parseSourceDate('Mar 5, 2024')?.toISOString()).toBe('2024-03-05T00:00:00.000Z'); | |
| 40 | + expect(parseSourceDate('5 March 2024')?.toISOString()).toBe('2024-03-05T00:00:00.000Z'); | |
| 41 | + expect(parseSourceDate('03/05/2024')?.toISOString()).toBe('2024-03-05T00:00:00.000Z'); | |
| 42 | + expect(parseSourceDate('05.03.2024', { dayFirst: true })?.toISOString()).toBe('2024-03-05T00:00:00.000Z'); | |
| 43 | + expect(parseSourceDate('garbage')).toBeNull(); | |
| 44 | + }); | |
| 45 | +}); | |
| 46 | + | |
| 47 | +describe('stats', () => { | |
| 48 | + it('median/trimmed/ew/drawdown', () => { | |
| 49 | + expect(median([3, 1, 2])).toBe(2); | |
| 50 | + expect(median([4, 1, 2, 3])).toBe(2.5); | |
| 51 | + expect(trimmedMean([1, 2, 3, 4, 100], 0.2)).toBe(3); | |
| 52 | + expect(ewMean([{ value: 100, ageDays: 0 }, { value: 50, ageDays: 1000 }])).toBeGreaterThan(90); | |
| 53 | + expect(maxDrawdown([100, 120, 60, 90])).toBeCloseTo(0.5); | |
| 54 | + }); | |
| 55 | +}); | |
| 56 | + | |
| 57 | +describe('text', () => { | |
| 58 | + it('normalises and compares', () => { | |
| 59 | + const a = '1999 Pokemon Base Charizard 1st PSA 10'; | |
| 60 | + const b = 'Pokémon 1999 First Edition Charizard Holo PSA GEM MT 10'; | |
| 61 | + expect(normalizeForMatch(a)).toBe('1999 pokemon base charizard 1st psa 10'); | |
| 62 | + expect(jaccard(a, b)).toBeGreaterThan(0.3); | |
| 63 | + expect(slugify('1999 Base Set Charizard #4/102 — 1st Edition')).toBe('1999-base-set-charizard-4-102-1st-edition'); | |
| 64 | + }); | |
| 65 | +}); | |
added
packages/shared/src/money.ts
+123 −0
@@ -0,0 +1,123 @@ | ||
| 1 | +/** | |
| 2 | + * Currency handling. Prices are stored as integer minor units? No — collectibles span | |
| 3 | + * cents to eight figures and many sources report fractional amounts; we use NUMERIC(18,4) | |
| 4 | + * in the database and JS numbers at the edges. Never mix currencies without an FX row. | |
| 5 | + */ | |
| 6 | +export const SUPPORTED_CURRENCIES = [ | |
| 7 | + 'USD', 'CAD', 'EUR', 'GBP', 'JPY', 'CHF', 'AUD', 'HKD', 'SGD', 'CNY', 'KRW', 'SEK', 'NOK', 'DKK', 'NZD', 'MXN', 'BRL', 'INR', 'PLN', 'CZK', 'TWD', 'THB', 'AED', | |
| 8 | +] as const; | |
| 9 | +export type CurrencyCode = (typeof SUPPORTED_CURRENCIES)[number]; | |
| 10 | + | |
| 11 | +export const DISPLAY_CURRENCIES: CurrencyCode[] = ['USD', 'CAD', 'EUR', 'GBP', 'JPY']; | |
| 12 | + | |
| 13 | +const SYMBOL_MAP: Array<[RegExp, CurrencyCode]> = [ | |
| 14 | + [/\bUS\s?\$|\bUSD\b|U\.S\.\s?\$/i, 'USD'], | |
| 15 | + [/\bCA\s?\$|\bC\$|\bCAD\b|CDN\s?\$/i, 'CAD'], | |
| 16 | + [/\bAU\s?\$|\bA\$|\bAUD\b/i, 'AUD'], | |
| 17 | + [/\bNZ\s?\$|\bNZD\b/i, 'NZD'], | |
| 18 | + [/\bHK\s?\$|\bHKD\b/i, 'HKD'], | |
| 19 | + [/\bS\$|\bSGD\b/i, 'SGD'], | |
| 20 | + [/\bMX\s?\$|\bMXN\b/i, 'MXN'], | |
| 21 | + [/€|\bEUR\b/i, 'EUR'], | |
| 22 | + [/£|\bGBP\b/i, 'GBP'], | |
| 23 | + [/¥|¥|\bJPY\b/i, 'JPY'], | |
| 24 | + [/\bCHF\b|\bFr\.\s?\d/i, 'CHF'], | |
| 25 | + [/\bCNY\b|\bRMB\b/i, 'CNY'], | |
| 26 | + [/₩|\bKRW\b/i, 'KRW'], | |
| 27 | + [/\bSEK\b|\bkr\b/i, 'SEK'], | |
| 28 | + [/\bNOK\b/i, 'NOK'], | |
| 29 | + [/\bDKK\b/i, 'DKK'], | |
| 30 | + [/\bAED\b/i, 'AED'], | |
| 31 | + [/\bINR\b|₹/i, 'INR'], | |
| 32 | + [/\bBRL\b|R\$/i, 'BRL'], | |
| 33 | + [/\bPLN\b|zł/i, 'PLN'], | |
| 34 | + [/\bCZK\b|Kč/i, 'CZK'], | |
| 35 | + [/\bTWD\b|NT\$/i, 'TWD'], | |
| 36 | + [/\bTHB\b|฿/i, 'THB'], | |
| 37 | +]; | |
| 38 | + | |
| 39 | +export interface ParsedPrice { | |
| 40 | + amount: number; | |
| 41 | + currency: CurrencyCode | null; | |
| 42 | + /** 0–1 confidence that the parse is correct */ | |
| 43 | + confidence: number; | |
| 44 | +} | |
| 45 | + | |
| 46 | +/** | |
| 47 | + * Parse a human-formatted price. Handles "$1,234.56", "1.234,56 €", "£12", "¥15,000", "US $2,500.00", | |
| 48 | + * "CA$1 200,00", "1 234,56 EUR", "2.500" (ambiguous → treated as thousands separator when 3 trailing digits). | |
| 49 | + * Returns null when no number is found. Never guesses a currency when none is present | |
| 50 | + * (caller supplies `defaultCurrency` if the source is single-currency). | |
| 51 | + */ | |
| 52 | +export function parsePrice(raw: string | null | undefined, defaultCurrency?: CurrencyCode): ParsedPrice | null { | |
| 53 | + if (!raw) return null; | |
| 54 | + const text = raw.replace(/ /g, ' ').trim(); | |
| 55 | + if (!text) return null; | |
| 56 | + | |
| 57 | + let currency: CurrencyCode | null = null; | |
| 58 | + for (const [re, code] of SYMBOL_MAP) { | |
| 59 | + if (re.test(text)) { | |
| 60 | + currency = code; | |
| 61 | + break; | |
| 62 | + } | |
| 63 | + } | |
| 64 | + // Bare "$" defaults to USD only when caller allows via defaultCurrency or nothing else matched. | |
| 65 | + if (!currency && /\$/.test(text)) currency = defaultCurrency ?? 'USD'; | |
| 66 | + if (!currency) currency = defaultCurrency ?? null; | |
| 67 | + | |
| 68 | + const m = text.match(/-?\d[\d\s.,']*\d|\d/); | |
| 69 | + if (!m) return null; | |
| 70 | + let num = m[0].replace(/[\s']/g, ''); | |
| 71 | + const negative = num.startsWith('-'); | |
| 72 | + num = num.replace('-', ''); | |
| 73 | + | |
| 74 | + const lastComma = num.lastIndexOf(','); | |
| 75 | + const lastDot = num.lastIndexOf('.'); | |
| 76 | + let confidence = 0.95; | |
| 77 | + if (lastComma >= 0 && lastDot >= 0) { | |
| 78 | + // Whichever separator is last is the decimal separator. | |
| 79 | + if (lastComma > lastDot) num = num.replace(/\./g, '').replace(',', '.'); | |
| 80 | + else num = num.replace(/,/g, ''); | |
| 81 | + } else if (lastComma >= 0) { | |
| 82 | + const tail = num.length - lastComma - 1; | |
| 83 | + if (tail === 3 && (num.match(/,/g)?.length ?? 0) >= 1 && !/^\d{1,3},\d{3}$/.test(num)) { | |
| 84 | + num = num.replace(/,/g, ''); | |
| 85 | + } else if (tail === 3) { | |
| 86 | + // "2,500" → ambiguous; thousands in EN sources, decimal in some EU sources. Prefer thousands. | |
| 87 | + num = num.replace(/,/g, ''); | |
| 88 | + confidence = 0.8; | |
| 89 | + } else { | |
| 90 | + num = num.replace(',', '.'); | |
| 91 | + } | |
| 92 | + } else if (lastDot >= 0) { | |
| 93 | + const tail = num.length - lastDot - 1; | |
| 94 | + const dots = num.match(/\./g)?.length ?? 0; | |
| 95 | + if (dots > 1 || (tail === 3 && currency === 'EUR')) { | |
| 96 | + num = num.replace(/\./g, ''); | |
| 97 | + confidence = dots > 1 ? 0.9 : 0.7; | |
| 98 | + } | |
| 99 | + } | |
| 100 | + const amount = Number.parseFloat(num); | |
| 101 | + if (!Number.isFinite(amount)) return null; | |
| 102 | + if (currency === 'JPY' || currency === 'KRW') confidence = Math.min(confidence, 0.9); | |
| 103 | + return { amount: negative ? -amount : amount, currency, confidence }; | |
| 104 | +} | |
| 105 | + | |
| 106 | +export function formatMoney(amount: number | null | undefined, currency: CurrencyCode = 'USD', opts: { compact?: boolean; maximumFractionDigits?: number } = {}): string { | |
| 107 | + if (amount === null || amount === undefined || !Number.isFinite(amount)) return '—'; | |
| 108 | + const zeroDecimal = currency === 'JPY' || currency === 'KRW'; | |
| 109 | + const fmt = new Intl.NumberFormat('en-US', { | |
| 110 | + style: 'currency', | |
| 111 | + currency, | |
| 112 | + notation: opts.compact ? 'compact' : 'standard', | |
| 113 | + maximumFractionDigits: opts.maximumFractionDigits ?? (zeroDecimal ? 0 : amount >= 1000 ? 0 : 2), | |
| 114 | + minimumFractionDigits: zeroDecimal || amount >= 1000 || opts.compact ? 0 : 2, | |
| 115 | + }); | |
| 116 | + return fmt.format(amount); | |
| 117 | +} | |
| 118 | + | |
| 119 | +export function formatPct(value: number | null | undefined, digits = 2): string { | |
| 120 | + if (value === null || value === undefined || !Number.isFinite(value)) return '—'; | |
| 121 | + const sign = value > 0 ? '+' : ''; | |
| 122 | + return `${sign}${(value * 100).toFixed(digits)}%`; | |
| 123 | +} | |
added
packages/shared/src/schemas.ts
+248 −0
@@ -0,0 +1,248 @@ | ||
| 1 | +import { z } from 'zod'; | |
| 2 | +import { SUPPORTED_CURRENCIES } from './money.js'; | |
| 3 | + | |
| 4 | +/** | |
| 5 | + * Canonical Zod schemas. These are the contracts between connectors, the ingestion pipeline, | |
| 6 | + * the database layer, and the apps. Source-specific quirks must be resolved BEFORE data | |
| 7 | + * reaches these shapes (see CLAUDE.md §108, §196.6). | |
| 8 | + */ | |
| 9 | + | |
| 10 | +export const CurrencySchema = z.enum(SUPPORTED_CURRENCIES); | |
| 11 | + | |
| 12 | +export const SourceTypeSchema = z.enum([ | |
| 13 | + 'marketplace', 'auction_house', 'dealer', 'pricing_guide', 'grading_company', 'manufacturer', 'museum', 'archive', | |
| 14 | + 'catalog', 'collector_database', 'community', 'forum', 'news', 'analytics_provider', 'registry', 'official_source', | |
| 15 | +]); | |
| 16 | +export type SourceType = z.infer<typeof SourceTypeSchema>; | |
| 17 | + | |
| 18 | +export const EngineSchema = z.enum(['api', 'feed', 'firecrawl', 'scrapfly', 'browser', 'manual']); | |
| 19 | +export type Engine = z.infer<typeof EngineSchema>; | |
| 20 | + | |
| 21 | +export const RecordKindSchema = z.enum(['sale', 'listing', 'auction_lot', 'price_observation', 'catalog_item', 'population_report', 'news_item']); | |
| 22 | +export type RecordKind = z.infer<typeof RecordKindSchema>; | |
| 23 | + | |
| 24 | +/** Immutable raw payload captured from a source. Never mutated after insert (§108). */ | |
| 25 | +export const RawRecordSchema = z.object({ | |
| 26 | + connectorId: z.string(), | |
| 27 | + sourceId: z.string(), | |
| 28 | + engine: EngineSchema, | |
| 29 | + url: z.string().url().or(z.string().min(1)), | |
| 30 | + externalId: z.string().nullable().default(null), | |
| 31 | + kind: RecordKindSchema, | |
| 32 | + fetchedAt: z.coerce.date(), | |
| 33 | + contentHash: z.string(), | |
| 34 | + httpStatus: z.number().int().nullable().default(null), | |
| 35 | + payload: z.unknown(), | |
| 36 | + /** raw HTML/markdown snapshot key in object storage or inline text (bounded) */ | |
| 37 | + snapshotRef: z.string().nullable().default(null), | |
| 38 | + parserVersion: z.string(), | |
| 39 | + connectorVersion: z.string(), | |
| 40 | +}); | |
| 41 | +export type RawRecord = z.infer<typeof RawRecordSchema>; | |
| 42 | + | |
| 43 | +/** Attributes used for canonical asset identity; anything unknown must be null, never guessed (§192). */ | |
| 44 | +export const AssetAttributesSchema = z.object({ | |
| 45 | + categorySlug: z.string(), | |
| 46 | + subcategorySlug: z.string().nullable().default(null), | |
| 47 | + franchise: z.string().nullable().default(null), | |
| 48 | + brand: z.string().nullable().default(null), | |
| 49 | + series: z.string().nullable().default(null), | |
| 50 | + set: z.string().nullable().default(null), | |
| 51 | + setCode: z.string().nullable().default(null), | |
| 52 | + name: z.string(), | |
| 53 | + model: z.string().nullable().default(null), | |
| 54 | + reference: z.string().nullable().default(null), | |
| 55 | + number: z.string().nullable().default(null), | |
| 56 | + year: z.number().int().nullable().default(null), | |
| 57 | + edition: z.string().nullable().default(null), | |
| 58 | + variant: z.string().nullable().default(null), | |
| 59 | + language: z.string().nullable().default(null), | |
| 60 | + region: z.string().nullable().default(null), | |
| 61 | + country: z.string().nullable().default(null), | |
| 62 | + material: z.string().nullable().default(null), | |
| 63 | + size: z.string().nullable().default(null), | |
| 64 | + color: z.string().nullable().default(null), | |
| 65 | + rarity: z.string().nullable().default(null), | |
| 66 | + productionQuantity: z.number().int().nullable().default(null), | |
| 67 | + originalMsrp: z.number().nullable().default(null), | |
| 68 | + originalMsrpCurrency: CurrencySchema.nullable().default(null), | |
| 69 | + /** Deterministic identifiers: upc, isbn, sku, scryfall_id, tcgplayer_id, bricklink_id, style_code, ref, cert… */ | |
| 70 | + identifiers: z.record(z.string(), z.string()).default({}), | |
| 71 | + metadata: z.record(z.string(), z.unknown()).default({}), | |
| 72 | +}); | |
| 73 | +export type AssetAttributes = z.infer<typeof AssetAttributesSchema>; | |
| 74 | + | |
| 75 | +export const GradeSchema = z.object({ | |
| 76 | + grader: z.string().nullable().default(null), // PSA, BGS, CGC, SGC, TAG, WATA, VGA, PCGS, NGC, CBCS, raw | |
| 77 | + grade: z.string().nullable().default(null), // "10", "9.5", "9.8", "MS65" | |
| 78 | + qualifier: z.string().nullable().default(null), // "OC", "Signature Series", "Black Label" | |
| 79 | + certificationNumber: z.string().nullable().default(null), | |
| 80 | +}); | |
| 81 | +export type Grade = z.infer<typeof GradeSchema>; | |
| 82 | + | |
| 83 | +export const ConditionSchema = z.object({ | |
| 84 | + /** category-specific normalised condition slug (see taxonomy condition scales) */ | |
| 85 | + condition: z.string().nullable().default(null), | |
| 86 | + conditionRaw: z.string().nullable().default(null), | |
| 87 | + completeness: z.string().nullable().default(null), // sealed, cib, loose, box_papers, papers_only… | |
| 88 | +}); | |
| 89 | + | |
| 90 | +const BaseNormalized = z.object({ | |
| 91 | + connectorId: z.string(), | |
| 92 | + sourceId: z.string(), | |
| 93 | + sourceUrl: z.string(), | |
| 94 | + externalId: z.string().nullable().default(null), | |
| 95 | + rawTitle: z.string(), | |
| 96 | + description: z.string().nullable().default(null), | |
| 97 | + imageUrls: z.array(z.string()).default([]), | |
| 98 | + attributes: AssetAttributesSchema, | |
| 99 | + grade: GradeSchema.prefault({}), | |
| 100 | + condition: ConditionSchema.prefault({}), | |
| 101 | + observedAt: z.coerce.date(), | |
| 102 | + /** 0–1 confidence in the extraction & identification */ | |
| 103 | + confidence: z.number().min(0).max(1).default(0.8), | |
| 104 | + parserVersion: z.string(), | |
| 105 | +}); | |
| 106 | + | |
| 107 | +export const NormalizedSaleSchema = BaseNormalized.extend({ | |
| 108 | + kind: z.literal('sale'), | |
| 109 | + saleType: z.enum(['auction', 'fixed_price', 'best_offer', 'private', 'dealer', 'unknown']).default('unknown'), | |
| 110 | + saleDate: z.coerce.date(), | |
| 111 | + price: z.number().nonnegative(), | |
| 112 | + currency: CurrencySchema, | |
| 113 | + buyerPremiumIncluded: z.boolean().nullable().default(null), | |
| 114 | + quantity: z.number().int().positive().default(1), | |
| 115 | + isBundle: z.boolean().default(false), | |
| 116 | + location: z.string().nullable().default(null), | |
| 117 | + auctionHouse: z.string().nullable().default(null), | |
| 118 | + lotNumber: z.string().nullable().default(null), | |
| 119 | +}); | |
| 120 | +export type NormalizedSale = z.infer<typeof NormalizedSaleSchema>; | |
| 121 | + | |
| 122 | +export const NormalizedListingSchema = BaseNormalized.extend({ | |
| 123 | + kind: z.literal('listing'), | |
| 124 | + listingType: z.enum(['fixed_price', 'auction', 'best_offer', 'ask', 'unknown']).default('unknown'), | |
| 125 | + price: z.number().nonnegative().nullable(), | |
| 126 | + currency: CurrencySchema.nullable(), | |
| 127 | + seller: z.string().nullable().default(null), | |
| 128 | + sellerReputation: z.string().nullable().default(null), | |
| 129 | + location: z.string().nullable().default(null), | |
| 130 | + shippingCost: z.number().nullable().default(null), | |
| 131 | + quantity: z.number().int().nullable().default(null), | |
| 132 | + listedAt: z.coerce.date().nullable().default(null), | |
| 133 | + endsAt: z.coerce.date().nullable().default(null), | |
| 134 | + availability: z.enum(['available', 'sold', 'ended', 'removed', 'unknown']).default('available'), | |
| 135 | + bidCount: z.number().int().nullable().default(null), | |
| 136 | +}); | |
| 137 | +export type NormalizedListing = z.infer<typeof NormalizedListingSchema>; | |
| 138 | + | |
| 139 | +export const NormalizedAuctionLotSchema = BaseNormalized.extend({ | |
| 140 | + kind: z.literal('auction_lot'), | |
| 141 | + auctionHouse: z.string(), | |
| 142 | + auctionName: z.string().nullable().default(null), | |
| 143 | + lotNumber: z.string().nullable().default(null), | |
| 144 | + startsAt: z.coerce.date().nullable().default(null), | |
| 145 | + endsAt: z.coerce.date().nullable().default(null), | |
| 146 | + estimateLow: z.number().nullable().default(null), | |
| 147 | + estimateHigh: z.number().nullable().default(null), | |
| 148 | + currentBid: z.number().nullable().default(null), | |
| 149 | + currency: CurrencySchema.nullable(), | |
| 150 | + status: z.enum(['upcoming', 'live', 'ended', 'unknown']).default('unknown'), | |
| 151 | + location: z.string().nullable().default(null), | |
| 152 | +}); | |
| 153 | +export type NormalizedAuctionLot = z.infer<typeof NormalizedAuctionLotSchema>; | |
| 154 | + | |
| 155 | +/** Price-guide style observation (e.g. Scryfall market price). Not a transaction (§111 spirit). */ | |
| 156 | +export const NormalizedPriceObservationSchema = BaseNormalized.extend({ | |
| 157 | + kind: z.literal('price_observation'), | |
| 158 | + priceKind: z.enum(['market', 'low', 'mid', 'high', 'trend', 'average_7d', 'average_30d', 'last_sale_reported', 'guide_value']), | |
| 159 | + price: z.number().nonnegative(), | |
| 160 | + currency: CurrencySchema, | |
| 161 | + observationDate: z.coerce.date(), | |
| 162 | + sampleSize: z.number().int().nullable().default(null), | |
| 163 | +}); | |
| 164 | +export type NormalizedPriceObservation = z.infer<typeof NormalizedPriceObservationSchema>; | |
| 165 | + | |
| 166 | +/** Catalog entry from a manufacturer/reference database: creates or enriches canonical assets. */ | |
| 167 | +export const NormalizedCatalogItemSchema = BaseNormalized.extend({ | |
| 168 | + kind: z.literal('catalog_item'), | |
| 169 | + releaseDate: z.coerce.date().nullable().default(null), | |
| 170 | +}); | |
| 171 | +export type NormalizedCatalogItem = z.infer<typeof NormalizedCatalogItemSchema>; | |
| 172 | + | |
| 173 | +export const NormalizedPopulationReportSchema = z.object({ | |
| 174 | + kind: z.literal('population_report'), | |
| 175 | + connectorId: z.string(), | |
| 176 | + sourceId: z.string(), | |
| 177 | + sourceUrl: z.string(), | |
| 178 | + grader: z.string(), | |
| 179 | + attributes: AssetAttributesSchema, | |
| 180 | + reportDate: z.coerce.date(), | |
| 181 | + total: z.number().int().nonnegative(), | |
| 182 | + byGrade: z.record(z.string(), z.number().int().nonnegative()), | |
| 183 | + parserVersion: z.string(), | |
| 184 | + confidence: z.number().min(0).max(1).default(0.9), | |
| 185 | +}); | |
| 186 | +export type NormalizedPopulationReport = z.infer<typeof NormalizedPopulationReportSchema>; | |
| 187 | + | |
| 188 | +export const NormalizedNewsItemSchema = z.object({ | |
| 189 | + kind: z.literal('news_item'), | |
| 190 | + connectorId: z.string(), | |
| 191 | + sourceId: z.string(), | |
| 192 | + sourceUrl: z.string(), | |
| 193 | + title: z.string(), | |
| 194 | + summary: z.string().nullable().default(null), | |
| 195 | + publishedAt: z.coerce.date().nullable().default(null), | |
| 196 | + categorySlugs: z.array(z.string()).default([]), | |
| 197 | + imageUrl: z.string().nullable().default(null), | |
| 198 | + parserVersion: z.string(), | |
| 199 | +}); | |
| 200 | +export type NormalizedNewsItem = z.infer<typeof NormalizedNewsItemSchema>; | |
| 201 | + | |
| 202 | +export const NormalizedRecordSchema = z.discriminatedUnion('kind', [ | |
| 203 | + NormalizedSaleSchema, | |
| 204 | + NormalizedListingSchema, | |
| 205 | + NormalizedAuctionLotSchema, | |
| 206 | + NormalizedPriceObservationSchema, | |
| 207 | + NormalizedCatalogItemSchema, | |
| 208 | + NormalizedPopulationReportSchema, | |
| 209 | + NormalizedNewsItemSchema, | |
| 210 | +]); | |
| 211 | +export type NormalizedRecord = z.infer<typeof NormalizedRecordSchema>; | |
| 212 | + | |
| 213 | +export const ConnectorStatusSchema = z.enum(['healthy', 'degraded', 'failing', 'paused', 'unknown']); | |
| 214 | +export const ConnectorHealthSchema = z.object({ | |
| 215 | + connector: z.string(), | |
| 216 | + status: ConnectorStatusSchema, | |
| 217 | + success_rate_24h: z.number().min(0).max(1).nullable(), | |
| 218 | + pages_attempted: z.number().int().nonnegative(), | |
| 219 | + pages_success: z.number().int().nonnegative(), | |
| 220 | + firecrawl_success_rate: z.number().min(0).max(1).nullable(), | |
| 221 | + scrapfly_fallback_rate: z.number().min(0).max(1).nullable(), | |
| 222 | + parse_failure_rate: z.number().min(0).max(1).nullable(), | |
| 223 | + last_success: z.string().nullable(), | |
| 224 | + last_error: z.string().nullable(), | |
| 225 | + schema_version: z.string(), | |
| 226 | + records_24h: z.number().int().nonnegative(), | |
| 227 | + duplicates_24h: z.number().int().nonnegative(), | |
| 228 | + anomalies: z.array(z.string()).default([]), | |
| 229 | +}); | |
| 230 | +export type ConnectorHealth = z.infer<typeof ConnectorHealthSchema>; | |
| 231 | + | |
| 232 | +export const ExtractionResultSchema = z.object({ | |
| 233 | + success: z.boolean(), | |
| 234 | + engine: EngineSchema, | |
| 235 | + url: z.string(), | |
| 236 | + finalUrl: z.string().nullable().default(null), | |
| 237 | + httpStatus: z.number().int().nullable().default(null), | |
| 238 | + html: z.string().nullable().default(null), | |
| 239 | + markdown: z.string().nullable().default(null), | |
| 240 | + json: z.unknown().nullable().default(null), | |
| 241 | + qualityScore: z.number().min(0).max(1).default(0), | |
| 242 | + requiresReview: z.boolean().default(false), | |
| 243 | + error: z.string().nullable().default(null), | |
| 244 | + costCredits: z.number().nullable().default(null), | |
| 245 | + durationMs: z.number().nullable().default(null), | |
| 246 | + fetchedAt: z.coerce.date(), | |
| 247 | +}); | |
| 248 | +export type ExtractionResult = z.infer<typeof ExtractionResultSchema>; | |
added
packages/shared/src/stats.ts
+109 −0
@@ -0,0 +1,109 @@ | ||
| 1 | +/** Small, dependency-free numeric helpers used by valuation, indices and scores. */ | |
| 2 | + | |
| 3 | +export function median(values: number[]): number | null { | |
| 4 | + if (values.length === 0) return null; | |
| 5 | + const s = [...values].sort((a, b) => a - b); | |
| 6 | + const mid = Math.floor(s.length / 2); | |
| 7 | + return s.length % 2 ? s[mid]! : (s[mid - 1]! + s[mid]!) / 2; | |
| 8 | +} | |
| 9 | + | |
| 10 | +export function mean(values: number[]): number | null { | |
| 11 | + if (values.length === 0) return null; | |
| 12 | + return values.reduce((a, b) => a + b, 0) / values.length; | |
| 13 | +} | |
| 14 | + | |
| 15 | +export function quantile(values: number[], q: number): number | null { | |
| 16 | + if (values.length === 0) return null; | |
| 17 | + const s = [...values].sort((a, b) => a - b); | |
| 18 | + const pos = (s.length - 1) * q; | |
| 19 | + const lo = Math.floor(pos); | |
| 20 | + const hi = Math.ceil(pos); | |
| 21 | + if (lo === hi) return s[lo]!; | |
| 22 | + return s[lo]! + (s[hi]! - s[lo]!) * (pos - lo); | |
| 23 | +} | |
| 24 | + | |
| 25 | +/** Trimmed mean dropping `trim` fraction from each tail (e.g. 0.1). */ | |
| 26 | +export function trimmedMean(values: number[], trim = 0.1): number | null { | |
| 27 | + if (values.length === 0) return null; | |
| 28 | + const s = [...values].sort((a, b) => a - b); | |
| 29 | + const k = Math.floor(s.length * trim); | |
| 30 | + const core = s.slice(k, s.length - k); | |
| 31 | + return mean(core.length ? core : s); | |
| 32 | +} | |
| 33 | + | |
| 34 | +export function stddev(values: number[]): number | null { | |
| 35 | + if (values.length < 2) return null; | |
| 36 | + const m = mean(values)!; | |
| 37 | + const v = values.reduce((acc, x) => acc + (x - m) ** 2, 0) / (values.length - 1); | |
| 38 | + return Math.sqrt(v); | |
| 39 | +} | |
| 40 | + | |
| 41 | +/** Median absolute deviation (robust dispersion). */ | |
| 42 | +export function mad(values: number[]): number | null { | |
| 43 | + const m = median(values); | |
| 44 | + if (m === null) return null; | |
| 45 | + return median(values.map((v) => Math.abs(v - m))); | |
| 46 | +} | |
| 47 | + | |
| 48 | +/** Exponentially weighted mean; `halfLifeDays` controls decay by age (days). Most recent = highest weight. */ | |
| 49 | +export function ewMean(points: Array<{ value: number; ageDays: number }>, halfLifeDays = 60): number | null { | |
| 50 | + if (points.length === 0) return null; | |
| 51 | + let num = 0; | |
| 52 | + let den = 0; | |
| 53 | + for (const p of points) { | |
| 54 | + const w = Math.pow(0.5, Math.max(0, p.ageDays) / halfLifeDays); | |
| 55 | + num += w * p.value; | |
| 56 | + den += w; | |
| 57 | + } | |
| 58 | + return den > 0 ? num / den : null; | |
| 59 | +} | |
| 60 | + | |
| 61 | +export function weightedMean(points: Array<{ value: number; weight: number }>): number | null { | |
| 62 | + let num = 0; | |
| 63 | + let den = 0; | |
| 64 | + for (const p of points) { | |
| 65 | + num += p.value * p.weight; | |
| 66 | + den += p.weight; | |
| 67 | + } | |
| 68 | + return den > 0 ? num / den : null; | |
| 69 | +} | |
| 70 | + | |
| 71 | +export function clamp(x: number, lo: number, hi: number): number { | |
| 72 | + return Math.min(hi, Math.max(lo, x)); | |
| 73 | +} | |
| 74 | + | |
| 75 | +/** Percent change guarded against zero/null. */ | |
| 76 | +export function pctChange(from: number | null | undefined, to: number | null | undefined): number | null { | |
| 77 | + if (from === null || from === undefined || to === null || to === undefined || from === 0) return null; | |
| 78 | + return (to - from) / from; | |
| 79 | +} | |
| 80 | + | |
| 81 | +/** Max drawdown of a value series (0..1). */ | |
| 82 | +export function maxDrawdown(series: number[]): number | null { | |
| 83 | + if (series.length < 2) return null; | |
| 84 | + let peak = series[0]!; | |
| 85 | + let mdd = 0; | |
| 86 | + for (const v of series) { | |
| 87 | + if (v > peak) peak = v; | |
| 88 | + if (peak > 0) mdd = Math.max(mdd, (peak - v) / peak); | |
| 89 | + } | |
| 90 | + return mdd; | |
| 91 | +} | |
| 92 | + | |
| 93 | +/** Annualised volatility of log returns from an evenly spaced series. */ | |
| 94 | +export function volatility(series: number[], periodsPerYear = 365): number | null { | |
| 95 | + if (series.length < 3) return null; | |
| 96 | + const rets: number[] = []; | |
| 97 | + for (let i = 1; i < series.length; i++) { | |
| 98 | + const a = series[i - 1]!; | |
| 99 | + const b = series[i]!; | |
| 100 | + if (a > 0 && b > 0) rets.push(Math.log(b / a)); | |
| 101 | + } | |
| 102 | + const sd = stddev(rets); | |
| 103 | + return sd === null ? null : sd * Math.sqrt(periodsPerYear); | |
| 104 | +} | |
| 105 | + | |
| 106 | +export function round(x: number, digits = 2): number { | |
| 107 | + const f = 10 ** digits; | |
| 108 | + return Math.round(x * f) / f; | |
| 109 | +} | |
added
packages/shared/src/text.ts
+61 −0
@@ -0,0 +1,61 @@ | ||
| 1 | +/** Text normalisation helpers shared by entity resolution, search and connectors. */ | |
| 2 | + | |
| 3 | +export function slugify(input: string, maxLength = 96): string { | |
| 4 | + const s = input | |
| 5 | + .normalize('NFKD') | |
| 6 | + .replace(/[̀-ͯ]/g, '') | |
| 7 | + .toLowerCase() | |
| 8 | + .replace(/&/g, ' and ') | |
| 9 | + .replace(/[^a-z0-9]+/g, '-') | |
| 10 | + .replace(/^-+|-+$/g, ''); | |
| 11 | + return s.length > maxLength ? s.slice(0, maxLength).replace(/-+$/g, '') : s; | |
| 12 | +} | |
| 13 | + | |
| 14 | +/** Aggressive normalisation for matching: lowercase, ASCII, punctuation removed, common noise words dropped. */ | |
| 15 | +const NOISE = new Set(['the', 'a', 'an', 'of', 'and', '&', 'card', 'cards', 'lot', 'rare', 'mint', 'nm', 'lp', 'mp', 'hp', 'wow', 'look', 'nice', 'beautiful', 'gorgeous', 'pop', 'gem', 'mt', 'l@@k']); | |
| 16 | +export function normalizeForMatch(input: string): string { | |
| 17 | + return input | |
| 18 | + .normalize('NFKD') | |
| 19 | + .replace(/[̀-ͯ]/g, '') | |
| 20 | + .toLowerCase() | |
| 21 | + .replace(/[#№]/g, ' ') | |
| 22 | + .replace(/[^a-z0-9./\- ]+/g, ' ') | |
| 23 | + .split(/\s+/) | |
| 24 | + .filter((t) => t && !NOISE.has(t)) | |
| 25 | + .join(' ') | |
| 26 | + .trim(); | |
| 27 | +} | |
| 28 | + | |
| 29 | +export function tokens(input: string): string[] { | |
| 30 | + return normalizeForMatch(input).split(' ').filter(Boolean); | |
| 31 | +} | |
| 32 | + | |
| 33 | +/** Jaccard similarity of token sets (0–1). */ | |
| 34 | +export function jaccard(a: string, b: string): number { | |
| 35 | + const A = new Set(tokens(a)); | |
| 36 | + const B = new Set(tokens(b)); | |
| 37 | + if (A.size === 0 && B.size === 0) return 1; | |
| 38 | + let inter = 0; | |
| 39 | + for (const t of A) if (B.has(t)) inter++; | |
| 40 | + return inter / (A.size + B.size - inter); | |
| 41 | +} | |
| 42 | + | |
| 43 | +export function truncate(s: string, n: number): string { | |
| 44 | + return s.length <= n ? s : `${s.slice(0, n - 1)}…`; | |
| 45 | +} | |
| 46 | + | |
| 47 | +export function compactWhitespace(s: string): string { | |
| 48 | + return s.replace(/\s+/g, ' ').trim(); | |
| 49 | +} | |
| 50 | + | |
| 51 | +/** Extract a 4-digit year plausible for collectibles (1800–current+1). */ | |
| 52 | +export function extractYear(s: string): number | null { | |
| 53 | + const now = new Date().getUTCFullYear() + 1; | |
| 54 | + const m = s.match(/\b(1[89]\d{2}|20\d{2})\b/g); | |
| 55 | + if (!m) return null; | |
| 56 | + for (const y of m) { | |
| 57 | + const n = Number(y); | |
| 58 | + if (n >= 1800 && n <= now) return n; | |
| 59 | + } | |
| 60 | + return null; | |
| 61 | +} | |
added
packages/shared/tsconfig.json
+9 −0
@@ -0,0 +1,9 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.base.json", | |
| 3 | + "compilerOptions": { | |
| 4 | + "rootDir": "src", | |
| 5 | + "outDir": "dist", | |
| 6 | + "noEmit": true | |
| 7 | + }, | |
| 8 | + "include": ["src"] | |
| 9 | +} | |
added
packages/shared/vitest.config.ts
+5 −0
@@ -0,0 +1,5 @@ | ||
| 1 | +import { defineConfig } from 'vitest/config'; | |
| 2 | + | |
| 3 | +export default defineConfig({ | |
| 4 | + test: { include: ['src/**/*.test.ts'] }, | |
| 5 | +}); | |
added
packages/taxonomy/package.json
+26 −0
@@ -0,0 +1,26 @@ | ||
| 1 | +{ | |
| 2 | + "name": "@rareindex/taxonomy", | |
| 3 | + "version": "0.1.0", | |
| 4 | + "private": true, | |
| 5 | + "type": "module", | |
| 6 | + "exports": { | |
| 7 | + ".": { | |
| 8 | + "types": "./src/index.ts", | |
| 9 | + "default": "./src/index.ts" | |
| 10 | + } | |
| 11 | + }, | |
| 12 | + "scripts": { | |
| 13 | + "build": "tsc -p tsconfig.json --noEmit", | |
| 14 | + "typecheck": "tsc -p tsconfig.json --noEmit", | |
| 15 | + "test": "vitest run --passWithNoTests" | |
| 16 | + }, | |
| 17 | + "dependencies": { | |
| 18 | + "@rareindex/shared": "workspace:*", | |
| 19 | + "zod": "^4.0.0" | |
| 20 | + }, | |
| 21 | + "devDependencies": { | |
| 22 | + "@types/node": "^24.0.0", | |
| 23 | + "typescript": "^5.9.3", | |
| 24 | + "vitest": "^3.2.0" | |
| 25 | + } | |
| 26 | +} | |
added
packages/taxonomy/src/index.ts
+230 −0
@@ -0,0 +1,230 @@ | ||
| 1 | +import { z } from 'zod'; | |
| 2 | +import categoriesJson from '../../../data/taxonomy/categories.json' with { type: 'json' }; | |
| 3 | +import conditionsJson from '../../../data/taxonomy/conditions.json' with { type: 'json' }; | |
| 4 | +import gradersJson from '../../../data/taxonomy/graders.json' with { type: 'json' }; | |
| 5 | +import indicesJson from '../../../data/taxonomy/indices.json' with { type: 'json' }; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * Taxonomy loader. The JSON files under data/taxonomy are the seed; the database `categories` | |
| 9 | + * table is the runtime source of truth (it may contain approved proposals). This module offers | |
| 10 | + * pure helpers usable from connectors, workers and the web layer without a DB round-trip. | |
| 11 | + */ | |
| 12 | + | |
| 13 | +const NodeSchema = z.object({ | |
| 14 | + slug: z.string(), | |
| 15 | + parent: z.string().optional(), | |
| 16 | + name: z.string(), | |
| 17 | + short: z.string().optional(), | |
| 18 | + phase: z.number().int().min(1).max(3), | |
| 19 | + index: z.string().nullable().optional(), | |
| 20 | + conditionScale: z.string().optional(), | |
| 21 | + graders: z.array(z.string()).optional(), | |
| 22 | + compliance: z.array(z.string()).optional(), | |
| 23 | + description: z.string().optional(), | |
| 24 | + icon: z.string().optional(), | |
| 25 | +}); | |
| 26 | +export type TaxonomyNode = z.infer<typeof NodeSchema>; | |
| 27 | + | |
| 28 | +export interface CategoryNode extends TaxonomyNode { | |
| 29 | + level: number; | |
| 30 | + familySlug: string; | |
| 31 | + children: string[]; | |
| 32 | + sortOrder: number; | |
| 33 | +} | |
| 34 | + | |
| 35 | +const parsedNodes = z.array(NodeSchema).parse(categoriesJson.nodes); | |
| 36 | + | |
| 37 | +const bySlug = new Map<string, CategoryNode>(); | |
| 38 | +for (const [i, n] of parsedNodes.entries()) { | |
| 39 | + bySlug.set(n.slug, { ...n, level: 0, familySlug: n.slug, children: [], sortOrder: i }); | |
| 40 | +} | |
| 41 | +for (const n of bySlug.values()) { | |
| 42 | + if (n.parent) { | |
| 43 | + const p = bySlug.get(n.parent); | |
| 44 | + if (!p) throw new Error(`taxonomy: parent ${n.parent} of ${n.slug} not found`); | |
| 45 | + p.children.push(n.slug); | |
| 46 | + } | |
| 47 | +} | |
| 48 | +function resolve(n: CategoryNode): void { | |
| 49 | + if (!n.parent) return; | |
| 50 | + const p = bySlug.get(n.parent)!; | |
| 51 | + resolve(p); | |
| 52 | + n.level = p.level + 1; | |
| 53 | + n.familySlug = p.familySlug; | |
| 54 | + n.index = n.index ?? p.index ?? null; | |
| 55 | + n.conditionScale = n.conditionScale ?? p.conditionScale; | |
| 56 | + n.graders = n.graders ?? p.graders; | |
| 57 | +} | |
| 58 | +for (const n of bySlug.values()) resolve(n); | |
| 59 | + | |
| 60 | +export const CATEGORIES: readonly CategoryNode[] = [...bySlug.values()]; | |
| 61 | +export const FAMILIES: readonly CategoryNode[] = CATEGORIES.filter((c) => c.level === 0); | |
| 62 | + | |
| 63 | +export function getCategory(slug: string): CategoryNode | undefined { | |
| 64 | + return bySlug.get(slug); | |
| 65 | +} | |
| 66 | +export function requireCategory(slug: string): CategoryNode { | |
| 67 | + const c = bySlug.get(slug); | |
| 68 | + if (!c) throw new Error(`Unknown category slug: ${slug}`); | |
| 69 | + return c; | |
| 70 | +} | |
| 71 | +export function categoryFamily(slug: string): string { | |
| 72 | + return bySlug.get(slug)?.familySlug ?? slug; | |
| 73 | +} | |
| 74 | +export function categoryPath(slug: string): CategoryNode[] { | |
| 75 | + const out: CategoryNode[] = []; | |
| 76 | + let cur = bySlug.get(slug); | |
| 77 | + while (cur) { | |
| 78 | + out.unshift(cur); | |
| 79 | + cur = cur.parent ? bySlug.get(cur.parent) : undefined; | |
| 80 | + } | |
| 81 | + return out; | |
| 82 | +} | |
| 83 | +export function descendants(slug: string): string[] { | |
| 84 | + const out: string[] = []; | |
| 85 | + const stack = [slug]; | |
| 86 | + while (stack.length) { | |
| 87 | + const s = stack.pop()!; | |
| 88 | + const n = bySlug.get(s); | |
| 89 | + if (!n) continue; | |
| 90 | + for (const c of n.children) { | |
| 91 | + out.push(c); | |
| 92 | + stack.push(c); | |
| 93 | + } | |
| 94 | + } | |
| 95 | + return out; | |
| 96 | +} | |
| 97 | +export function phaseCategories(phase: 1 | 2 | 3): CategoryNode[] { | |
| 98 | + return CATEGORIES.filter((c) => c.phase <= phase); | |
| 99 | +} | |
| 100 | + | |
| 101 | +// ---------- Condition scales ---------- | |
| 102 | +export interface ConditionScale { | |
| 103 | + values: string[]; | |
| 104 | + completeness: string[]; | |
| 105 | + aliases: Record<string, string | null>; | |
| 106 | +} | |
| 107 | +export const CONDITION_SCALES: Record<string, ConditionScale> = conditionsJson.scales as Record<string, ConditionScale>; | |
| 108 | + | |
| 109 | +export function conditionScaleFor(categorySlug: string): ConditionScale { | |
| 110 | + const scale = bySlug.get(categorySlug)?.conditionScale ?? 'general'; | |
| 111 | + return CONDITION_SCALES[scale] ?? CONDITION_SCALES.general!; | |
| 112 | +} | |
| 113 | + | |
| 114 | +/** Map a raw condition string to the category's normalised slug; null when unknown (never guess). */ | |
| 115 | +export function normalizeCondition(categorySlug: string, raw: string | null | undefined): string | null { | |
| 116 | + if (!raw) return null; | |
| 117 | + const scale = conditionScaleFor(categorySlug); | |
| 118 | + const key = raw.trim().toLowerCase().replace(/\s+/g, ' '); | |
| 119 | + if (key in scale.aliases) return scale.aliases[key] ?? null; | |
| 120 | + const asSlug = key.replace(/[\s-]+/g, '_'); | |
| 121 | + if (scale.values.includes(asSlug)) return asSlug; | |
| 122 | + // Try contained alias (e.g. "Condition: Near Mint or Better") | |
| 123 | + for (const [alias, slug] of Object.entries(scale.aliases)) { | |
| 124 | + if (alias.length >= 4 && key.includes(alias)) return slug; | |
| 125 | + } | |
| 126 | + return null; | |
| 127 | +} | |
| 128 | + | |
| 129 | +export function conditionRank(categorySlug: string, condition: string | null): number | null { | |
| 130 | + if (!condition) return null; | |
| 131 | + const i = conditionScaleFor(categorySlug).values.indexOf(condition); | |
| 132 | + return i >= 0 ? i : null; | |
| 133 | +} | |
| 134 | + | |
| 135 | +// ---------- Graders ---------- | |
| 136 | +export interface GraderDef { | |
| 137 | + slug: string; | |
| 138 | + name: string; | |
| 139 | + categories: string[]; | |
| 140 | + scale: { type: 'numeric' | 'sheldon' | 'descriptive'; values: string[]; top: string }; | |
| 141 | + populationUrl?: string; | |
| 142 | + verifyUrl?: string; | |
| 143 | + aliases: string[]; | |
| 144 | +} | |
| 145 | +export const GRADERS: readonly GraderDef[] = gradersJson.graders as GraderDef[]; | |
| 146 | +const graderByAlias = new Map<string, GraderDef>(); | |
| 147 | +for (const g of GRADERS) { | |
| 148 | + graderByAlias.set(g.slug, g); | |
| 149 | + for (const a of g.aliases) graderByAlias.set(a.toLowerCase(), g); | |
| 150 | +} | |
| 151 | +export function getGrader(slugOrAlias: string | null | undefined): GraderDef | undefined { | |
| 152 | + if (!slugOrAlias) return undefined; | |
| 153 | + return graderByAlias.get(slugOrAlias.trim().toLowerCase()); | |
| 154 | +} | |
| 155 | + | |
| 156 | +const GRADE_RE = /\b(PSA|BGS|BECKETT|CGC|SGC|TAG|ACE|CBCS|PGX|WATA|VGA|PCGS|NGC|ANACS|ICCS|PMG)\b[\s:-]*(?:GEM\s*MT|GEM\s*MINT|MINT|NM-?MT|PRISTINE|BLACK\s*LABEL)?[\s:-]*(\d{1,3}(?:\.\d)?)?/i; | |
| 157 | + | |
| 158 | +/** Extract grader + grade from a free-text title. Returns nulls when absent. */ | |
| 159 | +export function parseGradeFromTitle(title: string): { grader: string | null; grade: string | null; qualifier: string | null } { | |
| 160 | + const m = title.match(GRADE_RE); | |
| 161 | + if (!m) { | |
| 162 | + if (/\b(raw|ungraded)\b/i.test(title)) return { grader: 'raw', grade: null, qualifier: null }; | |
| 163 | + return { grader: null, grade: null, qualifier: null }; | |
| 164 | + } | |
| 165 | + const grader = getGrader(m[1]!)?.slug ?? m[1]!.toLowerCase(); | |
| 166 | + let grade = m[2] ?? null; | |
| 167 | + const g = getGrader(grader); | |
| 168 | + if (grade && g && g.scale.values.length && !g.scale.values.includes(grade)) { | |
| 169 | + // e.g. "PSA 10" where 10 is fine; "PSA 2021" is a year → reject | |
| 170 | + if (Number(grade) > Number(g.scale.top)) grade = null; | |
| 171 | + } | |
| 172 | + let qualifier: string | null = null; | |
| 173 | + if (/black\s*label/i.test(title)) qualifier = 'Black Label'; | |
| 174 | + else if (/pristine/i.test(title) && grader === 'bgs') qualifier = 'Pristine'; | |
| 175 | + else if (/signature\s*series/i.test(title)) qualifier = 'Signature Series'; | |
| 176 | + else if (/\b(OC|MC|ST|PD|MK)\b/.test(title) && grader === 'psa') qualifier = title.match(/\b(OC|MC|ST|PD|MK)\b/)![1]!; | |
| 177 | + return { grader, grade, qualifier }; | |
| 178 | +} | |
| 179 | + | |
| 180 | +/** Variant key used by asset_variants (deterministic). */ | |
| 181 | +export function variantKey(input: { grader?: string | null; grade?: string | null; qualifier?: string | null; condition?: string | null; completeness?: string | null; size?: string | null }): { key: string; label: string } { | |
| 182 | + const parts: string[] = []; | |
| 183 | + const labelParts: string[] = []; | |
| 184 | + if (input.grader && input.grader !== 'raw' && input.grade) { | |
| 185 | + parts.push(input.grader, input.grade); | |
| 186 | + labelParts.push(`${getGrader(input.grader)?.name ?? input.grader.toUpperCase()} ${input.grade}`); | |
| 187 | + if (input.qualifier) { | |
| 188 | + parts.push(input.qualifier.toLowerCase().replace(/\s+/g, '_')); | |
| 189 | + labelParts.push(input.qualifier); | |
| 190 | + } | |
| 191 | + } else { | |
| 192 | + parts.push('raw'); | |
| 193 | + if (input.completeness) { | |
| 194 | + parts.push(input.completeness); | |
| 195 | + labelParts.push(humanize(input.completeness)); | |
| 196 | + } else if (input.condition) { | |
| 197 | + parts.push(input.condition); | |
| 198 | + labelParts.push(humanize(input.condition)); | |
| 199 | + } else { | |
| 200 | + labelParts.push('Raw / ungraded'); | |
| 201 | + } | |
| 202 | + } | |
| 203 | + if (input.size) { | |
| 204 | + parts.push(`size_${input.size.toLowerCase().replace(/\s+/g, '')}`); | |
| 205 | + labelParts.push(`Size ${input.size}`); | |
| 206 | + } | |
| 207 | + return { key: parts.join('|'), label: labelParts.join(' · ') }; | |
| 208 | +} | |
| 209 | + | |
| 210 | +export function humanize(slug: string): string { | |
| 211 | + return slug.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase()).replace(/\bCib\b/, 'CIB'); | |
| 212 | +} | |
| 213 | + | |
| 214 | +// ---------- Indices ---------- | |
| 215 | +export interface IndexDef { | |
| 216 | + ticker: string; | |
| 217 | + name: string; | |
| 218 | + flagship?: boolean; | |
| 219 | + description?: string; | |
| 220 | + families: string[]; | |
| 221 | + color: string; | |
| 222 | + minConstituents: number; | |
| 223 | +} | |
| 224 | +export const INDEX_BASE_DATE: string = indicesJson.baseDate; | |
| 225 | +export const INDEX_BASE_VALUE: number = indicesJson.baseValue; | |
| 226 | +export const INDICES: readonly IndexDef[] = indicesJson.indices as IndexDef[]; | |
| 227 | +export function indexForCategory(categorySlug: string): IndexDef | undefined { | |
| 228 | + const ticker = bySlug.get(categorySlug)?.index; | |
| 229 | + return ticker ? INDICES.find((i) => i.ticker === ticker) : undefined; | |
| 230 | +} | |
added
packages/taxonomy/src/taxonomy.test.ts
+35 −0
@@ -0,0 +1,35 @@ | ||
| 1 | +import { describe, expect, it } from 'vitest'; | |
| 2 | +import { CATEGORIES, FAMILIES, getCategory, normalizeCondition, parseGradeFromTitle, variantKey, indexForCategory, descendants } from './index.js'; | |
| 3 | + | |
| 4 | +describe('taxonomy', () => { | |
| 5 | + it('loads a large, consistent tree', () => { | |
| 6 | + expect(FAMILIES.length).toBeGreaterThan(90); | |
| 7 | + expect(CATEGORIES.length).toBeGreaterThan(FAMILIES.length); | |
| 8 | + const slugs = new Set(CATEGORIES.map((c) => c.slug)); | |
| 9 | + expect(slugs.size).toBe(CATEGORIES.length); | |
| 10 | + expect(getCategory('pokemon')?.familySlug).toBe('trading_cards'); | |
| 11 | + expect(getCategory('pokemon')?.index).toBe('RARE-TCG'); | |
| 12 | + expect(descendants('trading_cards')).toContain('pokemon'); | |
| 13 | + }); | |
| 14 | + it('normalises conditions per scale', () => { | |
| 15 | + expect(normalizeCondition('pokemon', 'Near Mint')).toBe('near_mint'); | |
| 16 | + expect(normalizeCondition('nintendo_games', 'Complete In Box')).toBe('cib'); | |
| 17 | + expect(normalizeCondition('nike_jordan', 'DS')).toBe('deadstock'); | |
| 18 | + expect(normalizeCondition('rolex', 'Unworn')).toBe('unworn'); | |
| 19 | + expect(normalizeCondition('rolex', 'weird')).toBeNull(); | |
| 20 | + }); | |
| 21 | + it('parses grades', () => { | |
| 22 | + expect(parseGradeFromTitle('1999 Pokemon Base Charizard 1st PSA 10')).toMatchObject({ grader: 'psa', grade: '10' }); | |
| 23 | + expect(parseGradeFromTitle('Charizard BGS 9.5 Black Label')).toMatchObject({ grader: 'bgs', grade: '9.5', qualifier: 'Black Label' }); | |
| 24 | + expect(parseGradeFromTitle('Amazing Fantasy 15 CGC 3.0')).toMatchObject({ grader: 'cgc', grade: '3.0' }); | |
| 25 | + expect(parseGradeFromTitle('Super Mario 64 WATA 9.8 A++')).toMatchObject({ grader: 'wata', grade: '9.8' }); | |
| 26 | + expect(parseGradeFromTitle('Rolex Daytona 116500LN')).toMatchObject({ grader: null, grade: null }); | |
| 27 | + expect(parseGradeFromTitle('1952 Topps Mantle raw')).toMatchObject({ grader: 'raw' }); | |
| 28 | + }); | |
| 29 | + it('builds variant keys', () => { | |
| 30 | + expect(variantKey({ grader: 'psa', grade: '10' })).toEqual({ key: 'psa|10', label: 'PSA 10' }); | |
| 31 | + expect(variantKey({ completeness: 'sealed' })).toEqual({ key: 'raw|sealed', label: 'Sealed' }); | |
| 32 | + expect(variantKey({ size: '10' }).key).toBe('raw|size_10'); | |
| 33 | + expect(indexForCategory('rolex')?.ticker).toBe('RARE-WATCH'); | |
| 34 | + }); | |
| 35 | +}); | |
added
packages/taxonomy/tsconfig.json
+9 −0
@@ -0,0 +1,9 @@ | ||
| 1 | +{ | |
| 2 | + "extends": "../../tsconfig.base.json", | |
| 3 | + "compilerOptions": { | |
| 4 | + "rootDir": "../..", | |
| 5 | + "outDir": "dist", | |
| 6 | + "noEmit": true | |
| 7 | + }, | |
| 8 | + "include": ["src", "../../data/taxonomy/*.json"] | |
| 9 | +} | |
added
packages/taxonomy/vitest.config.ts
+5 −0
@@ -0,0 +1,5 @@ | ||
| 1 | +import { defineConfig } from 'vitest/config'; | |
| 2 | + | |
| 3 | +export default defineConfig({ | |
| 4 | + test: { include: ['src/**/*.test.ts'] }, | |
| 5 | +}); | |
added
pnpm-lock.yaml
+6244 −0
@@ -0,0 +1,6244 @@ | ||
| 1 | +lockfileVersion: '9.0' | |
| 2 | + | |
| 3 | +settings: | |
| 4 | + autoInstallPeers: true | |
| 5 | + excludeLinksFromLockfile: false | |
| 6 | + | |
| 7 | +importers: | |
| 8 | + | |
| 9 | + .: | |
| 10 | + devDependencies: | |
| 11 | + '@types/node': | |
| 12 | + specifier: ^24.0.0 | |
| 13 | + version: 24.13.3 | |
| 14 | + tsx: | |
| 15 | + specifier: ^4.20.0 | |
| 16 | + version: 4.23.13 | |
| 17 | + typescript: | |
| 18 | + specifier: ^5.9.3 | |
| 19 | + version: 5.9.3 | |
| 20 | + vitest: | |
| 21 | + specifier: ^3.2.0 | |
| 22 | + version: 3.2.7(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.13) | |
| 23 | + | |
| 24 | + apps/api: | |
| 25 | + dependencies: | |
| 26 | + '@rareindex/shared': | |
| 27 | + specifier: workspace:* | |
| 28 | + version: link:../../packages/shared | |
| 29 | + devDependencies: | |
| 30 | + '@types/node': | |
| 31 | + specifier: ^24.0.0 | |
| 32 | + version: 24.13.3 | |
| 33 | + typescript: | |
| 34 | + specifier: ^5.9.3 | |
| 35 | + version: 5.9.3 | |
| 36 | + vitest: | |
| 37 | + specifier: ^3.2.0 | |
| 38 | + version: 3.2.7(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.13) | |
| 39 | + | |
| 40 | + apps/web: | |
| 41 | + dependencies: | |
| 42 | + '@rareindex/connectors': | |
| 43 | + specifier: workspace:* | |
| 44 | + version: link:../../packages/connectors | |
| 45 | + '@rareindex/database': | |
| 46 | + specifier: workspace:* | |
| 47 | + version: link:../../packages/database | |
| 48 | + '@rareindex/shared': | |
| 49 | + specifier: workspace:* | |
| 50 | + version: link:../../packages/shared | |
| 51 | + '@rareindex/taxonomy': | |
| 52 | + specifier: workspace:* | |
| 53 | + version: link:../../packages/taxonomy | |
| 54 | + '@tanstack/react-query': | |
| 55 | + specifier: ^5.90.0 | |
| 56 | + version: 5.102.8(react@19.2.8) | |
| 57 | + lucide-react: | |
| 58 | + specifier: ^1.0.0 | |
| 59 | + version: 1.41.0(react@19.2.8) | |
| 60 | + next: | |
| 61 | + specifier: 16.3.4 | |
| 62 | + version: 16.3.4(@babel/core@7.29.7)(@types/node@24.13.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) | |
| 63 | + react: | |
| 64 | + specifier: 19.2.8 | |
| 65 | + version: 19.2.8 | |
| 66 | + react-dom: | |
| 67 | + specifier: 19.2.8 | |
| 68 | + version: 19.2.8(react@19.2.8) | |
| 69 | + server-only: | |
| 70 | + specifier: ^0.0.1 | |
| 71 | + version: 0.0.1 | |
| 72 | + zod: | |
| 73 | + specifier: ^4.0.0 | |
| 74 | + version: 4.5.4 | |
| 75 | + devDependencies: | |
| 76 | + '@tailwindcss/postcss': | |
| 77 | + specifier: ^4 | |
| 78 | + version: 4.3.3 | |
| 79 | + '@types/node': | |
| 80 | + specifier: ^24.0.0 | |
| 81 | + version: 24.13.3 | |
| 82 | + '@types/react': | |
| 83 | + specifier: ^19 | |
| 84 | + version: 19.2.18 | |
| 85 | + '@types/react-dom': | |
| 86 | + specifier: ^19 | |
| 87 | + version: 19.2.7(@types/react@19.2.18) | |
| 88 | + eslint: | |
| 89 | + specifier: ^9 | |
| 90 | + version: 9.39.5(jiti@2.7.0) | |
| 91 | + eslint-config-next: | |
| 92 | + specifier: 16.3.4 | |
| 93 | + version: 16.3.4(@typescript-eslint/parser@8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) | |
| 94 | + tailwindcss: | |
| 95 | + specifier: ^4 | |
| 96 | + version: 4.3.3 | |
| 97 | + typescript: | |
| 98 | + specifier: ^5.9.3 | |
| 99 | + version: 5.9.3 | |
| 100 | + vitest: | |
| 101 | + specifier: ^3.2.0 | |
| 102 | + version: 3.2.7(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.13) | |
| 103 | + | |
| 104 | + connectors: | |
| 105 | + dependencies: | |
| 106 | + '@rareindex/connectors': | |
| 107 | + specifier: workspace:* | |
| 108 | + version: link:../packages/connectors | |
| 109 | + '@rareindex/shared': | |
| 110 | + specifier: workspace:* | |
| 111 | + version: link:../packages/shared | |
| 112 | + '@rareindex/taxonomy': | |
| 113 | + specifier: workspace:* | |
| 114 | + version: link:../packages/taxonomy | |
| 115 | + zod: | |
| 116 | + specifier: ^4.0.0 | |
| 117 | + version: 4.5.4 | |
| 118 | + devDependencies: | |
| 119 | + '@types/node': | |
| 120 | + specifier: ^24.0.0 | |
| 121 | + version: 24.13.3 | |
| 122 | + typescript: | |
| 123 | + specifier: ^5.9.3 | |
| 124 | + version: 5.9.3 | |
| 125 | + vitest: | |
| 126 | + specifier: ^3.2.0 | |
| 127 | + version: 3.2.7(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.13) | |
| 128 | + | |
| 129 | + packages/connectors: | |
| 130 | + dependencies: | |
| 131 | + '@rareindex/shared': | |
| 132 | + specifier: workspace:* | |
| 133 | + version: link:../shared | |
| 134 | + '@rareindex/taxonomy': | |
| 135 | + specifier: workspace:* | |
| 136 | + version: link:../taxonomy | |
| 137 | + cheerio: | |
| 138 | + specifier: ^1.1.0 | |
| 139 | + version: 1.2.0 | |
| 140 | + zod: | |
| 141 | + specifier: ^4.0.0 | |
| 142 | + version: 4.5.4 | |
| 143 | + devDependencies: | |
| 144 | + '@types/node': | |
| 145 | + specifier: ^24.0.0 | |
| 146 | + version: 24.13.3 | |
| 147 | + typescript: | |
| 148 | + specifier: ^5.9.3 | |
| 149 | + version: 5.9.3 | |
| 150 | + vitest: | |
| 151 | + specifier: ^3.2.0 | |
| 152 | + version: 3.2.7(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.13) | |
| 153 | + | |
| 154 | + packages/database: | |
| 155 | + dependencies: | |
| 156 | + '@rareindex/shared': | |
| 157 | + specifier: workspace:* | |
| 158 | + version: link:../shared | |
| 159 | + '@rareindex/taxonomy': | |
| 160 | + specifier: workspace:* | |
| 161 | + version: link:../taxonomy | |
| 162 | + drizzle-orm: | |
| 163 | + specifier: ^0.45.0 | |
| 164 | + version: 0.45.2(postgres@3.4.9) | |
| 165 | + postgres: | |
| 166 | + specifier: ^3.4.7 | |
| 167 | + version: 3.4.9 | |
| 168 | + devDependencies: | |
| 169 | + '@types/node': | |
| 170 | + specifier: ^24.0.0 | |
| 171 | + version: 24.13.3 | |
| 172 | + drizzle-kit: | |
| 173 | + specifier: ^0.31.0 | |
| 174 | + version: 0.31.10 | |
| 175 | + tsx: | |
| 176 | + specifier: ^4.20.0 | |
| 177 | + version: 4.23.13 | |
| 178 | + typescript: | |
| 179 | + specifier: ^5.9.3 | |
| 180 | + version: 5.9.3 | |
| 181 | + vitest: | |
| 182 | + specifier: ^3.2.0 | |
| 183 | + version: 3.2.7(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.13) | |
| 184 | + | |
| 185 | + packages/shared: | |
| 186 | + dependencies: | |
| 187 | + pino: | |
| 188 | + specifier: ^9.7.0 | |
| 189 | + version: 9.14.0 | |
| 190 | + zod: | |
| 191 | + specifier: ^4.0.0 | |
| 192 | + version: 4.5.4 | |
| 193 | + devDependencies: | |
| 194 | + '@types/node': | |
| 195 | + specifier: ^24.0.0 | |
| 196 | + version: 24.13.3 | |
| 197 | + typescript: | |
| 198 | + specifier: ^5.9.3 | |
| 199 | + version: 5.9.3 | |
| 200 | + vitest: | |
| 201 | + specifier: ^3.2.0 | |
| 202 | + version: 3.2.7(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.13) | |
| 203 | + | |
| 204 | + packages/taxonomy: | |
| 205 | + dependencies: | |
| 206 | + '@rareindex/shared': | |
| 207 | + specifier: workspace:* | |
| 208 | + version: link:../shared | |
| 209 | + zod: | |
| 210 | + specifier: ^4.0.0 | |
| 211 | + version: 4.5.4 | |
| 212 | + devDependencies: | |
| 213 | + '@types/node': | |
| 214 | + specifier: ^24.0.0 | |
| 215 | + version: 24.13.3 | |
| 216 | + typescript: | |
| 217 | + specifier: ^5.9.3 | |
| 218 | + version: 5.9.3 | |
| 219 | + vitest: | |
| 220 | + specifier: ^3.2.0 | |
| 221 | + version: 3.2.7(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.13) | |
| 222 | + | |
| 223 | + workers: | |
| 224 | + dependencies: | |
| 225 | + '@rareindex/shared': | |
| 226 | + specifier: workspace:* | |
| 227 | + version: link:../packages/shared | |
| 228 | + devDependencies: | |
| 229 | + '@types/node': | |
| 230 | + specifier: ^24.0.0 | |
| 231 | + version: 24.13.3 | |
| 232 | + typescript: | |
| 233 | + specifier: ^5.9.3 | |
| 234 | + version: 5.9.3 | |
| 235 | + vitest: | |
| 236 | + specifier: ^3.2.0 | |
| 237 | + version: 3.2.7(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.13) | |
| 238 | + | |
| 239 | +packages: | |
| 240 | + | |
| 241 | + '@alloc/quick-lru@5.3.0': | |
| 242 | + resolution: {integrity: sha512-U4+70Pc5ZS9osnCBCE5Jha/ciHM+Yp+CNMNC/7HvYbNRk1Ldd+f7qO65W5qfhu/TCv+/ozljlXXe9Nj8419DMA==} | |
| 243 | + engines: {node: '>=10'} | |
| 244 | + | |
| 245 | + '@babel/code-frame@7.29.7': | |
| 246 | + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} | |
| 247 | + engines: {node: '>=6.9.0'} | |
| 248 | + | |
| 249 | + '@babel/compat-data@7.29.7': | |
| 250 | + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} | |
| 251 | + engines: {node: '>=6.9.0'} | |
| 252 | + | |
| 253 | + '@babel/core@7.29.7': | |
| 254 | + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} | |
| 255 | + engines: {node: '>=6.9.0'} | |
| 256 | + | |
| 257 | + '@babel/generator@7.29.8': | |
| 258 | + resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==} | |
| 259 | + engines: {node: '>=6.9.0'} | |
| 260 | + | |
| 261 | + '@babel/helper-compilation-targets@7.29.7': | |
| 262 | + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} | |
| 263 | + engines: {node: '>=6.9.0'} | |
| 264 | + | |
| 265 | + '@babel/helper-globals@7.29.7': | |
| 266 | + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} | |
| 267 | + engines: {node: '>=6.9.0'} | |
| 268 | + | |
| 269 | + '@babel/helper-module-imports@7.29.7': | |
| 270 | + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} | |
| 271 | + engines: {node: '>=6.9.0'} | |
| 272 | + | |
| 273 | + '@babel/helper-module-transforms@7.29.7': | |
| 274 | + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} | |
| 275 | + engines: {node: '>=6.9.0'} | |
| 276 | + peerDependencies: | |
| 277 | + '@babel/core': ^7.0.0 | |
| 278 | + | |
| 279 | + '@babel/helper-string-parser@7.29.7': | |
| 280 | + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} | |
| 281 | + engines: {node: '>=6.9.0'} | |
| 282 | + | |
| 283 | + '@babel/helper-validator-identifier@7.29.7': | |
| 284 | + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} | |
| 285 | + engines: {node: '>=6.9.0'} | |
| 286 | + | |
| 287 | + '@babel/helper-validator-option@7.29.7': | |
| 288 | + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} | |
| 289 | + engines: {node: '>=6.9.0'} | |
| 290 | + | |
| 291 | + '@babel/helpers@7.29.7': | |
| 292 | + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} | |
| 293 | + engines: {node: '>=6.9.0'} | |
| 294 | + | |
| 295 | + '@babel/parser@7.29.8': | |
| 296 | + resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==} | |
| 297 | + engines: {node: '>=6.0.0'} | |
| 298 | + hasBin: true | |
| 299 | + | |
| 300 | + '@babel/template@7.29.7': | |
| 301 | + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} | |
| 302 | + engines: {node: '>=6.9.0'} | |
| 303 | + | |
| 304 | + '@babel/traverse@7.29.8': | |
| 305 | + resolution: {integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==} | |
| 306 | + engines: {node: '>=6.9.0'} | |
| 307 | + | |
| 308 | + '@babel/types@7.29.8': | |
| 309 | + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} | |
| 310 | + engines: {node: '>=6.9.0'} | |
| 311 | + | |
| 312 | + '@drizzle-team/brocli@0.10.2': | |
| 313 | + resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} | |
| 314 | + | |
| 315 | + '@emnapi/core@1.10.0': | |
| 316 | + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} | |
| 317 | + | |
| 318 | + '@emnapi/runtime@1.10.0': | |
| 319 | + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} | |
| 320 | + | |
| 321 | + '@emnapi/runtime@1.11.3': | |
| 322 | + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} | |
| 323 | + | |
| 324 | + '@emnapi/wasi-threads@1.2.1': | |
| 325 | + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} | |
| 326 | + | |
| 327 | + '@esbuild-kit/core-utils@3.3.2': | |
| 328 | + resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} | |
| 329 | + deprecated: 'Merged into tsx: https://tsx.hirok.io' | |
| 330 | + | |
| 331 | + '@esbuild-kit/esm-loader@2.6.5': | |
| 332 | + resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} | |
| 333 | + deprecated: 'Merged into tsx: https://tsx.hirok.io' | |
| 334 | + | |
| 335 | + '@esbuild/aix-ppc64@0.25.12': | |
| 336 | + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} | |
| 337 | + engines: {node: '>=18'} | |
| 338 | + cpu: [ppc64] | |
| 339 | + os: [aix] | |
| 340 | + | |
| 341 | + '@esbuild/aix-ppc64@0.28.2': | |
| 342 | + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} | |
| 343 | + engines: {node: '>=18'} | |
| 344 | + cpu: [ppc64] | |
| 345 | + os: [aix] | |
| 346 | + | |
| 347 | + '@esbuild/android-arm64@0.18.20': | |
| 348 | + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} | |
| 349 | + engines: {node: '>=12'} | |
| 350 | + cpu: [arm64] | |
| 351 | + os: [android] | |
| 352 | + | |
| 353 | + '@esbuild/android-arm64@0.25.12': | |
| 354 | + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} | |
| 355 | + engines: {node: '>=18'} | |
| 356 | + cpu: [arm64] | |
| 357 | + os: [android] | |
| 358 | + | |
| 359 | + '@esbuild/android-arm64@0.28.2': | |
| 360 | + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} | |
| 361 | + engines: {node: '>=18'} | |
| 362 | + cpu: [arm64] | |
| 363 | + os: [android] | |
| 364 | + | |
| 365 | + '@esbuild/android-arm@0.18.20': | |
| 366 | + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} | |
| 367 | + engines: {node: '>=12'} | |
| 368 | + cpu: [arm] | |
| 369 | + os: [android] | |
| 370 | + | |
| 371 | + '@esbuild/android-arm@0.25.12': | |
| 372 | + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} | |
| 373 | + engines: {node: '>=18'} | |
| 374 | + cpu: [arm] | |
| 375 | + os: [android] | |
| 376 | + | |
| 377 | + '@esbuild/android-arm@0.28.2': | |
| 378 | + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} | |
| 379 | + engines: {node: '>=18'} | |
| 380 | + cpu: [arm] | |
| 381 | + os: [android] | |
| 382 | + | |
| 383 | + '@esbuild/android-x64@0.18.20': | |
| 384 | + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} | |
| 385 | + engines: {node: '>=12'} | |
| 386 | + cpu: [x64] | |
| 387 | + os: [android] | |
| 388 | + | |
| 389 | + '@esbuild/android-x64@0.25.12': | |
| 390 | + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} | |
| 391 | + engines: {node: '>=18'} | |
| 392 | + cpu: [x64] | |
| 393 | + os: [android] | |
| 394 | + | |
| 395 | + '@esbuild/android-x64@0.28.2': | |
| 396 | + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} | |
| 397 | + engines: {node: '>=18'} | |
| 398 | + cpu: [x64] | |
| 399 | + os: [android] | |
| 400 | + | |
| 401 | + '@esbuild/darwin-arm64@0.18.20': | |
| 402 | + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} | |
| 403 | + engines: {node: '>=12'} | |
| 404 | + cpu: [arm64] | |
| 405 | + os: [darwin] | |
| 406 | + | |
| 407 | + '@esbuild/darwin-arm64@0.25.12': | |
| 408 | + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} | |
| 409 | + engines: {node: '>=18'} | |
| 410 | + cpu: [arm64] | |
| 411 | + os: [darwin] | |
| 412 | + | |
| 413 | + '@esbuild/darwin-arm64@0.28.2': | |
| 414 | + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} | |
| 415 | + engines: {node: '>=18'} | |
| 416 | + cpu: [arm64] | |
| 417 | + os: [darwin] | |
| 418 | + | |
| 419 | + '@esbuild/darwin-x64@0.18.20': | |
| 420 | + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} | |
| 421 | + engines: {node: '>=12'} | |
| 422 | + cpu: [x64] | |
| 423 | + os: [darwin] | |
| 424 | + | |
| 425 | + '@esbuild/darwin-x64@0.25.12': | |
| 426 | + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} | |
| 427 | + engines: {node: '>=18'} | |
| 428 | + cpu: [x64] | |
| 429 | + os: [darwin] | |
| 430 | + | |
| 431 | + '@esbuild/darwin-x64@0.28.2': | |
| 432 | + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} | |
| 433 | + engines: {node: '>=18'} | |
| 434 | + cpu: [x64] | |
| 435 | + os: [darwin] | |
| 436 | + | |
| 437 | + '@esbuild/freebsd-arm64@0.18.20': | |
| 438 | + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} | |
| 439 | + engines: {node: '>=12'} | |
| 440 | + cpu: [arm64] | |
| 441 | + os: [freebsd] | |
| 442 | + | |
| 443 | + '@esbuild/freebsd-arm64@0.25.12': | |
| 444 | + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} | |
| 445 | + engines: {node: '>=18'} | |
| 446 | + cpu: [arm64] | |
| 447 | + os: [freebsd] | |
| 448 | + | |
| 449 | + '@esbuild/freebsd-arm64@0.28.2': | |
| 450 | + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} | |
| 451 | + engines: {node: '>=18'} | |
| 452 | + cpu: [arm64] | |
| 453 | + os: [freebsd] | |
| 454 | + | |
| 455 | + '@esbuild/freebsd-x64@0.18.20': | |
| 456 | + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} | |
| 457 | + engines: {node: '>=12'} | |
| 458 | + cpu: [x64] | |
| 459 | + os: [freebsd] | |
| 460 | + | |
| 461 | + '@esbuild/freebsd-x64@0.25.12': | |
| 462 | + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} | |
| 463 | + engines: {node: '>=18'} | |
| 464 | + cpu: [x64] | |
| 465 | + os: [freebsd] | |
| 466 | + | |
| 467 | + '@esbuild/freebsd-x64@0.28.2': | |
| 468 | + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} | |
| 469 | + engines: {node: '>=18'} | |
| 470 | + cpu: [x64] | |
| 471 | + os: [freebsd] | |
| 472 | + | |
| 473 | + '@esbuild/linux-arm64@0.18.20': | |
| 474 | + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} | |
| 475 | + engines: {node: '>=12'} | |
| 476 | + cpu: [arm64] | |
| 477 | + os: [linux] | |
| 478 | + | |
| 479 | + '@esbuild/linux-arm64@0.25.12': | |
| 480 | + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} | |
| 481 | + engines: {node: '>=18'} | |
| 482 | + cpu: [arm64] | |
| 483 | + os: [linux] | |
| 484 | + | |
| 485 | + '@esbuild/linux-arm64@0.28.2': | |
| 486 | + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} | |
| 487 | + engines: {node: '>=18'} | |
| 488 | + cpu: [arm64] | |
| 489 | + os: [linux] | |
| 490 | + | |
| 491 | + '@esbuild/linux-arm@0.18.20': | |
| 492 | + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} | |
| 493 | + engines: {node: '>=12'} | |
| 494 | + cpu: [arm] | |
| 495 | + os: [linux] | |
| 496 | + | |
| 497 | + '@esbuild/linux-arm@0.25.12': | |
| 498 | + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} | |
| 499 | + engines: {node: '>=18'} | |
| 500 | + cpu: [arm] | |
| 501 | + os: [linux] | |
| 502 | + | |
| 503 | + '@esbuild/linux-arm@0.28.2': | |
| 504 | + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} | |
| 505 | + engines: {node: '>=18'} | |
| 506 | + cpu: [arm] | |
| 507 | + os: [linux] | |
| 508 | + | |
| 509 | + '@esbuild/linux-ia32@0.18.20': | |
| 510 | + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} | |
| 511 | + engines: {node: '>=12'} | |
| 512 | + cpu: [ia32] | |
| 513 | + os: [linux] | |
| 514 | + | |
| 515 | + '@esbuild/linux-ia32@0.25.12': | |
| 516 | + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} | |
| 517 | + engines: {node: '>=18'} | |
| 518 | + cpu: [ia32] | |
| 519 | + os: [linux] | |
| 520 | + | |
| 521 | + '@esbuild/linux-ia32@0.28.2': | |
| 522 | + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} | |
| 523 | + engines: {node: '>=18'} | |
| 524 | + cpu: [ia32] | |
| 525 | + os: [linux] | |
| 526 | + | |
| 527 | + '@esbuild/linux-loong64@0.18.20': | |
| 528 | + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} | |
| 529 | + engines: {node: '>=12'} | |
| 530 | + cpu: [loong64] | |
| 531 | + os: [linux] | |
| 532 | + | |
| 533 | + '@esbuild/linux-loong64@0.25.12': | |
| 534 | + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} | |
| 535 | + engines: {node: '>=18'} | |
| 536 | + cpu: [loong64] | |
| 537 | + os: [linux] | |
| 538 | + | |
| 539 | + '@esbuild/linux-loong64@0.28.2': | |
| 540 | + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} | |
| 541 | + engines: {node: '>=18'} | |
| 542 | + cpu: [loong64] | |
| 543 | + os: [linux] | |
| 544 | + | |
| 545 | + '@esbuild/linux-mips64el@0.18.20': | |
| 546 | + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} | |
| 547 | + engines: {node: '>=12'} | |
| 548 | + cpu: [mips64el] | |
| 549 | + os: [linux] | |
| 550 | + | |
| 551 | + '@esbuild/linux-mips64el@0.25.12': | |
| 552 | + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} | |
| 553 | + engines: {node: '>=18'} | |
| 554 | + cpu: [mips64el] | |
| 555 | + os: [linux] | |
| 556 | + | |
| 557 | + '@esbuild/linux-mips64el@0.28.2': | |
| 558 | + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} | |
| 559 | + engines: {node: '>=18'} | |
| 560 | + cpu: [mips64el] | |
| 561 | + os: [linux] | |
| 562 | + | |
| 563 | + '@esbuild/linux-ppc64@0.18.20': | |
| 564 | + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} | |
| 565 | + engines: {node: '>=12'} | |
| 566 | + cpu: [ppc64] | |
| 567 | + os: [linux] | |
| 568 | + | |
| 569 | + '@esbuild/linux-ppc64@0.25.12': | |
| 570 | + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} | |
| 571 | + engines: {node: '>=18'} | |
| 572 | + cpu: [ppc64] | |
| 573 | + os: [linux] | |
| 574 | + | |
| 575 | + '@esbuild/linux-ppc64@0.28.2': | |
| 576 | + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} | |
| 577 | + engines: {node: '>=18'} | |
| 578 | + cpu: [ppc64] | |
| 579 | + os: [linux] | |
| 580 | + | |
| 581 | + '@esbuild/linux-riscv64@0.18.20': | |
| 582 | + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} | |
| 583 | + engines: {node: '>=12'} | |
| 584 | + cpu: [riscv64] | |
| 585 | + os: [linux] | |
| 586 | + | |
| 587 | + '@esbuild/linux-riscv64@0.25.12': | |
| 588 | + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} | |
| 589 | + engines: {node: '>=18'} | |
| 590 | + cpu: [riscv64] | |
| 591 | + os: [linux] | |
| 592 | + | |
| 593 | + '@esbuild/linux-riscv64@0.28.2': | |
| 594 | + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} | |
| 595 | + engines: {node: '>=18'} | |
| 596 | + cpu: [riscv64] | |
| 597 | + os: [linux] | |
| 598 | + | |
| 599 | + '@esbuild/linux-s390x@0.18.20': | |
| 600 | + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} | |
| 601 | + engines: {node: '>=12'} | |
| 602 | + cpu: [s390x] | |
| 603 | + os: [linux] | |
| 604 | + | |
| 605 | + '@esbuild/linux-s390x@0.25.12': | |
| 606 | + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} | |
| 607 | + engines: {node: '>=18'} | |
| 608 | + cpu: [s390x] | |
| 609 | + os: [linux] | |
| 610 | + | |
| 611 | + '@esbuild/linux-s390x@0.28.2': | |
| 612 | + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} | |
| 613 | + engines: {node: '>=18'} | |
| 614 | + cpu: [s390x] | |
| 615 | + os: [linux] | |
| 616 | + | |
| 617 | + '@esbuild/linux-x64@0.18.20': | |
| 618 | + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} | |
| 619 | + engines: {node: '>=12'} | |
| 620 | + cpu: [x64] | |
| 621 | + os: [linux] | |
| 622 | + | |
| 623 | + '@esbuild/linux-x64@0.25.12': | |
| 624 | + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} | |
| 625 | + engines: {node: '>=18'} | |
| 626 | + cpu: [x64] | |
| 627 | + os: [linux] | |
| 628 | + | |
| 629 | + '@esbuild/linux-x64@0.28.2': | |
| 630 | + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} | |
| 631 | + engines: {node: '>=18'} | |
| 632 | + cpu: [x64] | |
| 633 | + os: [linux] | |
| 634 | + | |
| 635 | + '@esbuild/netbsd-arm64@0.25.12': | |
| 636 | + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} | |
| 637 | + engines: {node: '>=18'} | |
| 638 | + cpu: [arm64] | |
| 639 | + os: [netbsd] | |
| 640 | + | |
| 641 | + '@esbuild/netbsd-arm64@0.28.2': | |
| 642 | + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} | |
| 643 | + engines: {node: '>=18'} | |
| 644 | + cpu: [arm64] | |
| 645 | + os: [netbsd] | |
| 646 | + | |
| 647 | + '@esbuild/netbsd-x64@0.18.20': | |
| 648 | + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} | |
| 649 | + engines: {node: '>=12'} | |
| 650 | + cpu: [x64] | |
| 651 | + os: [netbsd] | |
| 652 | + | |
| 653 | + '@esbuild/netbsd-x64@0.25.12': | |
| 654 | + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} | |
| 655 | + engines: {node: '>=18'} | |
| 656 | + cpu: [x64] | |
| 657 | + os: [netbsd] | |
| 658 | + | |
| 659 | + '@esbuild/netbsd-x64@0.28.2': | |
| 660 | + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} | |
| 661 | + engines: {node: '>=18'} | |
| 662 | + cpu: [x64] | |
| 663 | + os: [netbsd] | |
| 664 | + | |
| 665 | + '@esbuild/openbsd-arm64@0.25.12': | |
| 666 | + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} | |
| 667 | + engines: {node: '>=18'} | |
| 668 | + cpu: [arm64] | |
| 669 | + os: [openbsd] | |
| 670 | + | |
| 671 | + '@esbuild/openbsd-arm64@0.28.2': | |
| 672 | + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} | |
| 673 | + engines: {node: '>=18'} | |
| 674 | + cpu: [arm64] | |
| 675 | + os: [openbsd] | |
| 676 | + | |
| 677 | + '@esbuild/openbsd-x64@0.18.20': | |
| 678 | + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} | |
| 679 | + engines: {node: '>=12'} | |
| 680 | + cpu: [x64] | |
| 681 | + os: [openbsd] | |
| 682 | + | |
| 683 | + '@esbuild/openbsd-x64@0.25.12': | |
| 684 | + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} | |
| 685 | + engines: {node: '>=18'} | |
| 686 | + cpu: [x64] | |
| 687 | + os: [openbsd] | |
| 688 | + | |
| 689 | + '@esbuild/openbsd-x64@0.28.2': | |
| 690 | + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} | |
| 691 | + engines: {node: '>=18'} | |
| 692 | + cpu: [x64] | |
| 693 | + os: [openbsd] | |
| 694 | + | |
| 695 | + '@esbuild/openharmony-arm64@0.25.12': | |
| 696 | + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} | |
| 697 | + engines: {node: '>=18'} | |
| 698 | + cpu: [arm64] | |
| 699 | + os: [openharmony] | |
| 700 | + | |
| 701 | + '@esbuild/openharmony-arm64@0.28.2': | |
| 702 | + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} | |
| 703 | + engines: {node: '>=18'} | |
| 704 | + cpu: [arm64] | |
| 705 | + os: [openharmony] | |
| 706 | + | |
| 707 | + '@esbuild/sunos-x64@0.18.20': | |
| 708 | + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} | |
| 709 | + engines: {node: '>=12'} | |
| 710 | + cpu: [x64] | |
| 711 | + os: [sunos] | |
| 712 | + | |
| 713 | + '@esbuild/sunos-x64@0.25.12': | |
| 714 | + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} | |
| 715 | + engines: {node: '>=18'} | |
| 716 | + cpu: [x64] | |
| 717 | + os: [sunos] | |
| 718 | + | |
| 719 | + '@esbuild/sunos-x64@0.28.2': | |
| 720 | + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} | |
| 721 | + engines: {node: '>=18'} | |
| 722 | + cpu: [x64] | |
| 723 | + os: [sunos] | |
| 724 | + | |
| 725 | + '@esbuild/win32-arm64@0.18.20': | |
| 726 | + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} | |
| 727 | + engines: {node: '>=12'} | |
| 728 | + cpu: [arm64] | |
| 729 | + os: [win32] | |
| 730 | + | |
| 731 | + '@esbuild/win32-arm64@0.25.12': | |
| 732 | + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} | |
| 733 | + engines: {node: '>=18'} | |
| 734 | + cpu: [arm64] | |
| 735 | + os: [win32] | |
| 736 | + | |
| 737 | + '@esbuild/win32-arm64@0.28.2': | |
| 738 | + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} | |
| 739 | + engines: {node: '>=18'} | |
| 740 | + cpu: [arm64] | |
| 741 | + os: [win32] | |
| 742 | + | |
| 743 | + '@esbuild/win32-ia32@0.18.20': | |
| 744 | + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} | |
| 745 | + engines: {node: '>=12'} | |
| 746 | + cpu: [ia32] | |
| 747 | + os: [win32] | |
| 748 | + | |
| 749 | + '@esbuild/win32-ia32@0.25.12': | |
| 750 | + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} | |
| 751 | + engines: {node: '>=18'} | |
| 752 | + cpu: [ia32] | |
| 753 | + os: [win32] | |
| 754 | + | |
| 755 | + '@esbuild/win32-ia32@0.28.2': | |
| 756 | + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} | |
| 757 | + engines: {node: '>=18'} | |
| 758 | + cpu: [ia32] | |
| 759 | + os: [win32] | |
| 760 | + | |
| 761 | + '@esbuild/win32-x64@0.18.20': | |
| 762 | + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} | |
| 763 | + engines: {node: '>=12'} | |
| 764 | + cpu: [x64] | |
| 765 | + os: [win32] | |
| 766 | + | |
| 767 | + '@esbuild/win32-x64@0.25.12': | |
| 768 | + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} | |
| 769 | + engines: {node: '>=18'} | |
| 770 | + cpu: [x64] | |
| 771 | + os: [win32] | |
| 772 | + | |
| 773 | + '@esbuild/win32-x64@0.28.2': | |
| 774 | + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} | |
| 775 | + engines: {node: '>=18'} | |
| 776 | + cpu: [x64] | |
| 777 | + os: [win32] | |
| 778 | + | |
| 779 | + '@eslint-community/eslint-utils@4.10.1': | |
| 780 | + resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} | |
| 781 | + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} | |
| 782 | + peerDependencies: | |
| 783 | + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 | |
| 784 | + | |
| 785 | + '@eslint-community/eslint-utils@4.9.1': | |
| 786 | + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} | |
| 787 | + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} | |
| 788 | + peerDependencies: | |
| 789 | + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 | |
| 790 | + | |
| 791 | + '@eslint-community/regexpp@4.12.2': | |
| 792 | + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} | |
| 793 | + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} | |
| 794 | + | |
| 795 | + '@eslint/config-array@0.21.2': | |
| 796 | + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} | |
| 797 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 798 | + | |
| 799 | + '@eslint/config-helpers@0.4.2': | |
| 800 | + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} | |
| 801 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 802 | + | |
| 803 | + '@eslint/core@0.17.0': | |
| 804 | + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} | |
| 805 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 806 | + | |
| 807 | + '@eslint/eslintrc@3.3.7': | |
| 808 | + resolution: {integrity: sha512-F42g89Qd5oAWtp0k0nnSrjziAKza7w8SVT4mStc18LZMaRb4J1HQAHLCalEtDCxrTuksx7NU9qsmeLwpOfPqWw==} | |
| 809 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 810 | + | |
| 811 | + '@eslint/js@9.39.5': | |
| 812 | + resolution: {integrity: sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==} | |
| 813 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 814 | + | |
| 815 | + '@eslint/object-schema@2.1.7': | |
| 816 | + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} | |
| 817 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 818 | + | |
| 819 | + '@eslint/plugin-kit@0.4.1': | |
| 820 | + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} | |
| 821 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 822 | + | |
| 823 | + '@humanfs/core@0.19.2': | |
| 824 | + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} | |
| 825 | + engines: {node: '>=18.18.0'} | |
| 826 | + | |
| 827 | + '@humanfs/node@0.16.8': | |
| 828 | + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} | |
| 829 | + engines: {node: '>=18.18.0'} | |
| 830 | + | |
| 831 | + '@humanfs/types@0.15.0': | |
| 832 | + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} | |
| 833 | + engines: {node: '>=18.18.0'} | |
| 834 | + | |
| 835 | + '@humanwhocodes/module-importer@1.0.1': | |
| 836 | + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} | |
| 837 | + engines: {node: '>=12.22'} | |
| 838 | + | |
| 839 | + '@humanwhocodes/retry@0.4.3': | |
| 840 | + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} | |
| 841 | + engines: {node: '>=18.18'} | |
| 842 | + | |
| 843 | + '@img/colour@1.1.0': | |
| 844 | + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} | |
| 845 | + engines: {node: '>=18'} | |
| 846 | + | |
| 847 | + '@img/sharp-darwin-arm64@0.35.4': | |
| 848 | + resolution: {integrity: sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA==} | |
| 849 | + engines: {node: '>=20.9.0'} | |
| 850 | + cpu: [arm64] | |
| 851 | + os: [darwin] | |
| 852 | + | |
| 853 | + '@img/sharp-darwin-x64@0.35.4': | |
| 854 | + resolution: {integrity: sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw==} | |
| 855 | + engines: {node: '>=20.9.0'} | |
| 856 | + cpu: [x64] | |
| 857 | + os: [darwin] | |
| 858 | + | |
| 859 | + '@img/sharp-freebsd-wasm32@0.35.4': | |
| 860 | + resolution: {integrity: sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA==} | |
| 861 | + engines: {node: '>=20.9.0'} | |
| 862 | + os: [freebsd] | |
| 863 | + | |
| 864 | + '@img/sharp-libvips-darwin-arm64@1.3.3': | |
| 865 | + resolution: {integrity: sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg==} | |
| 866 | + cpu: [arm64] | |
| 867 | + os: [darwin] | |
| 868 | + | |
| 869 | + '@img/sharp-libvips-darwin-x64@1.3.3': | |
| 870 | + resolution: {integrity: sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw==} | |
| 871 | + cpu: [x64] | |
| 872 | + os: [darwin] | |
| 873 | + | |
| 874 | + '@img/sharp-libvips-linux-arm64@1.3.3': | |
| 875 | + resolution: {integrity: sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A==} | |
| 876 | + cpu: [arm64] | |
| 877 | + os: [linux] | |
| 878 | + libc: [glibc] | |
| 879 | + | |
| 880 | + '@img/sharp-libvips-linux-arm@1.3.3': | |
| 881 | + resolution: {integrity: sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA==} | |
| 882 | + cpu: [arm] | |
| 883 | + os: [linux] | |
| 884 | + libc: [glibc] | |
| 885 | + | |
| 886 | + '@img/sharp-libvips-linux-ppc64@1.3.3': | |
| 887 | + resolution: {integrity: sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w==} | |
| 888 | + cpu: [ppc64] | |
| 889 | + os: [linux] | |
| 890 | + libc: [glibc] | |
| 891 | + | |
| 892 | + '@img/sharp-libvips-linux-riscv64@1.3.3': | |
| 893 | + resolution: {integrity: sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ==} | |
| 894 | + cpu: [riscv64] | |
| 895 | + os: [linux] | |
| 896 | + libc: [glibc] | |
| 897 | + | |
| 898 | + '@img/sharp-libvips-linux-s390x@1.3.3': | |
| 899 | + resolution: {integrity: sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q==} | |
| 900 | + cpu: [s390x] | |
| 901 | + os: [linux] | |
| 902 | + libc: [glibc] | |
| 903 | + | |
| 904 | + '@img/sharp-libvips-linux-x64@1.3.3': | |
| 905 | + resolution: {integrity: sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA==} | |
| 906 | + cpu: [x64] | |
| 907 | + os: [linux] | |
| 908 | + libc: [glibc] | |
| 909 | + | |
| 910 | + '@img/sharp-libvips-linuxmusl-arm64@1.3.3': | |
| 911 | + resolution: {integrity: sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw==} | |
| 912 | + cpu: [arm64] | |
| 913 | + os: [linux] | |
| 914 | + libc: [musl] | |
| 915 | + | |
| 916 | + '@img/sharp-libvips-linuxmusl-x64@1.3.3': | |
| 917 | + resolution: {integrity: sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw==} | |
| 918 | + cpu: [x64] | |
| 919 | + os: [linux] | |
| 920 | + libc: [musl] | |
| 921 | + | |
| 922 | + '@img/sharp-linux-arm64@0.35.4': | |
| 923 | + resolution: {integrity: sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ==} | |
| 924 | + engines: {node: '>=20.9.0'} | |
| 925 | + cpu: [arm64] | |
| 926 | + os: [linux] | |
| 927 | + libc: [glibc] | |
| 928 | + | |
| 929 | + '@img/sharp-linux-arm@0.35.4': | |
| 930 | + resolution: {integrity: sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A==} | |
| 931 | + engines: {node: '>=20.9.0'} | |
| 932 | + cpu: [arm] | |
| 933 | + os: [linux] | |
| 934 | + libc: [glibc] | |
| 935 | + | |
| 936 | + '@img/sharp-linux-ppc64@0.35.4': | |
| 937 | + resolution: {integrity: sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ==} | |
| 938 | + engines: {node: '>=20.9.0'} | |
| 939 | + cpu: [ppc64] | |
| 940 | + os: [linux] | |
| 941 | + libc: [glibc] | |
| 942 | + | |
| 943 | + '@img/sharp-linux-riscv64@0.35.4': | |
| 944 | + resolution: {integrity: sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA==} | |
| 945 | + engines: {node: '>=20.9.0'} | |
| 946 | + cpu: [riscv64] | |
| 947 | + os: [linux] | |
| 948 | + libc: [glibc] | |
| 949 | + | |
| 950 | + '@img/sharp-linux-s390x@0.35.4': | |
| 951 | + resolution: {integrity: sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ==} | |
| 952 | + engines: {node: '>=20.9.0'} | |
| 953 | + cpu: [s390x] | |
| 954 | + os: [linux] | |
| 955 | + libc: [glibc] | |
| 956 | + | |
| 957 | + '@img/sharp-linux-x64@0.35.4': | |
| 958 | + resolution: {integrity: sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA==} | |
| 959 | + engines: {node: '>=20.9.0'} | |
| 960 | + cpu: [x64] | |
| 961 | + os: [linux] | |
| 962 | + libc: [glibc] | |
| 963 | + | |
| 964 | + '@img/sharp-linuxmusl-arm64@0.35.4': | |
| 965 | + resolution: {integrity: sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA==} | |
| 966 | + engines: {node: '>=20.9.0'} | |
| 967 | + cpu: [arm64] | |
| 968 | + os: [linux] | |
| 969 | + libc: [musl] | |
| 970 | + | |
| 971 | + '@img/sharp-linuxmusl-x64@0.35.4': | |
| 972 | + resolution: {integrity: sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg==} | |
| 973 | + engines: {node: '>=20.9.0'} | |
| 974 | + cpu: [x64] | |
| 975 | + os: [linux] | |
| 976 | + libc: [musl] | |
| 977 | + | |
| 978 | + '@img/sharp-wasm32@0.35.4': | |
| 979 | + resolution: {integrity: sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==} | |
| 980 | + engines: {node: '>=20.9.0'} | |
| 981 | + | |
| 982 | + '@img/sharp-webcontainers-wasm32@0.35.4': | |
| 983 | + resolution: {integrity: sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA==} | |
| 984 | + engines: {node: '>=20.9.0'} | |
| 985 | + cpu: [wasm32] | |
| 986 | + | |
| 987 | + '@img/sharp-win32-arm64@0.35.4': | |
| 988 | + resolution: {integrity: sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw==} | |
| 989 | + engines: {node: '>=20.9.0'} | |
| 990 | + cpu: [arm64] | |
| 991 | + os: [win32] | |
| 992 | + | |
| 993 | + '@img/sharp-win32-ia32@0.35.4': | |
| 994 | + resolution: {integrity: sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw==} | |
| 995 | + engines: {node: ^20.9.0} | |
| 996 | + cpu: [ia32] | |
| 997 | + os: [win32] | |
| 998 | + | |
| 999 | + '@img/sharp-win32-x64@0.35.4': | |
| 1000 | + resolution: {integrity: sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg==} | |
| 1001 | + engines: {node: '>=20.9.0'} | |
| 1002 | + cpu: [x64] | |
| 1003 | + os: [win32] | |
| 1004 | + | |
| 1005 | + '@jridgewell/gen-mapping@0.3.13': | |
| 1006 | + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} | |
| 1007 | + | |
| 1008 | + '@jridgewell/remapping@2.3.5': | |
| 1009 | + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} | |
| 1010 | + | |
| 1011 | + '@jridgewell/resolve-uri@3.1.2': | |
| 1012 | + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} | |
| 1013 | + engines: {node: '>=6.0.0'} | |
| 1014 | + | |
| 1015 | + '@jridgewell/sourcemap-codec@1.6.0': | |
| 1016 | + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} | |
| 1017 | + | |
| 1018 | + '@jridgewell/trace-mapping@0.3.31': | |
| 1019 | + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} | |
| 1020 | + | |
| 1021 | + '@napi-rs/lzma-linux-x64-gnu@1.5.1': | |
| 1022 | + resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} | |
| 1023 | + engines: {node: ^22.20 || ^24.12 || >=25} | |
| 1024 | + cpu: [x64] | |
| 1025 | + os: [linux] | |
| 1026 | + libc: [glibc] | |
| 1027 | + | |
| 1028 | + '@napi-rs/wasm-runtime@1.2.3': | |
| 1029 | + resolution: {integrity: sha512-UMduMbqO5s5zF2NkNacMT/yK5Y5QiKvWr2+50bzIIxFDwVJ2h49b+oyjaCGPhJxd2/gC2x39EHv/gHVuu36x2Q==} | |
| 1030 | + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} | |
| 1031 | + peerDependencies: | |
| 1032 | + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 | |
| 1033 | + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 | |
| 1034 | + | |
| 1035 | + '@next/env@16.3.4': | |
| 1036 | + resolution: {integrity: sha512-cjWZnUUa6jZq2kFaNe/ZyJdZonOZ/QoN0Zka2nz/FLOrfx14pQuM9c5RaSVkWMqgdt4ksgPAMWPyHSs/CyV48Q==} | |
| 1037 | + | |
| 1038 | + '@next/eslint-plugin-next@16.3.4': | |
| 1039 | + resolution: {integrity: sha512-szW9y2Aumu4z88YXfTzcFsgUAg2k64uzbtcO5L9f1AKS4w/GUKJcbFllRflROVyNPgJtGOnvNxiyp3v6b+prIA==} | |
| 1040 | + | |
| 1041 | + '@next/swc-darwin-arm64@16.3.4': | |
| 1042 | + resolution: {integrity: sha512-iBr3I5LZNk5/bgl5//iTgD2tcym14MX0Xo7fD//u9dYAEgGzza1y9oywluPtf74YnOswVdH1908aK9xVz7zQTw==} | |
| 1043 | + engines: {node: '>= 10'} | |
| 1044 | + cpu: [arm64] | |
| 1045 | + os: [darwin] | |
| 1046 | + | |
| 1047 | + '@next/swc-darwin-x64@16.3.4': | |
| 1048 | + resolution: {integrity: sha512-2dpiSyl2Jw/NrBPaU2MAKGSa+2MR82pJIn4Sm5Rjr+gxAeuh0z158Su3Z2O8zn7UNNq+ej4bToed6RcRN/Lydg==} | |
| 1049 | + engines: {node: '>= 10'} | |
| 1050 | + cpu: [x64] | |
| 1051 | + os: [darwin] | |
| 1052 | + | |
| 1053 | + '@next/swc-linux-arm64-gnu@16.3.4': | |
| 1054 | + resolution: {integrity: sha512-+t+U8HZT+fApePCS5h89CSH3datz29MkzyfCn+6fpsZBG/oiEOhINcb9rtkv6sdpToLGFn2e6146NzaKCXkqrA==} | |
| 1055 | + engines: {node: '>= 10'} | |
| 1056 | + cpu: [arm64] | |
| 1057 | + os: [linux] | |
| 1058 | + libc: [glibc] | |
| 1059 | + | |
| 1060 | + '@next/swc-linux-arm64-musl@16.3.4': | |
| 1061 | + resolution: {integrity: sha512-mx03GNs1ocQA5JQ4FxDMmIsNkdrZh8cuezKCrId28e5/gIPU/l7Kcy2+vmCCzdjnnmXJy+iOAu+7K0QppO6Urg==} | |
| 1062 | + engines: {node: '>= 10'} | |
| 1063 | + cpu: [arm64] | |
| 1064 | + os: [linux] | |
| 1065 | + libc: [musl] | |
| 1066 | + | |
| 1067 | + '@next/swc-linux-x64-gnu@16.3.4': | |
| 1068 | + resolution: {integrity: sha512-YIhGY6fSMfha52bnVxnzc9zaVBzJg+cqQTOD8tXIBSx4fuv0pVMxQTE0PaS59YhnMOiYiG09IMwxJAf/CFm/Dw==} | |
| 1069 | + engines: {node: '>= 10'} | |
| 1070 | + cpu: [x64] | |
| 1071 | + os: [linux] | |
| 1072 | + libc: [glibc] | |
| 1073 | + | |
| 1074 | + '@next/swc-linux-x64-musl@16.3.4': | |
| 1075 | + resolution: {integrity: sha512-+eaaX6axpDb0yF1GCpiERe6njplvdC+nks/fKfcHu3XPGRrald8P3/X7yv7QLdjA51knnxwl9pxdIJsg+w1L+Q==} | |
| 1076 | + engines: {node: '>= 10'} | |
| 1077 | + cpu: [x64] | |
| 1078 | + os: [linux] | |
| 1079 | + libc: [musl] | |
| 1080 | + | |
| 1081 | + '@next/swc-win32-arm64-msvc@16.3.4': | |
| 1082 | + resolution: {integrity: sha512-0jcXW7Xs/uzICrmgV3MhDYDeRy++1CqnpDIerlPIqYO4bhzB4WNbX/aRnQclustsAyTkFKB0z6rbcjmNg5tR8A==} | |
| 1083 | + engines: {node: '>= 10'} | |
| 1084 | + cpu: [arm64] | |
| 1085 | + os: [win32] | |
| 1086 | + | |
| 1087 | + '@next/swc-win32-x64-msvc@16.3.4': | |
| 1088 | + resolution: {integrity: sha512-vvBzwu1pYQCp92maZCFCIw/XgOTMR5tur9GjakwIo2cmwRTMKajRZZDS9+e4KsUZWKu1E007WUeAFXRRjZeuzw==} | |
| 1089 | + engines: {node: '>= 10'} | |
| 1090 | + cpu: [x64] | |
| 1091 | + os: [win32] | |
| 1092 | + | |
| 1093 | + '@nodelib/fs.scandir@2.1.5': | |
| 1094 | + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} | |
| 1095 | + engines: {node: '>= 8'} | |
| 1096 | + | |
| 1097 | + '@nodelib/fs.stat@2.0.5': | |
| 1098 | + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} | |
| 1099 | + engines: {node: '>= 8'} | |
| 1100 | + | |
| 1101 | + '@nodelib/fs.walk@1.2.8': | |
| 1102 | + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} | |
| 1103 | + engines: {node: '>= 8'} | |
| 1104 | + | |
| 1105 | + '@nolyfill/is-core-module@1.0.39': | |
| 1106 | + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} | |
| 1107 | + engines: {node: '>=12.4.0'} | |
| 1108 | + | |
| 1109 | + '@pinojs/redact@0.4.0': | |
| 1110 | + resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} | |
| 1111 | + | |
| 1112 | + '@rollup/rollup-android-arm-eabi@4.63.1': | |
| 1113 | + resolution: {integrity: sha512-UZ8sUxPTiHWYX9QNdJedb1kDZSpS1t/VPWBWGSgqHNi9w3Cu6IXvu2mzbhiTiPvtrqgTQJ+zqiAq2iPIPilpaQ==} | |
| 1114 | + cpu: [arm] | |
| 1115 | + os: [android] | |
| 1116 | + | |
| 1117 | + '@rollup/rollup-android-arm64@4.63.1': | |
| 1118 | + resolution: {integrity: sha512-cQ4nFQABN5cDvDpbvJ7bMStCpnaVxynZrRMfUJYgxcIk9Sh54FIO1vtfkg0B69REjER77ioZ/ov+eAApx/KmLQ==} | |
| 1119 | + cpu: [arm64] | |
| 1120 | + os: [android] | |
| 1121 | + | |
| 1122 | + '@rollup/rollup-darwin-arm64@4.63.1': | |
| 1123 | + resolution: {integrity: sha512-FQNqd1lRy/0QhDk3xeRIkSBiCpXCiDnZO3YLVdcDKN1UBiKToNftCzcXYNLshmPDUMlu2TdeS8tGcsU6f3YF1Q==} | |
| 1124 | + cpu: [arm64] | |
| 1125 | + os: [darwin] | |
| 1126 | + | |
| 1127 | + '@rollup/rollup-darwin-x64@4.63.1': | |
| 1128 | + resolution: {integrity: sha512-pvD16V939D3CloK0+qikpGaxiPrDUXTe7Y5cWOMkMSy7m1cawa8EGy/kXYi/G/cKAC4HDAbSnzCIk1WmsoOKXg==} | |
| 1129 | + cpu: [x64] | |
| 1130 | + os: [darwin] | |
| 1131 | + | |
| 1132 | + '@rollup/rollup-freebsd-arm64@4.63.1': | |
| 1133 | + resolution: {integrity: sha512-pcFGeL2345VwdTnJhA6zLbew+YgWB0qBG2+dMtXjCicf6+rm6kO6cOoh5VnTe0ZMrMRgRyuHmCJxZWrIdzYuOw==} | |
| 1134 | + cpu: [arm64] | |
| 1135 | + os: [freebsd] | |
| 1136 | + | |
| 1137 | + '@rollup/rollup-freebsd-x64@4.63.1': | |
| 1138 | + resolution: {integrity: sha512-mRJlqSRulVzcKq/LKA6ICSIc3K/l4fzlVn/gePn2nXIHy8seRi5z/eeRE0d/XMBxcMldiXtQTSpRj0tkkC3g8Q==} | |
| 1139 | + cpu: [x64] | |
| 1140 | + os: [freebsd] | |
| 1141 | + | |
| 1142 | + '@rollup/rollup-linux-arm-gnueabihf@4.63.1': | |
| 1143 | + resolution: {integrity: sha512-YDUNvVM85TI3g/1OpnqKP1h4NeW/j64DfWMf+G3M809xNk1bJSnpFp4sh83NpmVE5DXnkh8ULor4LTVZKoYLHw==} | |
| 1144 | + cpu: [arm] | |
| 1145 | + os: [linux] | |
| 1146 | + libc: [glibc] | |
| 1147 | + | |
| 1148 | + '@rollup/rollup-linux-arm-musleabihf@4.63.1': | |
| 1149 | + resolution: {integrity: sha512-7Mcn71p9ZuQFAj+h+dhQXy/yeLePRS2yKRnmW1DijA9thKO5qap0GNOIQK4yQ6iP3SU0Mrb/yWo8h8vgRba8lw==} | |
| 1150 | + cpu: [arm] | |
| 1151 | + os: [linux] | |
| 1152 | + libc: [musl] | |
| 1153 | + | |
| 1154 | + '@rollup/rollup-linux-arm64-gnu@4.63.1': | |
| 1155 | + resolution: {integrity: sha512-4YiLQTX6U4CSl0L9cluep9A9W6UmTfqBDc2/CH6wlu54pl4E7Jn3cOD8oxzvBDEGk/JMKgJ47C8g+radF7mwvg==} | |
| 1156 | + cpu: [arm64] | |
| 1157 | + os: [linux] | |
| 1158 | + libc: [glibc] | |
| 1159 | + | |
| 1160 | + '@rollup/rollup-linux-arm64-musl@4.63.1': | |
| 1161 | + resolution: {integrity: sha512-2ra8F7w8OquwZN9z2/fKFnli69wa8PLwaVzRMIPGb13ByMJwC28Fbp8YcVGoUhlYMTt7j5j9bNgpysrN2UM+vw==} | |
| 1162 | + cpu: [arm64] | |
| 1163 | + os: [linux] | |
| 1164 | + libc: [musl] | |
| 1165 | + | |
| 1166 | + '@rollup/rollup-linux-loong64-gnu@4.63.1': | |
| 1167 | + resolution: {integrity: sha512-Sy20ncyhjmBP0Ml+UvQbimjlk6VFgjW5uNP+qqwHB00mTE8Bl2C1TuHTlRwK2YoXeZbee5lP2XevBWVkAQAtSQ==} | |
| 1168 | + cpu: [loong64] | |
| 1169 | + os: [linux] | |
| 1170 | + libc: [glibc] | |
| 1171 | + | |
| 1172 | + '@rollup/rollup-linux-loong64-musl@4.63.1': | |
| 1173 | + resolution: {integrity: sha512-noITLp8oNjYliPnGWmLyelIHwULGqbHloQHGw1rtxbWhTuWooRpnZarZQJ1y9EUC4szuCusCc+HEpUtxpIwYvA==} | |
| 1174 | + cpu: [loong64] | |
| 1175 | + os: [linux] | |
| 1176 | + libc: [musl] | |
| 1177 | + | |
| 1178 | + '@rollup/rollup-linux-ppc64-gnu@4.63.1': | |
| 1179 | + resolution: {integrity: sha512-hlxxXd+F1mWiAcaFR7Sv9ZQT6m6UfI8+Vy/kFJzztq2pDMU/0wZ9sish0iszNZvsQDo8Gc0i5yuFEOz5dDf6fA==} | |
| 1180 | + cpu: [ppc64] | |
| 1181 | + os: [linux] | |
| 1182 | + libc: [glibc] | |
| 1183 | + | |
| 1184 | + '@rollup/rollup-linux-ppc64-musl@4.63.1': | |
| 1185 | + resolution: {integrity: sha512-EF7OpqQTQ/BvGqLzUi4rEHuagCV9MugAUXSHemwPW5vxZ75RR+jxO/2j95Ph2dalMpFHSVECjRoioHZgA9zOYA==} | |
| 1186 | + cpu: [ppc64] | |
| 1187 | + os: [linux] | |
| 1188 | + libc: [musl] | |
| 1189 | + | |
| 1190 | + '@rollup/rollup-linux-riscv64-gnu@4.63.1': | |
| 1191 | + resolution: {integrity: sha512-wQO3JesW9PRkwlabQ27y7sPfVOOTLRG73I4F2UYHG5PXun3J9U3y+b7ezVKSYbsvSKGQ1k1cq8Qlun4C9kLt3w==} | |
| 1192 | + cpu: [riscv64] | |
| 1193 | + os: [linux] | |
| 1194 | + libc: [glibc] | |
| 1195 | + | |
| 1196 | + '@rollup/rollup-linux-riscv64-musl@4.63.1': | |
| 1197 | + resolution: {integrity: sha512-ouAGwhO6wHRXdnOVCOsB0tRFkA7nhNB2Nwax6oECXN0YiN8EYUTBAOudADOB1PI+yDL61TeNx/u7MVCzksNbkQ==} | |
| 1198 | + cpu: [riscv64] | |
| 1199 | + os: [linux] | |
| 1200 | + libc: [musl] | |
| 1201 | + | |
| 1202 | + '@rollup/rollup-linux-s390x-gnu@4.63.1': | |
| 1203 | + resolution: {integrity: sha512-q2R38Sn+1J8RxhfJ+T54wSWmyKXWec+9jgDfqO2AtArEqHO5R2aeayp5H5OYLr5UYDVGsVaZPEFUooMhYCdz5A==} | |
| 1204 | + cpu: [s390x] | |
| 1205 | + os: [linux] | |
| 1206 | + libc: [glibc] | |
| 1207 | + | |
| 1208 | + '@rollup/rollup-linux-x64-gnu@4.63.1': | |
| 1209 | + resolution: {integrity: sha512-gfI5T24WLLuFfSKw7Go/zDXjAAV0fny0swTaDv+WjK7vqcw4cRhFfdsyKL1n+ukI+ooBxn3bVQnyrn06WpI50w==} | |
| 1210 | + cpu: [x64] | |
| 1211 | + os: [linux] | |
| 1212 | + libc: [glibc] | |
| 1213 | + | |
| 1214 | + '@rollup/rollup-linux-x64-musl@4.63.1': | |
| 1215 | + resolution: {integrity: sha512-4h6XqthmB4Hspji84wvgk+ElodTsGj+dbZqHJHHtKxj4mYq0ANSEEPX9ys3moJueqsRjwpaJYH7874Itwnj2ow==} | |
| 1216 | + cpu: [x64] | |
| 1217 | + os: [linux] | |
| 1218 | + libc: [musl] | |
| 1219 | + | |
| 1220 | + '@rollup/rollup-openbsd-x64@4.63.1': | |
| 1221 | + resolution: {integrity: sha512-dlfCOa87o1VAYegLQ9EKilx2JCeRofiyPGhTCmqnuXZ6bMPiycO1rq1+sKoulAp7pGLIsTIw+1x5R+zgh5LhhA==} | |
| 1222 | + cpu: [x64] | |
| 1223 | + os: [openbsd] | |
| 1224 | + | |
| 1225 | + '@rollup/rollup-openharmony-arm64@4.63.1': | |
| 1226 | + resolution: {integrity: sha512-cjkLbOlfcm3QGhMM1J5zaZjsw1GggbN6rw9UTSSRrPrR1KkcXnN7Uq9rPw34xImQ9VOY9GN+6u2Zj80B9ptkcw==} | |
| 1227 | + cpu: [arm64] | |
| 1228 | + os: [openharmony] | |
| 1229 | + | |
| 1230 | + '@rollup/rollup-win32-arm64-msvc@4.63.1': | |
| 1231 | + resolution: {integrity: sha512-Li1KdUnWGE4N3e1F/B4RTB1ms+nG4WBgjByO46pkeBVX/2UBsY53xf5vK9WygVmnH3RwncIST7lkSdLSY6P9lg==} | |
| 1232 | + cpu: [arm64] | |
| 1233 | + os: [win32] | |
| 1234 | + | |
| 1235 | + '@rollup/rollup-win32-ia32-msvc@4.63.1': | |
| 1236 | + resolution: {integrity: sha512-t4ZYOSoLTgwhuFMrmTMLx/+i1DQVK7HYqMc6kY46EApwi8X0nIVphzdNoThU3xt6n+N5urG1/gxBdCaKDLavfg==} | |
| 1237 | + cpu: [ia32] | |
| 1238 | + os: [win32] | |
| 1239 | + | |
| 1240 | + '@rollup/rollup-win32-x64-gnu@4.63.1': | |
| 1241 | + resolution: {integrity: sha512-RgroPfMmKlD1RzSDxvwgcPiy2HNQKoYV7OmwIXDsk73uKW5t6B/V8KIy27SMv/FNXFo/oSBtWc9J0X7t91ezZg==} | |
| 1242 | + cpu: [x64] | |
| 1243 | + os: [win32] | |
| 1244 | + | |
| 1245 | + '@rollup/rollup-win32-x64-msvc@4.63.1': | |
| 1246 | + resolution: {integrity: sha512-at8QVep6S3h5Y6gSbdGU06bRY5WJkf6WUduM9YtvYMbYhB1MOFfUgc6kehitQXzOtMSaT70q7f9ydPhpqu821w==} | |
| 1247 | + cpu: [x64] | |
| 1248 | + os: [win32] | |
| 1249 | + | |
| 1250 | + '@rtsao/scc@1.1.0': | |
| 1251 | + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} | |
| 1252 | + | |
| 1253 | + '@swc/helpers@0.5.23': | |
| 1254 | + resolution: {integrity: sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==} | |
| 1255 | + | |
| 1256 | + '@tailwindcss/node@4.3.3': | |
| 1257 | + resolution: {integrity: sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==} | |
| 1258 | + | |
| 1259 | + '@tailwindcss/oxide-android-arm64@4.3.3': | |
| 1260 | + resolution: {integrity: sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==} | |
| 1261 | + engines: {node: '>= 20'} | |
| 1262 | + cpu: [arm64] | |
| 1263 | + os: [android] | |
| 1264 | + | |
| 1265 | + '@tailwindcss/oxide-darwin-arm64@4.3.3': | |
| 1266 | + resolution: {integrity: sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==} | |
| 1267 | + engines: {node: '>= 20'} | |
| 1268 | + cpu: [arm64] | |
| 1269 | + os: [darwin] | |
| 1270 | + | |
| 1271 | + '@tailwindcss/oxide-darwin-x64@4.3.3': | |
| 1272 | + resolution: {integrity: sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==} | |
| 1273 | + engines: {node: '>= 20'} | |
| 1274 | + cpu: [x64] | |
| 1275 | + os: [darwin] | |
| 1276 | + | |
| 1277 | + '@tailwindcss/oxide-freebsd-x64@4.3.3': | |
| 1278 | + resolution: {integrity: sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==} | |
| 1279 | + engines: {node: '>= 20'} | |
| 1280 | + cpu: [x64] | |
| 1281 | + os: [freebsd] | |
| 1282 | + | |
| 1283 | + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': | |
| 1284 | + resolution: {integrity: sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==} | |
| 1285 | + engines: {node: '>= 20'} | |
| 1286 | + cpu: [arm] | |
| 1287 | + os: [linux] | |
| 1288 | + | |
| 1289 | + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': | |
| 1290 | + resolution: {integrity: sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==} | |
| 1291 | + engines: {node: '>= 20'} | |
| 1292 | + cpu: [arm64] | |
| 1293 | + os: [linux] | |
| 1294 | + libc: [glibc] | |
| 1295 | + | |
| 1296 | + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': | |
| 1297 | + resolution: {integrity: sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==} | |
| 1298 | + engines: {node: '>= 20'} | |
| 1299 | + cpu: [arm64] | |
| 1300 | + os: [linux] | |
| 1301 | + libc: [musl] | |
| 1302 | + | |
| 1303 | + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': | |
| 1304 | + resolution: {integrity: sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==} | |
| 1305 | + engines: {node: '>= 20'} | |
| 1306 | + cpu: [x64] | |
| 1307 | + os: [linux] | |
| 1308 | + libc: [glibc] | |
| 1309 | + | |
| 1310 | + '@tailwindcss/oxide-linux-x64-musl@4.3.3': | |
| 1311 | + resolution: {integrity: sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==} | |
| 1312 | + engines: {node: '>= 20'} | |
| 1313 | + cpu: [x64] | |
| 1314 | + os: [linux] | |
| 1315 | + libc: [musl] | |
| 1316 | + | |
| 1317 | + '@tailwindcss/oxide-wasm32-wasi@4.3.3': | |
| 1318 | + resolution: {integrity: sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==} | |
| 1319 | + engines: {node: '>=14.0.0'} | |
| 1320 | + cpu: [wasm32] | |
| 1321 | + bundledDependencies: | |
| 1322 | + - '@napi-rs/wasm-runtime' | |
| 1323 | + - '@emnapi/core' | |
| 1324 | + - '@emnapi/runtime' | |
| 1325 | + - '@tybys/wasm-util' | |
| 1326 | + - '@emnapi/wasi-threads' | |
| 1327 | + - tslib | |
| 1328 | + | |
| 1329 | + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': | |
| 1330 | + resolution: {integrity: sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==} | |
| 1331 | + engines: {node: '>= 20'} | |
| 1332 | + cpu: [arm64] | |
| 1333 | + os: [win32] | |
| 1334 | + | |
| 1335 | + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': | |
| 1336 | + resolution: {integrity: sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==} | |
| 1337 | + engines: {node: '>= 20'} | |
| 1338 | + cpu: [x64] | |
| 1339 | + os: [win32] | |
| 1340 | + | |
| 1341 | + '@tailwindcss/oxide@4.3.3': | |
| 1342 | + resolution: {integrity: sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==} | |
| 1343 | + engines: {node: '>= 20'} | |
| 1344 | + | |
| 1345 | + '@tailwindcss/postcss@4.3.3': | |
| 1346 | + resolution: {integrity: sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg==} | |
| 1347 | + | |
| 1348 | + '@tanstack/query-core@5.102.8': | |
| 1349 | + resolution: {integrity: sha512-ZNjkJ33CqvPNec/6lZBnHqLc3EVGPZ9ySLhYahU9TcuRFdmwXewuj0c4hwSWcGHqEUwcSrKeZ+oGcvPBqXcQcg==} | |
| 1350 | + | |
| 1351 | + '@tanstack/react-query@5.102.8': | |
| 1352 | + resolution: {integrity: sha512-TYBea4OuXWD7MhaSHq069TWbFe7rcwWN6kzT7JF0OKi1K6c1gTv2IzD6A6ExJsCMozdkqBWeuIUZmu4KQg0O5A==} | |
| 1353 | + peerDependencies: | |
| 1354 | + react: ^18 || ^19 | |
| 1355 | + | |
| 1356 | + '@tybys/wasm-util@0.10.3': | |
| 1357 | + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} | |
| 1358 | + | |
| 1359 | + '@types/chai@5.2.3': | |
| 1360 | + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} | |
| 1361 | + | |
| 1362 | + '@types/deep-eql@4.0.2': | |
| 1363 | + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} | |
| 1364 | + | |
| 1365 | + '@types/estree@1.0.9': | |
| 1366 | + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} | |
| 1367 | + | |
| 1368 | + '@types/json-schema@7.0.15': | |
| 1369 | + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} | |
| 1370 | + | |
| 1371 | + '@types/json5@0.0.29': | |
| 1372 | + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} | |
| 1373 | + | |
| 1374 | + '@types/node@24.13.3': | |
| 1375 | + resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==} | |
| 1376 | + | |
| 1377 | + '@types/react-dom@19.2.7': | |
| 1378 | + resolution: {integrity: sha512-I8bPpDLcHBv1qiIiXDCy71Rt8eQDKJP0sMSWJphDdAcdqiJ1sGpZamavoEIRZmYzjia9LuEb2HlYdDpmoENpvQ==} | |
| 1379 | + peerDependencies: | |
| 1380 | + '@types/react': ^19.2.0 | |
| 1381 | + | |
| 1382 | + '@types/react@19.2.18': | |
| 1383 | + resolution: {integrity: sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==} | |
| 1384 | + | |
| 1385 | + '@typescript-eslint/eslint-plugin@8.69.0': | |
| 1386 | + resolution: {integrity: sha512-t5jQTKPIgVW1PE6dR6H6Qz5gm8zjMlX5/2gRaOGd9eO6V7J+tQc6iWKukEe7dY8u9HyYasQ0yfF0/FSSTEO2gA==} | |
| 1387 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 1388 | + peerDependencies: | |
| 1389 | + '@typescript-eslint/parser': ^8.69.0 | |
| 1390 | + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 | |
| 1391 | + typescript: '>=4.8.4 <6.1.0' | |
| 1392 | + | |
| 1393 | + '@typescript-eslint/parser@8.69.0': | |
| 1394 | + resolution: {integrity: sha512-l4b0DhWioGg6Gt2ebGlvfkFMOjRsauxtsnDRwUSRX1qHq3HdTfQHV8wW9zEXeciai6HfeaKOedQn2Zoofx3WBw==} | |
| 1395 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 1396 | + peerDependencies: | |
| 1397 | + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 | |
| 1398 | + typescript: '>=4.8.4 <6.1.0' | |
| 1399 | + | |
| 1400 | + '@typescript-eslint/project-service@8.69.0': | |
| 1401 | + resolution: {integrity: sha512-yi4obFrHMmnsesWehHbkg9zMA7Jt8cXT+mKM08G999pH1yT6nqgsHx7MYm0uY1wAj8CqiBXYRJ7WAT0QdQHQXg==} | |
| 1402 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 1403 | + peerDependencies: | |
| 1404 | + typescript: '>=4.8.4 <6.1.0' | |
| 1405 | + | |
| 1406 | + '@typescript-eslint/scope-manager@8.69.0': | |
| 1407 | + resolution: {integrity: sha512-ewfspqWvSxKSOaplqAUNbaSFO0eB6w1EtQ+esfYFRm3614Ty4uNtExkcbgd6nWsXphbqKyf9ZYdbZdv2xEoWEQ==} | |
| 1408 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 1409 | + | |
| 1410 | + '@typescript-eslint/tsconfig-utils@8.69.0': | |
| 1411 | + resolution: {integrity: sha512-xNqK7YTDZsLniQMV/4rpFR8Z5JlqeRvVjuG1YgF/mdPVH84HSD19L8CczMA0qg2RfwEV231GHH3VnToJDo4MfQ==} | |
| 1412 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 1413 | + peerDependencies: | |
| 1414 | + typescript: '>=4.8.4 <6.1.0' | |
| 1415 | + | |
| 1416 | + '@typescript-eslint/type-utils@8.69.0': | |
| 1417 | + resolution: {integrity: sha512-ZfoJAVg3JZndQEpEl9petVlxau3lRuElc4HRMuAlLCf8to04/iHz692RUSNmXKDjEuJmIL+KZ2/BsOcBc16dsA==} | |
| 1418 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 1419 | + peerDependencies: | |
| 1420 | + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 | |
| 1421 | + typescript: '>=4.8.4 <6.1.0' | |
| 1422 | + | |
| 1423 | + '@typescript-eslint/types@8.69.0': | |
| 1424 | + resolution: {integrity: sha512-K3VrubUPhlo9VDBS6QdI8YB5j7ClpqLRdefcz6PFrhnwicehBweqQ9Evhl4l+FYz0HdDmMqIiSX0aldGRYtDCA==} | |
| 1425 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 1426 | + | |
| 1427 | + '@typescript-eslint/typescript-estree@8.69.0': | |
| 1428 | + resolution: {integrity: sha512-AdFkgqck3Vudb/kWnxlyafU/4aBhHrbQ9locP2N4psXTy5mOBg0SHJumnLvx7r6g1gV4DKvUFwV2nJZBoqOD8w==} | |
| 1429 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 1430 | + peerDependencies: | |
| 1431 | + typescript: '>=4.8.4 <6.1.0' | |
| 1432 | + | |
| 1433 | + '@typescript-eslint/utils@8.69.0': | |
| 1434 | + resolution: {integrity: sha512-tUbx60BBqQa31kXF5MCsOOLL5E/WzUuxIn7YpAvq+eaUlqvk8/NXnXMBNAdLCr0icjkzem7iUA5QqWHe/hJ1aw==} | |
| 1435 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 1436 | + peerDependencies: | |
| 1437 | + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 | |
| 1438 | + typescript: '>=4.8.4 <6.1.0' | |
| 1439 | + | |
| 1440 | + '@typescript-eslint/visitor-keys@8.69.0': | |
| 1441 | + resolution: {integrity: sha512-+rmdgPA+EXkNgKYvHvFfhrs35utXbwaC5PGpDquSXcoXQDKUA5UjV0LmTucG/4JXkM31BTu4TilHtrN8IVBe8w==} | |
| 1442 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 1443 | + | |
| 1444 | + '@unrs/resolver-binding-android-arm-eabi@1.12.2': | |
| 1445 | + resolution: {integrity: sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==} | |
| 1446 | + cpu: [arm] | |
| 1447 | + os: [android] | |
| 1448 | + | |
| 1449 | + '@unrs/resolver-binding-android-arm64@1.12.2': | |
| 1450 | + resolution: {integrity: sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==} | |
| 1451 | + cpu: [arm64] | |
| 1452 | + os: [android] | |
| 1453 | + | |
| 1454 | + '@unrs/resolver-binding-darwin-arm64@1.12.2': | |
| 1455 | + resolution: {integrity: sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==} | |
| 1456 | + cpu: [arm64] | |
| 1457 | + os: [darwin] | |
| 1458 | + | |
| 1459 | + '@unrs/resolver-binding-darwin-x64@1.12.2': | |
| 1460 | + resolution: {integrity: sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==} | |
| 1461 | + cpu: [x64] | |
| 1462 | + os: [darwin] | |
| 1463 | + | |
| 1464 | + '@unrs/resolver-binding-freebsd-x64@1.12.2': | |
| 1465 | + resolution: {integrity: sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==} | |
| 1466 | + cpu: [x64] | |
| 1467 | + os: [freebsd] | |
| 1468 | + | |
| 1469 | + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': | |
| 1470 | + resolution: {integrity: sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==} | |
| 1471 | + cpu: [arm] | |
| 1472 | + os: [linux] | |
| 1473 | + | |
| 1474 | + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': | |
| 1475 | + resolution: {integrity: sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==} | |
| 1476 | + cpu: [arm] | |
| 1477 | + os: [linux] | |
| 1478 | + | |
| 1479 | + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': | |
| 1480 | + resolution: {integrity: sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==} | |
| 1481 | + cpu: [arm64] | |
| 1482 | + os: [linux] | |
| 1483 | + libc: [glibc] | |
| 1484 | + | |
| 1485 | + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': | |
| 1486 | + resolution: {integrity: sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==} | |
| 1487 | + cpu: [arm64] | |
| 1488 | + os: [linux] | |
| 1489 | + libc: [musl] | |
| 1490 | + | |
| 1491 | + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': | |
| 1492 | + resolution: {integrity: sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==} | |
| 1493 | + cpu: [loong64] | |
| 1494 | + os: [linux] | |
| 1495 | + libc: [glibc] | |
| 1496 | + | |
| 1497 | + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': | |
| 1498 | + resolution: {integrity: sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==} | |
| 1499 | + cpu: [loong64] | |
| 1500 | + os: [linux] | |
| 1501 | + libc: [musl] | |
| 1502 | + | |
| 1503 | + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': | |
| 1504 | + resolution: {integrity: sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==} | |
| 1505 | + cpu: [ppc64] | |
| 1506 | + os: [linux] | |
| 1507 | + libc: [glibc] | |
| 1508 | + | |
| 1509 | + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': | |
| 1510 | + resolution: {integrity: sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==} | |
| 1511 | + cpu: [riscv64] | |
| 1512 | + os: [linux] | |
| 1513 | + libc: [glibc] | |
| 1514 | + | |
| 1515 | + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': | |
| 1516 | + resolution: {integrity: sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==} | |
| 1517 | + cpu: [riscv64] | |
| 1518 | + os: [linux] | |
| 1519 | + libc: [musl] | |
| 1520 | + | |
| 1521 | + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': | |
| 1522 | + resolution: {integrity: sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==} | |
| 1523 | + cpu: [s390x] | |
| 1524 | + os: [linux] | |
| 1525 | + libc: [glibc] | |
| 1526 | + | |
| 1527 | + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': | |
| 1528 | + resolution: {integrity: sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==} | |
| 1529 | + cpu: [x64] | |
| 1530 | + os: [linux] | |
| 1531 | + libc: [glibc] | |
| 1532 | + | |
| 1533 | + '@unrs/resolver-binding-linux-x64-musl@1.12.2': | |
| 1534 | + resolution: {integrity: sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==} | |
| 1535 | + cpu: [x64] | |
| 1536 | + os: [linux] | |
| 1537 | + libc: [musl] | |
| 1538 | + | |
| 1539 | + '@unrs/resolver-binding-openharmony-arm64@1.12.2': | |
| 1540 | + resolution: {integrity: sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==} | |
| 1541 | + cpu: [arm64] | |
| 1542 | + os: [openharmony] | |
| 1543 | + | |
| 1544 | + '@unrs/resolver-binding-wasm32-wasi@1.12.2': | |
| 1545 | + resolution: {integrity: sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==} | |
| 1546 | + engines: {node: '>=14.0.0'} | |
| 1547 | + cpu: [wasm32] | |
| 1548 | + | |
| 1549 | + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': | |
| 1550 | + resolution: {integrity: sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==} | |
| 1551 | + cpu: [arm64] | |
| 1552 | + os: [win32] | |
| 1553 | + | |
| 1554 | + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': | |
| 1555 | + resolution: {integrity: sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==} | |
| 1556 | + cpu: [ia32] | |
| 1557 | + os: [win32] | |
| 1558 | + | |
| 1559 | + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': | |
| 1560 | + resolution: {integrity: sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==} | |
| 1561 | + cpu: [x64] | |
| 1562 | + os: [win32] | |
| 1563 | + | |
| 1564 | + '@vitest/expect@3.2.7': | |
| 1565 | + resolution: {integrity: sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==} | |
| 1566 | + | |
| 1567 | + '@vitest/mocker@3.2.7': | |
| 1568 | + resolution: {integrity: sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA==} | |
| 1569 | + peerDependencies: | |
| 1570 | + msw: ^2.4.9 | |
| 1571 | + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 | |
| 1572 | + peerDependenciesMeta: | |
| 1573 | + msw: | |
| 1574 | + optional: true | |
| 1575 | + vite: | |
| 1576 | + optional: true | |
| 1577 | + | |
| 1578 | + '@vitest/pretty-format@3.2.7': | |
| 1579 | + resolution: {integrity: sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==} | |
| 1580 | + | |
| 1581 | + '@vitest/runner@3.2.7': | |
| 1582 | + resolution: {integrity: sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA==} | |
| 1583 | + | |
| 1584 | + '@vitest/snapshot@3.2.7': | |
| 1585 | + resolution: {integrity: sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g==} | |
| 1586 | + | |
| 1587 | + '@vitest/spy@3.2.7': | |
| 1588 | + resolution: {integrity: sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ==} | |
| 1589 | + | |
| 1590 | + '@vitest/utils@3.2.7': | |
| 1591 | + resolution: {integrity: sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw==} | |
| 1592 | + | |
| 1593 | + acorn-jsx@5.3.2: | |
| 1594 | + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} | |
| 1595 | + peerDependencies: | |
| 1596 | + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 | |
| 1597 | + | |
| 1598 | + acorn@8.18.0: | |
| 1599 | + resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==} | |
| 1600 | + engines: {node: '>=0.4.0'} | |
| 1601 | + hasBin: true | |
| 1602 | + | |
| 1603 | + ajv@6.15.0: | |
| 1604 | + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} | |
| 1605 | + | |
| 1606 | + ansi-styles@4.3.0: | |
| 1607 | + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} | |
| 1608 | + engines: {node: '>=8'} | |
| 1609 | + | |
| 1610 | + argparse@2.0.1: | |
| 1611 | + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} | |
| 1612 | + | |
| 1613 | + aria-query@5.3.2: | |
| 1614 | + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} | |
| 1615 | + engines: {node: '>= 0.4'} | |
| 1616 | + | |
| 1617 | + array-buffer-byte-length@1.0.2: | |
| 1618 | + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} | |
| 1619 | + engines: {node: '>= 0.4'} | |
| 1620 | + | |
| 1621 | + array-includes@3.1.9: | |
| 1622 | + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} | |
| 1623 | + engines: {node: '>= 0.4'} | |
| 1624 | + | |
| 1625 | + array.prototype.findlast@1.2.5: | |
| 1626 | + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} | |
| 1627 | + engines: {node: '>= 0.4'} | |
| 1628 | + | |
| 1629 | + array.prototype.findlastindex@1.2.6: | |
| 1630 | + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} | |
| 1631 | + engines: {node: '>= 0.4'} | |
| 1632 | + | |
| 1633 | + array.prototype.flat@1.3.3: | |
| 1634 | + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} | |
| 1635 | + engines: {node: '>= 0.4'} | |
| 1636 | + | |
| 1637 | + array.prototype.flatmap@1.3.3: | |
| 1638 | + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} | |
| 1639 | + engines: {node: '>= 0.4'} | |
| 1640 | + | |
| 1641 | + array.prototype.tosorted@1.1.4: | |
| 1642 | + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} | |
| 1643 | + engines: {node: '>= 0.4'} | |
| 1644 | + | |
| 1645 | + arraybuffer.prototype.slice@1.0.4: | |
| 1646 | + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} | |
| 1647 | + engines: {node: '>= 0.4'} | |
| 1648 | + | |
| 1649 | + assertion-error@2.0.1: | |
| 1650 | + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} | |
| 1651 | + engines: {node: '>=12'} | |
| 1652 | + | |
| 1653 | + ast-types-flow@0.0.8: | |
| 1654 | + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} | |
| 1655 | + | |
| 1656 | + async-function@1.0.0: | |
| 1657 | + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} | |
| 1658 | + engines: {node: '>= 0.4'} | |
| 1659 | + | |
| 1660 | + atomic-sleep@1.0.0: | |
| 1661 | + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} | |
| 1662 | + engines: {node: '>=8.0.0'} | |
| 1663 | + | |
| 1664 | + available-typed-arrays@1.0.7: | |
| 1665 | + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} | |
| 1666 | + engines: {node: '>= 0.4'} | |
| 1667 | + | |
| 1668 | + axe-core@4.13.0: | |
| 1669 | + resolution: {integrity: sha512-UzGt8zg7Ny8djbYMhxl2zuEevVa7r2gJjYY5Lwr1xM7+XU2nd6CkIWFTVcCIbAP63vSz71NaVyyuSk9lHKcy0A==} | |
| 1670 | + engines: {node: '>=4'} | |
| 1671 | + | |
| 1672 | + axobject-query@4.1.0: | |
| 1673 | + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} | |
| 1674 | + engines: {node: '>= 0.4'} | |
| 1675 | + | |
| 1676 | + balanced-match@1.0.2: | |
| 1677 | + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} | |
| 1678 | + | |
| 1679 | + balanced-match@4.0.4: | |
| 1680 | + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} | |
| 1681 | + engines: {node: 18 || 20 || >=22} | |
| 1682 | + | |
| 1683 | + baseline-browser-mapping@2.11.21: | |
| 1684 | + resolution: {integrity: sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ==} | |
| 1685 | + engines: {node: '>=6.0.0'} | |
| 1686 | + hasBin: true | |
| 1687 | + | |
| 1688 | + boolbase@1.0.0: | |
| 1689 | + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} | |
| 1690 | + | |
| 1691 | + brace-expansion@1.1.18: | |
| 1692 | + resolution: {integrity: sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==} | |
| 1693 | + | |
| 1694 | + brace-expansion@5.0.9: | |
| 1695 | + resolution: {integrity: sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==} | |
| 1696 | + engines: {node: 20 || >=22} | |
| 1697 | + | |
| 1698 | + braces@3.0.3: | |
| 1699 | + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} | |
| 1700 | + engines: {node: '>=8'} | |
| 1701 | + | |
| 1702 | + browserslist@4.28.9: | |
| 1703 | + resolution: {integrity: sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg==} | |
| 1704 | + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} | |
| 1705 | + hasBin: true | |
| 1706 | + | |
| 1707 | + buffer-from@1.1.2: | |
| 1708 | + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} | |
| 1709 | + | |
| 1710 | + cac@6.7.14: | |
| 1711 | + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} | |
| 1712 | + engines: {node: '>=8'} | |
| 1713 | + | |
| 1714 | + call-bind-apply-helpers@1.0.2: | |
| 1715 | + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} | |
| 1716 | + engines: {node: '>= 0.4'} | |
| 1717 | + | |
| 1718 | + call-bind@1.0.9: | |
| 1719 | + resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} | |
| 1720 | + engines: {node: '>= 0.4'} | |
| 1721 | + | |
| 1722 | + call-bound@1.0.4: | |
| 1723 | + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} | |
| 1724 | + engines: {node: '>= 0.4'} | |
| 1725 | + | |
| 1726 | + callsites@3.1.0: | |
| 1727 | + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} | |
| 1728 | + engines: {node: '>=6'} | |
| 1729 | + | |
| 1730 | + caniuse-lite@1.0.30001810: | |
| 1731 | + resolution: {integrity: sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==} | |
| 1732 | + | |
| 1733 | + chai@5.3.3: | |
| 1734 | + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} | |
| 1735 | + engines: {node: '>=18'} | |
| 1736 | + | |
| 1737 | + chalk@4.1.2: | |
| 1738 | + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} | |
| 1739 | + engines: {node: '>=10'} | |
| 1740 | + | |
| 1741 | + check-error@2.1.3: | |
| 1742 | + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} | |
| 1743 | + engines: {node: '>= 16'} | |
| 1744 | + | |
| 1745 | + cheerio-select@2.1.0: | |
| 1746 | + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} | |
| 1747 | + | |
| 1748 | + cheerio@1.2.0: | |
| 1749 | + resolution: {integrity: sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==} | |
| 1750 | + engines: {node: '>=20.18.1'} | |
| 1751 | + | |
| 1752 | + client-only@0.0.1: | |
| 1753 | + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} | |
| 1754 | + | |
| 1755 | + color-convert@2.0.1: | |
| 1756 | + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} | |
| 1757 | + engines: {node: '>=7.0.0'} | |
| 1758 | + | |
| 1759 | + color-name@1.1.4: | |
| 1760 | + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} | |
| 1761 | + | |
| 1762 | + concat-map@0.0.1: | |
| 1763 | + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} | |
| 1764 | + | |
| 1765 | + convert-source-map@2.0.0: | |
| 1766 | + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} | |
| 1767 | + | |
| 1768 | + cross-spawn@7.0.6: | |
| 1769 | + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} | |
| 1770 | + engines: {node: '>= 8'} | |
| 1771 | + | |
| 1772 | + css-select@5.2.2: | |
| 1773 | + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} | |
| 1774 | + | |
| 1775 | + css-what@6.2.2: | |
| 1776 | + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} | |
| 1777 | + engines: {node: '>= 6'} | |
| 1778 | + | |
| 1779 | + csstype@3.2.3: | |
| 1780 | + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} | |
| 1781 | + | |
| 1782 | + damerau-levenshtein@1.0.8: | |
| 1783 | + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} | |
| 1784 | + | |
| 1785 | + data-view-buffer@1.0.2: | |
| 1786 | + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} | |
| 1787 | + engines: {node: '>= 0.4'} | |
| 1788 | + | |
| 1789 | + data-view-byte-length@1.0.2: | |
| 1790 | + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} | |
| 1791 | + engines: {node: '>= 0.4'} | |
| 1792 | + | |
| 1793 | + data-view-byte-offset@1.0.1: | |
| 1794 | + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} | |
| 1795 | + engines: {node: '>= 0.4'} | |
| 1796 | + | |
| 1797 | + debug@3.2.7: | |
| 1798 | + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} | |
| 1799 | + peerDependencies: | |
| 1800 | + supports-color: '*' | |
| 1801 | + peerDependenciesMeta: | |
| 1802 | + supports-color: | |
| 1803 | + optional: true | |
| 1804 | + | |
| 1805 | + debug@4.4.3: | |
| 1806 | + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} | |
| 1807 | + engines: {node: '>=6.0'} | |
| 1808 | + peerDependencies: | |
| 1809 | + supports-color: '*' | |
| 1810 | + peerDependenciesMeta: | |
| 1811 | + supports-color: | |
| 1812 | + optional: true | |
| 1813 | + | |
| 1814 | + deep-eql@5.0.2: | |
| 1815 | + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} | |
| 1816 | + engines: {node: '>=6'} | |
| 1817 | + | |
| 1818 | + deep-is@0.1.4: | |
| 1819 | + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} | |
| 1820 | + | |
| 1821 | + define-data-property@1.1.4: | |
| 1822 | + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} | |
| 1823 | + engines: {node: '>= 0.4'} | |
| 1824 | + | |
| 1825 | + define-properties@1.2.1: | |
| 1826 | + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} | |
| 1827 | + engines: {node: '>= 0.4'} | |
| 1828 | + | |
| 1829 | + detect-libc@2.1.2: | |
| 1830 | + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} | |
| 1831 | + engines: {node: '>=8'} | |
| 1832 | + | |
| 1833 | + doctrine@2.1.0: | |
| 1834 | + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} | |
| 1835 | + engines: {node: '>=0.10.0'} | |
| 1836 | + | |
| 1837 | + dom-serializer@2.0.0: | |
| 1838 | + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} | |
| 1839 | + | |
| 1840 | + domelementtype@2.3.0: | |
| 1841 | + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} | |
| 1842 | + | |
| 1843 | + domhandler@5.0.3: | |
| 1844 | + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} | |
| 1845 | + engines: {node: '>= 4'} | |
| 1846 | + | |
| 1847 | + domutils@3.2.2: | |
| 1848 | + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} | |
| 1849 | + | |
| 1850 | + drizzle-kit@0.31.10: | |
| 1851 | + resolution: {integrity: sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw==} | |
| 1852 | + hasBin: true | |
| 1853 | + | |
| 1854 | + drizzle-orm@0.45.2: | |
| 1855 | + resolution: {integrity: sha512-kY0BSaTNYWnoDMVoyY8uxmyHjpJW1geOmBMdSSicKo9CIIWkSxMIj2rkeSR51b8KAPB7m+qysjuHme5nKP+E5Q==} | |
| 1856 | + peerDependencies: | |
| 1857 | + '@aws-sdk/client-rds-data': '>=3' | |
| 1858 | + '@cloudflare/workers-types': '>=4' | |
| 1859 | + '@electric-sql/pglite': '>=0.2.0' | |
| 1860 | + '@libsql/client': '>=0.10.0' | |
| 1861 | + '@libsql/client-wasm': '>=0.10.0' | |
| 1862 | + '@neondatabase/serverless': '>=0.10.0' | |
| 1863 | + '@op-engineering/op-sqlite': '>=2' | |
| 1864 | + '@opentelemetry/api': ^1.4.1 | |
| 1865 | + '@planetscale/database': '>=1.13' | |
| 1866 | + '@prisma/client': '*' | |
| 1867 | + '@tidbcloud/serverless': '*' | |
| 1868 | + '@types/better-sqlite3': '*' | |
| 1869 | + '@types/pg': '*' | |
| 1870 | + '@types/sql.js': '*' | |
| 1871 | + '@upstash/redis': '>=1.34.7' | |
| 1872 | + '@vercel/postgres': '>=0.8.0' | |
| 1873 | + '@xata.io/client': '*' | |
| 1874 | + better-sqlite3: '>=7' | |
| 1875 | + bun-types: '*' | |
| 1876 | + expo-sqlite: '>=14.0.0' | |
| 1877 | + gel: '>=2' | |
| 1878 | + knex: '*' | |
| 1879 | + kysely: '*' | |
| 1880 | + mysql2: '>=2' | |
| 1881 | + pg: '>=8' | |
| 1882 | + postgres: '>=3' | |
| 1883 | + prisma: '*' | |
| 1884 | + sql.js: '>=1' | |
| 1885 | + sqlite3: '>=5' | |
| 1886 | + peerDependenciesMeta: | |
| 1887 | + '@aws-sdk/client-rds-data': | |
| 1888 | + optional: true | |
| 1889 | + '@cloudflare/workers-types': | |
| 1890 | + optional: true | |
| 1891 | + '@electric-sql/pglite': | |
| 1892 | + optional: true | |
| 1893 | + '@libsql/client': | |
| 1894 | + optional: true | |
| 1895 | + '@libsql/client-wasm': | |
| 1896 | + optional: true | |
| 1897 | + '@neondatabase/serverless': | |
| 1898 | + optional: true | |
| 1899 | + '@op-engineering/op-sqlite': | |
| 1900 | + optional: true | |
| 1901 | + '@opentelemetry/api': | |
| 1902 | + optional: true | |
| 1903 | + '@planetscale/database': | |
| 1904 | + optional: true | |
| 1905 | + '@prisma/client': | |
| 1906 | + optional: true | |
| 1907 | + '@tidbcloud/serverless': | |
| 1908 | + optional: true | |
| 1909 | + '@types/better-sqlite3': | |
| 1910 | + optional: true | |
| 1911 | + '@types/pg': | |
| 1912 | + optional: true | |
| 1913 | + '@types/sql.js': | |
| 1914 | + optional: true | |
| 1915 | + '@upstash/redis': | |
| 1916 | + optional: true | |
| 1917 | + '@vercel/postgres': | |
| 1918 | + optional: true | |
| 1919 | + '@xata.io/client': | |
| 1920 | + optional: true | |
| 1921 | + better-sqlite3: | |
| 1922 | + optional: true | |
| 1923 | + bun-types: | |
| 1924 | + optional: true | |
| 1925 | + expo-sqlite: | |
| 1926 | + optional: true | |
| 1927 | + gel: | |
| 1928 | + optional: true | |
| 1929 | + knex: | |
| 1930 | + optional: true | |
| 1931 | + kysely: | |
| 1932 | + optional: true | |
| 1933 | + mysql2: | |
| 1934 | + optional: true | |
| 1935 | + pg: | |
| 1936 | + optional: true | |
| 1937 | + postgres: | |
| 1938 | + optional: true | |
| 1939 | + prisma: | |
| 1940 | + optional: true | |
| 1941 | + sql.js: | |
| 1942 | + optional: true | |
| 1943 | + sqlite3: | |
| 1944 | + optional: true | |
| 1945 | + | |
| 1946 | + dunder-proto@1.0.1: | |
| 1947 | + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} | |
| 1948 | + engines: {node: '>= 0.4'} | |
| 1949 | + | |
| 1950 | + electron-to-chromium@1.5.422: | |
| 1951 | + resolution: {integrity: sha512-UvA/32XqrLDdZSn7Jllo1AYNcWji/G0d5M0GTViE7KoGBiMunw3a34Sb2KO4ZZyrSEhqsxFoVhWWJshdyfKqJA==} | |
| 1952 | + | |
| 1953 | + emoji-regex@9.2.2: | |
| 1954 | + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} | |
| 1955 | + | |
| 1956 | + encoding-sniffer@0.2.1: | |
| 1957 | + resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} | |
| 1958 | + | |
| 1959 | + enhanced-resolve@5.24.5: | |
| 1960 | + resolution: {integrity: sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==} | |
| 1961 | + engines: {node: '>=10.13.0'} | |
| 1962 | + | |
| 1963 | + entities@4.5.0: | |
| 1964 | + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} | |
| 1965 | + engines: {node: '>=0.12'} | |
| 1966 | + | |
| 1967 | + entities@6.0.1: | |
| 1968 | + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} | |
| 1969 | + engines: {node: '>=0.12'} | |
| 1970 | + | |
| 1971 | + entities@7.0.1: | |
| 1972 | + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} | |
| 1973 | + engines: {node: '>=0.12'} | |
| 1974 | + | |
| 1975 | + es-abstract-get@1.0.0: | |
| 1976 | + resolution: {integrity: sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==} | |
| 1977 | + engines: {node: '>= 0.4'} | |
| 1978 | + | |
| 1979 | + es-abstract@1.24.2: | |
| 1980 | + resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} | |
| 1981 | + engines: {node: '>= 0.4'} | |
| 1982 | + | |
| 1983 | + es-define-property@1.0.1: | |
| 1984 | + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} | |
| 1985 | + engines: {node: '>= 0.4'} | |
| 1986 | + | |
| 1987 | + es-errors@1.3.0: | |
| 1988 | + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} | |
| 1989 | + engines: {node: '>= 0.4'} | |
| 1990 | + | |
| 1991 | + es-iterator-helpers@1.4.0: | |
| 1992 | + resolution: {integrity: sha512-c/A0P0oxkACDc+cKWw8evLXK83oBKgn0qPOqCYT4x9uolpCIJAcYvJC9QYKNDRPsTeGyCrQ326jrvgZWdCdK5Q==} | |
| 1993 | + engines: {node: '>= 0.4'} | |
| 1994 | + | |
| 1995 | + es-module-lexer@1.7.0: | |
| 1996 | + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} | |
| 1997 | + | |
| 1998 | + es-object-atoms@1.1.2: | |
| 1999 | + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} | |
| 2000 | + engines: {node: '>= 0.4'} | |
| 2001 | + | |
| 2002 | + es-set-tostringtag@2.1.0: | |
| 2003 | + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} | |
| 2004 | + engines: {node: '>= 0.4'} | |
| 2005 | + | |
| 2006 | + es-shim-unscopables@1.1.0: | |
| 2007 | + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} | |
| 2008 | + engines: {node: '>= 0.4'} | |
| 2009 | + | |
| 2010 | + es-to-primitive@1.3.4: | |
| 2011 | + resolution: {integrity: sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==} | |
| 2012 | + engines: {node: '>= 0.4'} | |
| 2013 | + | |
| 2014 | + esbuild@0.18.20: | |
| 2015 | + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} | |
| 2016 | + engines: {node: '>=12'} | |
| 2017 | + hasBin: true | |
| 2018 | + | |
| 2019 | + esbuild@0.25.12: | |
| 2020 | + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} | |
| 2021 | + engines: {node: '>=18'} | |
| 2022 | + hasBin: true | |
| 2023 | + | |
| 2024 | + esbuild@0.28.2: | |
| 2025 | + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} | |
| 2026 | + engines: {node: '>=18'} | |
| 2027 | + hasBin: true | |
| 2028 | + | |
| 2029 | + escalade@3.2.0: | |
| 2030 | + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} | |
| 2031 | + engines: {node: '>=6'} | |
| 2032 | + | |
| 2033 | + escape-string-regexp@4.0.0: | |
| 2034 | + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} | |
| 2035 | + engines: {node: '>=10'} | |
| 2036 | + | |
| 2037 | + eslint-config-next@16.3.4: | |
| 2038 | + resolution: {integrity: sha512-35/8RM10huEL9vlr8hUZMERMENHBrnyHN3ZZkF9efSgzGaqK34jIqry44A956//zriUhUAUW0XSkcolhrryqAA==} | |
| 2039 | + peerDependencies: | |
| 2040 | + eslint: '>=9.0.0' | |
| 2041 | + typescript: '>=3.3.1' | |
| 2042 | + peerDependenciesMeta: | |
| 2043 | + typescript: | |
| 2044 | + optional: true | |
| 2045 | + | |
| 2046 | + eslint-import-resolver-node@0.3.10: | |
| 2047 | + resolution: {integrity: sha512-tRrKqFyCaKict5hOd244sL6EQFNycnMQnBe+j8uqGNXYzsImGbGUU4ibtoaBmv5FLwJwcFJNeg1GeVjQfbMrDQ==} | |
| 2048 | + | |
| 2049 | + eslint-import-resolver-typescript@3.10.1: | |
| 2050 | + resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==} | |
| 2051 | + engines: {node: ^14.18.0 || >=16.0.0} | |
| 2052 | + peerDependencies: | |
| 2053 | + eslint: '*' | |
| 2054 | + eslint-plugin-import: '*' | |
| 2055 | + eslint-plugin-import-x: '*' | |
| 2056 | + peerDependenciesMeta: | |
| 2057 | + eslint-plugin-import: | |
| 2058 | + optional: true | |
| 2059 | + eslint-plugin-import-x: | |
| 2060 | + optional: true | |
| 2061 | + | |
| 2062 | + eslint-module-utils@2.14.0: | |
| 2063 | + resolution: {integrity: sha512-W2WCRZ9Dqntd+2u8jJcVMV2PKulc6RdLgUUoh/yQr3uB6lo/ZOeGx11sv60/8S4QFFKNslAlWhr9u0Ef7ZW6Ig==} | |
| 2064 | + engines: {node: '>=4'} | |
| 2065 | + peerDependencies: | |
| 2066 | + '@typescript-eslint/parser': '*' | |
| 2067 | + eslint: '*' | |
| 2068 | + eslint-import-resolver-node: '*' | |
| 2069 | + eslint-import-resolver-typescript: '*' | |
| 2070 | + eslint-import-resolver-webpack: '*' | |
| 2071 | + peerDependenciesMeta: | |
| 2072 | + '@typescript-eslint/parser': | |
| 2073 | + optional: true | |
| 2074 | + eslint: | |
| 2075 | + optional: true | |
| 2076 | + eslint-import-resolver-node: | |
| 2077 | + optional: true | |
| 2078 | + eslint-import-resolver-typescript: | |
| 2079 | + optional: true | |
| 2080 | + eslint-import-resolver-webpack: | |
| 2081 | + optional: true | |
| 2082 | + | |
| 2083 | + eslint-plugin-import@2.32.0: | |
| 2084 | + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} | |
| 2085 | + engines: {node: '>=4'} | |
| 2086 | + peerDependencies: | |
| 2087 | + '@typescript-eslint/parser': '*' | |
| 2088 | + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 | |
| 2089 | + peerDependenciesMeta: | |
| 2090 | + '@typescript-eslint/parser': | |
| 2091 | + optional: true | |
| 2092 | + | |
| 2093 | + eslint-plugin-jsx-a11y@6.10.2: | |
| 2094 | + resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} | |
| 2095 | + engines: {node: '>=4.0'} | |
| 2096 | + peerDependencies: | |
| 2097 | + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 | |
| 2098 | + | |
| 2099 | + eslint-plugin-react-hooks@7.1.1: | |
| 2100 | + resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} | |
| 2101 | + engines: {node: '>=18'} | |
| 2102 | + peerDependencies: | |
| 2103 | + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 | |
| 2104 | + | |
| 2105 | + eslint-plugin-react@7.37.5: | |
| 2106 | + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} | |
| 2107 | + engines: {node: '>=4'} | |
| 2108 | + peerDependencies: | |
| 2109 | + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 | |
| 2110 | + | |
| 2111 | + eslint-scope@8.4.0: | |
| 2112 | + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} | |
| 2113 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 2114 | + | |
| 2115 | + eslint-visitor-keys@3.4.3: | |
| 2116 | + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} | |
| 2117 | + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} | |
| 2118 | + | |
| 2119 | + eslint-visitor-keys@4.2.1: | |
| 2120 | + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} | |
| 2121 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 2122 | + | |
| 2123 | + eslint-visitor-keys@5.0.1: | |
| 2124 | + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} | |
| 2125 | + engines: {node: ^20.19.0 || ^22.13.0 || >=24} | |
| 2126 | + | |
| 2127 | + eslint@9.39.5: | |
| 2128 | + resolution: {integrity: sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==} | |
| 2129 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 2130 | + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. | |
| 2131 | + hasBin: true | |
| 2132 | + peerDependencies: | |
| 2133 | + jiti: '*' | |
| 2134 | + peerDependenciesMeta: | |
| 2135 | + jiti: | |
| 2136 | + optional: true | |
| 2137 | + | |
| 2138 | + espree@10.4.0: | |
| 2139 | + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} | |
| 2140 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 2141 | + | |
| 2142 | + esquery@1.7.0: | |
| 2143 | + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} | |
| 2144 | + engines: {node: '>=0.10'} | |
| 2145 | + | |
| 2146 | + esrecurse@4.3.0: | |
| 2147 | + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} | |
| 2148 | + engines: {node: '>=4.0'} | |
| 2149 | + | |
| 2150 | + estraverse@5.3.0: | |
| 2151 | + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} | |
| 2152 | + engines: {node: '>=4.0'} | |
| 2153 | + | |
| 2154 | + estree-walker@3.0.3: | |
| 2155 | + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} | |
| 2156 | + | |
| 2157 | + esutils@2.0.3: | |
| 2158 | + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} | |
| 2159 | + engines: {node: '>=0.10.0'} | |
| 2160 | + | |
| 2161 | + expect-type@1.4.0: | |
| 2162 | + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} | |
| 2163 | + engines: {node: '>=12.0.0'} | |
| 2164 | + | |
| 2165 | + fast-deep-equal@3.1.3: | |
| 2166 | + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} | |
| 2167 | + | |
| 2168 | + fast-glob@3.3.1: | |
| 2169 | + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} | |
| 2170 | + engines: {node: '>=8.6.0'} | |
| 2171 | + | |
| 2172 | + fast-json-stable-stringify@2.1.0: | |
| 2173 | + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} | |
| 2174 | + | |
| 2175 | + fast-levenshtein@2.0.6: | |
| 2176 | + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} | |
| 2177 | + | |
| 2178 | + fastq@1.20.3: | |
| 2179 | + resolution: {integrity: sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==} | |
| 2180 | + | |
| 2181 | + fdir@6.5.0: | |
| 2182 | + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} | |
| 2183 | + engines: {node: '>=12.0.0'} | |
| 2184 | + peerDependencies: | |
| 2185 | + picomatch: ^3 || ^4 | |
| 2186 | + peerDependenciesMeta: | |
| 2187 | + picomatch: | |
| 2188 | + optional: true | |
| 2189 | + | |
| 2190 | + file-entry-cache@8.0.0: | |
| 2191 | + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} | |
| 2192 | + engines: {node: '>=16.0.0'} | |
| 2193 | + | |
| 2194 | + fill-range@7.1.1: | |
| 2195 | + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} | |
| 2196 | + engines: {node: '>=8'} | |
| 2197 | + | |
| 2198 | + find-up@5.0.0: | |
| 2199 | + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} | |
| 2200 | + engines: {node: '>=10'} | |
| 2201 | + | |
| 2202 | + flat-cache@4.0.1: | |
| 2203 | + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} | |
| 2204 | + engines: {node: '>=16'} | |
| 2205 | + | |
| 2206 | + flatted@3.4.4: | |
| 2207 | + resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} | |
| 2208 | + | |
| 2209 | + for-each@0.3.5: | |
| 2210 | + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} | |
| 2211 | + engines: {node: '>= 0.4'} | |
| 2212 | + | |
| 2213 | + fsevents@2.3.3: | |
| 2214 | + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} | |
| 2215 | + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} | |
| 2216 | + os: [darwin] | |
| 2217 | + | |
| 2218 | + function-bind@1.1.2: | |
| 2219 | + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} | |
| 2220 | + | |
| 2221 | + function.prototype.name@1.2.0: | |
| 2222 | + resolution: {integrity: sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==} | |
| 2223 | + engines: {node: '>= 0.4'} | |
| 2224 | + | |
| 2225 | + functions-have-names@1.2.3: | |
| 2226 | + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} | |
| 2227 | + | |
| 2228 | + generator-function@2.0.1: | |
| 2229 | + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} | |
| 2230 | + engines: {node: '>= 0.4'} | |
| 2231 | + | |
| 2232 | + gensync@1.0.0-beta.2: | |
| 2233 | + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} | |
| 2234 | + engines: {node: '>=6.9.0'} | |
| 2235 | + | |
| 2236 | + get-intrinsic@1.3.0: | |
| 2237 | + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} | |
| 2238 | + engines: {node: '>= 0.4'} | |
| 2239 | + | |
| 2240 | + get-proto@1.0.1: | |
| 2241 | + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} | |
| 2242 | + engines: {node: '>= 0.4'} | |
| 2243 | + | |
| 2244 | + get-symbol-description@1.1.0: | |
| 2245 | + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} | |
| 2246 | + engines: {node: '>= 0.4'} | |
| 2247 | + | |
| 2248 | + get-tsconfig@4.14.3: | |
| 2249 | + resolution: {integrity: sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA==} | |
| 2250 | + | |
| 2251 | + glob-parent@5.1.2: | |
| 2252 | + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} | |
| 2253 | + engines: {node: '>= 6'} | |
| 2254 | + | |
| 2255 | + glob-parent@6.0.2: | |
| 2256 | + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} | |
| 2257 | + engines: {node: '>=10.13.0'} | |
| 2258 | + | |
| 2259 | + globals@14.0.0: | |
| 2260 | + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} | |
| 2261 | + engines: {node: '>=18'} | |
| 2262 | + | |
| 2263 | + globals@16.4.0: | |
| 2264 | + resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} | |
| 2265 | + engines: {node: '>=18'} | |
| 2266 | + | |
| 2267 | + globalthis@1.0.4: | |
| 2268 | + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} | |
| 2269 | + engines: {node: '>= 0.4'} | |
| 2270 | + | |
| 2271 | + gopd@1.2.0: | |
| 2272 | + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} | |
| 2273 | + engines: {node: '>= 0.4'} | |
| 2274 | + | |
| 2275 | + graceful-fs@4.2.11: | |
| 2276 | + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} | |
| 2277 | + | |
| 2278 | + has-bigints@1.1.0: | |
| 2279 | + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} | |
| 2280 | + engines: {node: '>= 0.4'} | |
| 2281 | + | |
| 2282 | + has-flag@4.0.0: | |
| 2283 | + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} | |
| 2284 | + engines: {node: '>=8'} | |
| 2285 | + | |
| 2286 | + has-property-descriptors@1.0.2: | |
| 2287 | + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} | |
| 2288 | + | |
| 2289 | + has-proto@1.2.0: | |
| 2290 | + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} | |
| 2291 | + engines: {node: '>= 0.4'} | |
| 2292 | + | |
| 2293 | + has-symbols@1.1.0: | |
| 2294 | + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} | |
| 2295 | + engines: {node: '>= 0.4'} | |
| 2296 | + | |
| 2297 | + has-tostringtag@1.0.2: | |
| 2298 | + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} | |
| 2299 | + engines: {node: '>= 0.4'} | |
| 2300 | + | |
| 2301 | + hasown@2.0.4: | |
| 2302 | + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} | |
| 2303 | + engines: {node: '>= 0.4'} | |
| 2304 | + | |
| 2305 | + hermes-estree@0.25.1: | |
| 2306 | + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} | |
| 2307 | + | |
| 2308 | + hermes-parser@0.25.1: | |
| 2309 | + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} | |
| 2310 | + | |
| 2311 | + htmlparser2@10.1.0: | |
| 2312 | + resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} | |
| 2313 | + | |
| 2314 | + iconv-lite@0.6.3: | |
| 2315 | + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} | |
| 2316 | + engines: {node: '>=0.10.0'} | |
| 2317 | + | |
| 2318 | + ignore@5.3.2: | |
| 2319 | + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} | |
| 2320 | + engines: {node: '>= 4'} | |
| 2321 | + | |
| 2322 | + ignore@7.0.8: | |
| 2323 | + resolution: {integrity: sha512-YYNsSlXBjMk92SKnkwvB5LOVSa6OznlFUGcsvrFgNJbJCd0M1XKeFVRc8ZByeCqz32FivYNHJVooLmdqrmvp/Q==} | |
| 2324 | + engines: {node: '>= 4'} | |
| 2325 | + | |
| 2326 | + import-fresh@3.3.1: | |
| 2327 | + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} | |
| 2328 | + engines: {node: '>=6'} | |
| 2329 | + | |
| 2330 | + imurmurhash@0.1.4: | |
| 2331 | + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} | |
| 2332 | + engines: {node: '>=0.8.19'} | |
| 2333 | + | |
| 2334 | + internal-slot@1.1.0: | |
| 2335 | + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} | |
| 2336 | + engines: {node: '>= 0.4'} | |
| 2337 | + | |
| 2338 | + is-array-buffer@3.0.5: | |
| 2339 | + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} | |
| 2340 | + engines: {node: '>= 0.4'} | |
| 2341 | + | |
| 2342 | + is-async-function@2.1.1: | |
| 2343 | + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} | |
| 2344 | + engines: {node: '>= 0.4'} | |
| 2345 | + | |
| 2346 | + is-bigint@1.1.0: | |
| 2347 | + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} | |
| 2348 | + engines: {node: '>= 0.4'} | |
| 2349 | + | |
| 2350 | + is-boolean-object@1.2.2: | |
| 2351 | + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} | |
| 2352 | + engines: {node: '>= 0.4'} | |
| 2353 | + | |
| 2354 | + is-bun-module@2.0.0: | |
| 2355 | + resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} | |
| 2356 | + | |
| 2357 | + is-callable@1.2.7: | |
| 2358 | + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} | |
| 2359 | + engines: {node: '>= 0.4'} | |
| 2360 | + | |
| 2361 | + is-core-module@2.16.2: | |
| 2362 | + resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} | |
| 2363 | + engines: {node: '>= 0.4'} | |
| 2364 | + | |
| 2365 | + is-data-view@1.0.2: | |
| 2366 | + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} | |
| 2367 | + engines: {node: '>= 0.4'} | |
| 2368 | + | |
| 2369 | + is-date-object@1.1.0: | |
| 2370 | + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} | |
| 2371 | + engines: {node: '>= 0.4'} | |
| 2372 | + | |
| 2373 | + is-document.all@1.0.0: | |
| 2374 | + resolution: {integrity: sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==} | |
| 2375 | + engines: {node: '>= 0.4'} | |
| 2376 | + | |
| 2377 | + is-extglob@2.1.1: | |
| 2378 | + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} | |
| 2379 | + engines: {node: '>=0.10.0'} | |
| 2380 | + | |
| 2381 | + is-finalizationregistry@1.1.1: | |
| 2382 | + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} | |
| 2383 | + engines: {node: '>= 0.4'} | |
| 2384 | + | |
| 2385 | + is-generator-function@1.1.2: | |
| 2386 | + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} | |
| 2387 | + engines: {node: '>= 0.4'} | |
| 2388 | + | |
| 2389 | + is-glob@4.0.3: | |
| 2390 | + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} | |
| 2391 | + engines: {node: '>=0.10.0'} | |
| 2392 | + | |
| 2393 | + is-map@2.0.3: | |
| 2394 | + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} | |
| 2395 | + engines: {node: '>= 0.4'} | |
| 2396 | + | |
| 2397 | + is-negative-zero@2.0.3: | |
| 2398 | + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} | |
| 2399 | + engines: {node: '>= 0.4'} | |
| 2400 | + | |
| 2401 | + is-number-object@1.1.1: | |
| 2402 | + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} | |
| 2403 | + engines: {node: '>= 0.4'} | |
| 2404 | + | |
| 2405 | + is-number@7.0.0: | |
| 2406 | + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} | |
| 2407 | + engines: {node: '>=0.12.0'} | |
| 2408 | + | |
| 2409 | + is-regex@1.2.1: | |
| 2410 | + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} | |
| 2411 | + engines: {node: '>= 0.4'} | |
| 2412 | + | |
| 2413 | + is-set@2.0.3: | |
| 2414 | + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} | |
| 2415 | + engines: {node: '>= 0.4'} | |
| 2416 | + | |
| 2417 | + is-shared-array-buffer@1.0.4: | |
| 2418 | + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} | |
| 2419 | + engines: {node: '>= 0.4'} | |
| 2420 | + | |
| 2421 | + is-string@1.1.1: | |
| 2422 | + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} | |
| 2423 | + engines: {node: '>= 0.4'} | |
| 2424 | + | |
| 2425 | + is-symbol@1.1.1: | |
| 2426 | + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} | |
| 2427 | + engines: {node: '>= 0.4'} | |
| 2428 | + | |
| 2429 | + is-typed-array@1.1.15: | |
| 2430 | + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} | |
| 2431 | + engines: {node: '>= 0.4'} | |
| 2432 | + | |
| 2433 | + is-weakmap@2.0.2: | |
| 2434 | + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} | |
| 2435 | + engines: {node: '>= 0.4'} | |
| 2436 | + | |
| 2437 | + is-weakref@1.1.1: | |
| 2438 | + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} | |
| 2439 | + engines: {node: '>= 0.4'} | |
| 2440 | + | |
| 2441 | + is-weakset@2.0.4: | |
| 2442 | + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} | |
| 2443 | + engines: {node: '>= 0.4'} | |
| 2444 | + | |
| 2445 | + isarray@2.0.5: | |
| 2446 | + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} | |
| 2447 | + | |
| 2448 | + isexe@2.0.0: | |
| 2449 | + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} | |
| 2450 | + | |
| 2451 | + iterator.prototype@1.1.5: | |
| 2452 | + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} | |
| 2453 | + engines: {node: '>= 0.4'} | |
| 2454 | + | |
| 2455 | + jiti@2.7.0: | |
| 2456 | + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} | |
| 2457 | + hasBin: true | |
| 2458 | + | |
| 2459 | + js-tokens@4.0.0: | |
| 2460 | + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} | |
| 2461 | + | |
| 2462 | + js-tokens@9.0.1: | |
| 2463 | + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} | |
| 2464 | + | |
| 2465 | + js-yaml@4.3.2: | |
| 2466 | + resolution: {integrity: sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==} | |
| 2467 | + hasBin: true | |
| 2468 | + | |
| 2469 | + jsesc@3.1.0: | |
| 2470 | + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} | |
| 2471 | + engines: {node: '>=6'} | |
| 2472 | + hasBin: true | |
| 2473 | + | |
| 2474 | + json-buffer@3.0.1: | |
| 2475 | + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} | |
| 2476 | + | |
| 2477 | + json-schema-traverse@0.4.1: | |
| 2478 | + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} | |
| 2479 | + | |
| 2480 | + json-stable-stringify-without-jsonify@1.0.1: | |
| 2481 | + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} | |
| 2482 | + | |
| 2483 | + json5@1.0.2: | |
| 2484 | + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} | |
| 2485 | + hasBin: true | |
| 2486 | + | |
| 2487 | + json5@2.2.3: | |
| 2488 | + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} | |
| 2489 | + engines: {node: '>=6'} | |
| 2490 | + hasBin: true | |
| 2491 | + | |
| 2492 | + jsx-ast-utils@3.3.5: | |
| 2493 | + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} | |
| 2494 | + engines: {node: '>=4.0'} | |
| 2495 | + | |
| 2496 | + keyv@4.5.4: | |
| 2497 | + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} | |
| 2498 | + | |
| 2499 | + language-subtag-registry@0.3.23: | |
| 2500 | + resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} | |
| 2501 | + | |
| 2502 | + language-tags@1.0.9: | |
| 2503 | + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} | |
| 2504 | + engines: {node: '>=0.10'} | |
| 2505 | + | |
| 2506 | + levn@0.4.1: | |
| 2507 | + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} | |
| 2508 | + engines: {node: '>= 0.8.0'} | |
| 2509 | + | |
| 2510 | + lightningcss-android-arm64@1.32.0: | |
| 2511 | + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} | |
| 2512 | + engines: {node: '>= 12.0.0'} | |
| 2513 | + cpu: [arm64] | |
| 2514 | + os: [android] | |
| 2515 | + | |
| 2516 | + lightningcss-darwin-arm64@1.32.0: | |
| 2517 | + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} | |
| 2518 | + engines: {node: '>= 12.0.0'} | |
| 2519 | + cpu: [arm64] | |
| 2520 | + os: [darwin] | |
| 2521 | + | |
| 2522 | + lightningcss-darwin-x64@1.32.0: | |
| 2523 | + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} | |
| 2524 | + engines: {node: '>= 12.0.0'} | |
| 2525 | + cpu: [x64] | |
| 2526 | + os: [darwin] | |
| 2527 | + | |
| 2528 | + lightningcss-freebsd-x64@1.32.0: | |
| 2529 | + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} | |
| 2530 | + engines: {node: '>= 12.0.0'} | |
| 2531 | + cpu: [x64] | |
| 2532 | + os: [freebsd] | |
| 2533 | + | |
| 2534 | + lightningcss-linux-arm-gnueabihf@1.32.0: | |
| 2535 | + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} | |
| 2536 | + engines: {node: '>= 12.0.0'} | |
| 2537 | + cpu: [arm] | |
| 2538 | + os: [linux] | |
| 2539 | + | |
| 2540 | + lightningcss-linux-arm64-gnu@1.32.0: | |
| 2541 | + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} | |
| 2542 | + engines: {node: '>= 12.0.0'} | |
| 2543 | + cpu: [arm64] | |
| 2544 | + os: [linux] | |
| 2545 | + libc: [glibc] | |
| 2546 | + | |
| 2547 | + lightningcss-linux-arm64-musl@1.32.0: | |
| 2548 | + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} | |
| 2549 | + engines: {node: '>= 12.0.0'} | |
| 2550 | + cpu: [arm64] | |
| 2551 | + os: [linux] | |
| 2552 | + libc: [musl] | |
| 2553 | + | |
| 2554 | + lightningcss-linux-x64-gnu@1.32.0: | |
| 2555 | + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} | |
| 2556 | + engines: {node: '>= 12.0.0'} | |
| 2557 | + cpu: [x64] | |
| 2558 | + os: [linux] | |
| 2559 | + libc: [glibc] | |
| 2560 | + | |
| 2561 | + lightningcss-linux-x64-musl@1.32.0: | |
| 2562 | + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} | |
| 2563 | + engines: {node: '>= 12.0.0'} | |
| 2564 | + cpu: [x64] | |
| 2565 | + os: [linux] | |
| 2566 | + libc: [musl] | |
| 2567 | + | |
| 2568 | + lightningcss-win32-arm64-msvc@1.32.0: | |
| 2569 | + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} | |
| 2570 | + engines: {node: '>= 12.0.0'} | |
| 2571 | + cpu: [arm64] | |
| 2572 | + os: [win32] | |
| 2573 | + | |
| 2574 | + lightningcss-win32-x64-msvc@1.32.0: | |
| 2575 | + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} | |
| 2576 | + engines: {node: '>= 12.0.0'} | |
| 2577 | + cpu: [x64] | |
| 2578 | + os: [win32] | |
| 2579 | + | |
| 2580 | + lightningcss@1.32.0: | |
| 2581 | + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} | |
| 2582 | + engines: {node: '>= 12.0.0'} | |
| 2583 | + | |
| 2584 | + locate-path@6.0.0: | |
| 2585 | + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} | |
| 2586 | + engines: {node: '>=10'} | |
| 2587 | + | |
| 2588 | + lodash.merge@4.6.2: | |
| 2589 | + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} | |
| 2590 | + | |
| 2591 | + loose-envify@1.4.0: | |
| 2592 | + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} | |
| 2593 | + hasBin: true | |
| 2594 | + | |
| 2595 | + loupe@3.2.1: | |
| 2596 | + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} | |
| 2597 | + | |
| 2598 | + lru-cache@5.1.1: | |
| 2599 | + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} | |
| 2600 | + | |
| 2601 | + lucide-react@1.41.0: | |
| 2602 | + resolution: {integrity: sha512-6lksP35l6KszDKUeRTi4LV7i6DEe0Yzl2ALJm9j4c5xEYN91GdW1xGsawGMOg2mgjF5GHBVX8pKX9kP+cWsP3Q==} | |
| 2603 | + peerDependencies: | |
| 2604 | + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 | |
| 2605 | + | |
| 2606 | + magic-string@0.30.21: | |
| 2607 | + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} | |
| 2608 | + | |
| 2609 | + math-intrinsics@1.1.0: | |
| 2610 | + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} | |
| 2611 | + engines: {node: '>= 0.4'} | |
| 2612 | + | |
| 2613 | + merge2@1.4.1: | |
| 2614 | + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} | |
| 2615 | + engines: {node: '>= 8'} | |
| 2616 | + | |
| 2617 | + micromatch@4.0.8: | |
| 2618 | + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} | |
| 2619 | + engines: {node: '>=8.6'} | |
| 2620 | + | |
| 2621 | + minimatch@10.2.6: | |
| 2622 | + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} | |
| 2623 | + engines: {node: 18 || 20 || >=22} | |
| 2624 | + | |
| 2625 | + minimatch@3.1.5: | |
| 2626 | + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} | |
| 2627 | + | |
| 2628 | + minimist@1.2.8: | |
| 2629 | + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} | |
| 2630 | + | |
| 2631 | + ms@2.1.3: | |
| 2632 | + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} | |
| 2633 | + | |
| 2634 | + nanoid@3.3.18: | |
| 2635 | + resolution: {integrity: sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==} | |
| 2636 | + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} | |
| 2637 | + hasBin: true | |
| 2638 | + | |
| 2639 | + napi-postinstall@0.3.4: | |
| 2640 | + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} | |
| 2641 | + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} | |
| 2642 | + hasBin: true | |
| 2643 | + | |
| 2644 | + natural-compare@1.4.0: | |
| 2645 | + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} | |
| 2646 | + | |
| 2647 | + next@16.3.4: | |
| 2648 | + resolution: {integrity: sha512-/Ztf6CeRH+ejEXUrYtqI4gkS66eFIHuSwqi60RgcpWKodxFZx2/dqVCMKBwILfAHXQ+F1b1vAudgj3mnxqtoIA==} | |
| 2649 | + engines: {node: '>=20.9.0'} | |
| 2650 | + hasBin: true | |
| 2651 | + peerDependencies: | |
| 2652 | + '@opentelemetry/api': ^1.1.0 | |
| 2653 | + '@playwright/test': ^1.51.1 | |
| 2654 | + babel-plugin-react-compiler: '*' | |
| 2655 | + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 | |
| 2656 | + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 | |
| 2657 | + sass: ^1.3.0 | |
| 2658 | + peerDependenciesMeta: | |
| 2659 | + '@opentelemetry/api': | |
| 2660 | + optional: true | |
| 2661 | + '@playwright/test': | |
| 2662 | + optional: true | |
| 2663 | + babel-plugin-react-compiler: | |
| 2664 | + optional: true | |
| 2665 | + sass: | |
| 2666 | + optional: true | |
| 2667 | + | |
| 2668 | + node-exports-info@1.6.2: | |
| 2669 | + resolution: {integrity: sha512-kXs9Go0cah0qHVV2v389IXQLdLCeE1xfFtjOAF+iobu0OIoG1pje8At2vMHyaPMiPMnG/LWP50twML21eMcAag==} | |
| 2670 | + engines: {node: '>= 0.4'} | |
| 2671 | + | |
| 2672 | + node-releases@2.0.54: | |
| 2673 | + resolution: {integrity: sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==} | |
| 2674 | + engines: {node: '>=18'} | |
| 2675 | + | |
| 2676 | + nth-check@2.1.1: | |
| 2677 | + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} | |
| 2678 | + | |
| 2679 | + object-assign@4.1.1: | |
| 2680 | + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} | |
| 2681 | + engines: {node: '>=0.10.0'} | |
| 2682 | + | |
| 2683 | + object-inspect@1.13.4: | |
| 2684 | + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} | |
| 2685 | + engines: {node: '>= 0.4'} | |
| 2686 | + | |
| 2687 | + object-keys@1.1.1: | |
| 2688 | + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} | |
| 2689 | + engines: {node: '>= 0.4'} | |
| 2690 | + | |
| 2691 | + object.assign@4.1.7: | |
| 2692 | + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} | |
| 2693 | + engines: {node: '>= 0.4'} | |
| 2694 | + | |
| 2695 | + object.entries@1.1.9: | |
| 2696 | + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} | |
| 2697 | + engines: {node: '>= 0.4'} | |
| 2698 | + | |
| 2699 | + object.fromentries@2.0.8: | |
| 2700 | + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} | |
| 2701 | + engines: {node: '>= 0.4'} | |
| 2702 | + | |
| 2703 | + object.groupby@1.0.3: | |
| 2704 | + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} | |
| 2705 | + engines: {node: '>= 0.4'} | |
| 2706 | + | |
| 2707 | + object.values@1.2.1: | |
| 2708 | + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} | |
| 2709 | + engines: {node: '>= 0.4'} | |
| 2710 | + | |
| 2711 | + on-exit-leak-free@2.1.2: | |
| 2712 | + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} | |
| 2713 | + engines: {node: '>=14.0.0'} | |
| 2714 | + | |
| 2715 | + optionator@0.9.4: | |
| 2716 | + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} | |
| 2717 | + engines: {node: '>= 0.8.0'} | |
| 2718 | + | |
| 2719 | + own-keys@1.0.2: | |
| 2720 | + resolution: {integrity: sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==} | |
| 2721 | + engines: {node: '>= 0.4'} | |
| 2722 | + | |
| 2723 | + p-limit@3.1.0: | |
| 2724 | + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} | |
| 2725 | + engines: {node: '>=10'} | |
| 2726 | + | |
| 2727 | + p-locate@5.0.0: | |
| 2728 | + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} | |
| 2729 | + engines: {node: '>=10'} | |
| 2730 | + | |
| 2731 | + parent-module@1.0.1: | |
| 2732 | + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} | |
| 2733 | + engines: {node: '>=6'} | |
| 2734 | + | |
| 2735 | + parse5-htmlparser2-tree-adapter@7.1.0: | |
| 2736 | + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} | |
| 2737 | + | |
| 2738 | + parse5-parser-stream@7.1.2: | |
| 2739 | + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} | |
| 2740 | + | |
| 2741 | + parse5@7.3.0: | |
| 2742 | + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} | |
| 2743 | + | |
| 2744 | + path-exists@4.0.0: | |
| 2745 | + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} | |
| 2746 | + engines: {node: '>=8'} | |
| 2747 | + | |
| 2748 | + path-key@3.1.1: | |
| 2749 | + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} | |
| 2750 | + engines: {node: '>=8'} | |
| 2751 | + | |
| 2752 | + path-parse@1.0.7: | |
| 2753 | + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} | |
| 2754 | + | |
| 2755 | + pathe@2.0.3: | |
| 2756 | + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} | |
| 2757 | + | |
| 2758 | + pathval@2.0.1: | |
| 2759 | + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} | |
| 2760 | + engines: {node: '>= 14.16'} | |
| 2761 | + | |
| 2762 | + picocolors@1.1.1: | |
| 2763 | + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} | |
| 2764 | + | |
| 2765 | + picomatch@2.3.2: | |
| 2766 | + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} | |
| 2767 | + engines: {node: '>=8.6'} | |
| 2768 | + | |
| 2769 | + picomatch@4.0.7: | |
| 2770 | + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} | |
| 2771 | + engines: {node: '>=12'} | |
| 2772 | + | |
| 2773 | + pino-abstract-transport@2.0.0: | |
| 2774 | + resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} | |
| 2775 | + | |
| 2776 | + pino-std-serializers@7.1.0: | |
| 2777 | + resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} | |
| 2778 | + | |
| 2779 | + pino@9.14.0: | |
| 2780 | + resolution: {integrity: sha512-8OEwKp5juEvb/MjpIc4hjqfgCNysrS94RIOMXYvpYCdm/jglrKEiAYmiumbmGhCvs+IcInsphYDFwqrjr7398w==} | |
| 2781 | + hasBin: true | |
| 2782 | + | |
| 2783 | + possible-typed-array-names@1.1.0: | |
| 2784 | + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} | |
| 2785 | + engines: {node: '>= 0.4'} | |
| 2786 | + | |
| 2787 | + postcss@8.5.23: | |
| 2788 | + resolution: {integrity: sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==} | |
| 2789 | + engines: {node: ^10 || ^12 || >=14} | |
| 2790 | + | |
| 2791 | + postcss@8.5.28: | |
| 2792 | + resolution: {integrity: sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==} | |
| 2793 | + engines: {node: ^10 || ^12 || >=14} | |
| 2794 | + | |
| 2795 | + postgres@3.4.9: | |
| 2796 | + resolution: {integrity: sha512-GD3qdB0x1z9xgFI6cdRD6xu2Sp2WCOEoe3mtnyB5Ee0XrrL5Pe+e4CCnJrRMnL1zYtRDZmQQVbvOttLnKDLnaw==} | |
| 2797 | + engines: {node: '>=12'} | |
| 2798 | + | |
| 2799 | + prelude-ls@1.2.1: | |
| 2800 | + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} | |
| 2801 | + engines: {node: '>= 0.8.0'} | |
| 2802 | + | |
| 2803 | + process-warning@5.1.0: | |
| 2804 | + resolution: {integrity: sha512-jQSaVHsPgtyw60e1rQ/A+/ArPEj/S8pS/vFnyGa/gYFXrKk/6RuDkoqVDQ5NI5MmS01698ltlAk0NoDBNLujRw==} | |
| 2805 | + | |
| 2806 | + prop-types@15.8.1: | |
| 2807 | + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} | |
| 2808 | + | |
| 2809 | + punycode@2.3.1: | |
| 2810 | + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} | |
| 2811 | + engines: {node: '>=6'} | |
| 2812 | + | |
| 2813 | + queue-microtask@1.2.3: | |
| 2814 | + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} | |
| 2815 | + | |
| 2816 | + quick-format-unescaped@4.0.4: | |
| 2817 | + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} | |
| 2818 | + | |
| 2819 | + react-dom@19.2.8: | |
| 2820 | + resolution: {integrity: sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==} | |
| 2821 | + peerDependencies: | |
| 2822 | + react: ^19.2.8 | |
| 2823 | + | |
| 2824 | + react-is@16.13.1: | |
| 2825 | + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} | |
| 2826 | + | |
| 2827 | + react@19.2.8: | |
| 2828 | + resolution: {integrity: sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==} | |
| 2829 | + engines: {node: '>=0.10.0'} | |
| 2830 | + | |
| 2831 | + real-require@0.2.0: | |
| 2832 | + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} | |
| 2833 | + engines: {node: '>= 12.13.0'} | |
| 2834 | + | |
| 2835 | + reflect.getprototypeof@1.0.10: | |
| 2836 | + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} | |
| 2837 | + engines: {node: '>= 0.4'} | |
| 2838 | + | |
| 2839 | + regexp.prototype.flags@1.5.4: | |
| 2840 | + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} | |
| 2841 | + engines: {node: '>= 0.4'} | |
| 2842 | + | |
| 2843 | + resolve-from@4.0.0: | |
| 2844 | + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} | |
| 2845 | + engines: {node: '>=4'} | |
| 2846 | + | |
| 2847 | + resolve-pkg-maps@1.0.0: | |
| 2848 | + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} | |
| 2849 | + | |
| 2850 | + resolve@2.0.0-next.7: | |
| 2851 | + resolution: {integrity: sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==} | |
| 2852 | + engines: {node: '>= 0.4'} | |
| 2853 | + hasBin: true | |
| 2854 | + | |
| 2855 | + reusify@1.1.0: | |
| 2856 | + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} | |
| 2857 | + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} | |
| 2858 | + | |
| 2859 | + rollup@4.63.1: | |
| 2860 | + resolution: {integrity: sha512-3Df9jsstwhccuEfmAMi9l8XUh/GOkVObmFTU7CCVBysEbcOZLl84jCtaAZMcPiMz2EGKsATzQcU+Xr3n/wU6cg==} | |
| 2861 | + engines: {node: '>=18.0.0', npm: '>=8.0.0'} | |
| 2862 | + hasBin: true | |
| 2863 | + | |
| 2864 | + run-parallel@1.2.0: | |
| 2865 | + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} | |
| 2866 | + | |
| 2867 | + safe-array-concat@1.1.4: | |
| 2868 | + resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} | |
| 2869 | + engines: {node: '>=0.4'} | |
| 2870 | + | |
| 2871 | + safe-push-apply@1.0.0: | |
| 2872 | + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} | |
| 2873 | + engines: {node: '>= 0.4'} | |
| 2874 | + | |
| 2875 | + safe-regex-test@1.1.0: | |
| 2876 | + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} | |
| 2877 | + engines: {node: '>= 0.4'} | |
| 2878 | + | |
| 2879 | + safe-stable-stringify@2.5.0: | |
| 2880 | + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} | |
| 2881 | + engines: {node: '>=10'} | |
| 2882 | + | |
| 2883 | + safer-buffer@2.1.2: | |
| 2884 | + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} | |
| 2885 | + | |
| 2886 | + scheduler@0.27.0: | |
| 2887 | + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} | |
| 2888 | + | |
| 2889 | + semver@6.3.1: | |
| 2890 | + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} | |
| 2891 | + hasBin: true | |
| 2892 | + | |
| 2893 | + semver@7.8.5: | |
| 2894 | + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} | |
| 2895 | + engines: {node: '>=10'} | |
| 2896 | + hasBin: true | |
| 2897 | + | |
| 2898 | + server-only@0.0.1: | |
| 2899 | + resolution: {integrity: sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==} | |
| 2900 | + | |
| 2901 | + set-function-length@1.2.2: | |
| 2902 | + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} | |
| 2903 | + engines: {node: '>= 0.4'} | |
| 2904 | + | |
| 2905 | + set-function-name@2.0.2: | |
| 2906 | + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} | |
| 2907 | + engines: {node: '>= 0.4'} | |
| 2908 | + | |
| 2909 | + set-proto@1.0.0: | |
| 2910 | + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} | |
| 2911 | + engines: {node: '>= 0.4'} | |
| 2912 | + | |
| 2913 | + sharp@0.35.4: | |
| 2914 | + resolution: {integrity: sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA==} | |
| 2915 | + engines: {node: '>=20.9.0'} | |
| 2916 | + peerDependencies: | |
| 2917 | + '@types/node': '*' | |
| 2918 | + peerDependenciesMeta: | |
| 2919 | + '@types/node': | |
| 2920 | + optional: true | |
| 2921 | + | |
| 2922 | + shebang-command@2.0.0: | |
| 2923 | + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} | |
| 2924 | + engines: {node: '>=8'} | |
| 2925 | + | |
| 2926 | + shebang-regex@3.0.0: | |
| 2927 | + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} | |
| 2928 | + engines: {node: '>=8'} | |
| 2929 | + | |
| 2930 | + side-channel-list@1.0.1: | |
| 2931 | + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} | |
| 2932 | + engines: {node: '>= 0.4'} | |
| 2933 | + | |
| 2934 | + side-channel-map@1.0.1: | |
| 2935 | + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} | |
| 2936 | + engines: {node: '>= 0.4'} | |
| 2937 | + | |
| 2938 | + side-channel-weakmap@1.0.2: | |
| 2939 | + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} | |
| 2940 | + engines: {node: '>= 0.4'} | |
| 2941 | + | |
| 2942 | + side-channel@1.1.1: | |
| 2943 | + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} | |
| 2944 | + engines: {node: '>= 0.4'} | |
| 2945 | + | |
| 2946 | + siginfo@2.0.0: | |
| 2947 | + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} | |
| 2948 | + | |
| 2949 | + sonic-boom@4.2.1: | |
| 2950 | + resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} | |
| 2951 | + | |
| 2952 | + source-map-js@1.2.1: | |
| 2953 | + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} | |
| 2954 | + engines: {node: '>=0.10.0'} | |
| 2955 | + | |
| 2956 | + source-map-support@0.5.21: | |
| 2957 | + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} | |
| 2958 | + | |
| 2959 | + source-map@0.6.1: | |
| 2960 | + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} | |
| 2961 | + engines: {node: '>=0.10.0'} | |
| 2962 | + | |
| 2963 | + split2@4.2.0: | |
| 2964 | + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} | |
| 2965 | + engines: {node: '>= 10.x'} | |
| 2966 | + | |
| 2967 | + stable-hash@0.0.5: | |
| 2968 | + resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} | |
| 2969 | + | |
| 2970 | + stackback@0.0.2: | |
| 2971 | + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} | |
| 2972 | + | |
| 2973 | + std-env@3.10.0: | |
| 2974 | + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} | |
| 2975 | + | |
| 2976 | + stop-iteration-iterator@1.1.0: | |
| 2977 | + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} | |
| 2978 | + engines: {node: '>= 0.4'} | |
| 2979 | + | |
| 2980 | + string.prototype.includes@2.0.1: | |
| 2981 | + resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} | |
| 2982 | + engines: {node: '>= 0.4'} | |
| 2983 | + | |
| 2984 | + string.prototype.matchall@4.1.0: | |
| 2985 | + resolution: {integrity: sha512-tHNHTxInrYLCga9O9YGxWA3G9/nnzQw8UGAyqGx3Ar1pSTTzIuM4woFSq4SowkXCjJIwq5sIiQvEfRI9tCH1qQ==} | |
| 2986 | + engines: {node: '>= 0.4'} | |
| 2987 | + | |
| 2988 | + string.prototype.repeat@1.0.0: | |
| 2989 | + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} | |
| 2990 | + | |
| 2991 | + string.prototype.trim@1.2.11: | |
| 2992 | + resolution: {integrity: sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==} | |
| 2993 | + engines: {node: '>= 0.4'} | |
| 2994 | + | |
| 2995 | + string.prototype.trimend@1.0.10: | |
| 2996 | + resolution: {integrity: sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==} | |
| 2997 | + engines: {node: '>= 0.4'} | |
| 2998 | + | |
| 2999 | + string.prototype.trimstart@1.0.8: | |
| 3000 | + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} | |
| 3001 | + engines: {node: '>= 0.4'} | |
| 3002 | + | |
| 3003 | + strip-bom@3.0.0: | |
| 3004 | + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} | |
| 3005 | + engines: {node: '>=4'} | |
| 3006 | + | |
| 3007 | + strip-json-comments@3.1.1: | |
| 3008 | + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} | |
| 3009 | + engines: {node: '>=8'} | |
| 3010 | + | |
| 3011 | + strip-literal@3.1.0: | |
| 3012 | + resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} | |
| 3013 | + | |
| 3014 | + styled-jsx@5.1.6: | |
| 3015 | + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} | |
| 3016 | + engines: {node: '>= 12.0.0'} | |
| 3017 | + peerDependencies: | |
| 3018 | + '@babel/core': '*' | |
| 3019 | + babel-plugin-macros: '*' | |
| 3020 | + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' | |
| 3021 | + peerDependenciesMeta: | |
| 3022 | + '@babel/core': | |
| 3023 | + optional: true | |
| 3024 | + babel-plugin-macros: | |
| 3025 | + optional: true | |
| 3026 | + | |
| 3027 | + supports-color@7.2.0: | |
| 3028 | + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} | |
| 3029 | + engines: {node: '>=8'} | |
| 3030 | + | |
| 3031 | + supports-preserve-symlinks-flag@1.0.0: | |
| 3032 | + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} | |
| 3033 | + engines: {node: '>= 0.4'} | |
| 3034 | + | |
| 3035 | + tailwindcss@4.3.3: | |
| 3036 | + resolution: {integrity: sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==} | |
| 3037 | + | |
| 3038 | + tapable@2.3.3: | |
| 3039 | + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} | |
| 3040 | + engines: {node: '>=6'} | |
| 3041 | + | |
| 3042 | + thread-stream@3.2.0: | |
| 3043 | + resolution: {integrity: sha512-zLBvqpwr4Esa0kRjcrzGU6zL25lePWaCLMx0RQFrmteozIfeNdaMLpG5U7PeHzvlFkAWaRKA9/KVW4F60iB+qw==} | |
| 3044 | + | |
| 3045 | + tinybench@2.9.0: | |
| 3046 | + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} | |
| 3047 | + | |
| 3048 | + tinyexec@0.3.2: | |
| 3049 | + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} | |
| 3050 | + | |
| 3051 | + tinyglobby@0.2.17: | |
| 3052 | + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} | |
| 3053 | + engines: {node: '>=12.0.0'} | |
| 3054 | + | |
| 3055 | + tinypool@1.1.1: | |
| 3056 | + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} | |
| 3057 | + engines: {node: ^18.0.0 || >=20.0.0} | |
| 3058 | + | |
| 3059 | + tinyrainbow@2.0.0: | |
| 3060 | + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} | |
| 3061 | + engines: {node: '>=14.0.0'} | |
| 3062 | + | |
| 3063 | + tinyspy@4.0.6: | |
| 3064 | + resolution: {integrity: sha512-u8KszXvGfU68hVcZpRHKG28T0krMuv2G5nDhiHaMLen/gIuFEgIJhaJuO69qjnXg5paSrbPMFfx3brNuN8eVSg==} | |
| 3065 | + engines: {node: '>=14.0.0'} | |
| 3066 | + | |
| 3067 | + to-regex-range@5.0.1: | |
| 3068 | + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} | |
| 3069 | + engines: {node: '>=8.0'} | |
| 3070 | + | |
| 3071 | + ts-api-utils@2.5.0: | |
| 3072 | + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} | |
| 3073 | + engines: {node: '>=18.12'} | |
| 3074 | + peerDependencies: | |
| 3075 | + typescript: '>=4.8.4' | |
| 3076 | + | |
| 3077 | + tsconfig-paths@3.15.0: | |
| 3078 | + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} | |
| 3079 | + | |
| 3080 | + tslib@2.8.1: | |
| 3081 | + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} | |
| 3082 | + | |
| 3083 | + tsx@4.23.13: | |
| 3084 | + resolution: {integrity: sha512-BL5MGkRln6aDYhb0xbQlEAGw743BaZYWdbWtdJOBriYJboKgUUYCadFp2/FpBBZquBC/ezNBn7wMMPx7FDZUDw==} | |
| 3085 | + engines: {node: '>=18.0.0'} | |
| 3086 | + hasBin: true | |
| 3087 | + | |
| 3088 | + type-check@0.4.0: | |
| 3089 | + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} | |
| 3090 | + engines: {node: '>= 0.8.0'} | |
| 3091 | + | |
| 3092 | + typed-array-buffer@1.0.3: | |
| 3093 | + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} | |
| 3094 | + engines: {node: '>= 0.4'} | |
| 3095 | + | |
| 3096 | + typed-array-byte-length@1.0.3: | |
| 3097 | + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} | |
| 3098 | + engines: {node: '>= 0.4'} | |
| 3099 | + | |
| 3100 | + typed-array-byte-offset@1.0.4: | |
| 3101 | + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} | |
| 3102 | + engines: {node: '>= 0.4'} | |
| 3103 | + | |
| 3104 | + typed-array-length@1.0.8: | |
| 3105 | + resolution: {integrity: sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==} | |
| 3106 | + engines: {node: '>= 0.4'} | |
| 3107 | + | |
| 3108 | + typescript-eslint@8.69.0: | |
| 3109 | + resolution: {integrity: sha512-B3MltX0VqjUBNEe3b3sSuiRbfa6XrfHFtBiPamjT5AsW/dfq+y+bc0wyuS9DxAS1LyzCxRp2+rxzpLUvqM2BvA==} | |
| 3110 | + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} | |
| 3111 | + peerDependencies: | |
| 3112 | + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 | |
| 3113 | + typescript: '>=4.8.4 <6.1.0' | |
| 3114 | + | |
| 3115 | + typescript@5.9.3: | |
| 3116 | + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} | |
| 3117 | + engines: {node: '>=14.17'} | |
| 3118 | + hasBin: true | |
| 3119 | + | |
| 3120 | + unbox-primitive@1.1.0: | |
| 3121 | + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} | |
| 3122 | + engines: {node: '>= 0.4'} | |
| 3123 | + | |
| 3124 | + undici-types@7.18.2: | |
| 3125 | + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} | |
| 3126 | + | |
| 3127 | + undici@7.29.1: | |
| 3128 | + resolution: {integrity: sha512-RYONW2MeafgYlkVOKYKkA/Ag7BmXqgIWCa8t1m0JcxrQg9pI9lEqRhAOruOBCbAohOa/gkCF+iPi9hrgvTzu6Q==} | |
| 3129 | + engines: {node: '>=20.18.1'} | |
| 3130 | + | |
| 3131 | + unrs-resolver@1.12.2: | |
| 3132 | + resolution: {integrity: sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==} | |
| 3133 | + | |
| 3134 | + update-browserslist-db@1.3.2: | |
| 3135 | + resolution: {integrity: sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==} | |
| 3136 | + hasBin: true | |
| 3137 | + peerDependencies: | |
| 3138 | + browserslist: '>= 4.21.0' | |
| 3139 | + | |
| 3140 | + uri-js@4.4.1: | |
| 3141 | + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} | |
| 3142 | + | |
| 3143 | + vite-node@3.2.4: | |
| 3144 | + resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} | |
| 3145 | + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} | |
| 3146 | + hasBin: true | |
| 3147 | + | |
| 3148 | + vite@7.3.6: | |
| 3149 | + resolution: {integrity: sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==} | |
| 3150 | + engines: {node: ^20.19.0 || >=22.12.0} | |
| 3151 | + hasBin: true | |
| 3152 | + peerDependencies: | |
| 3153 | + '@types/node': ^20.19.0 || >=22.12.0 | |
| 3154 | + jiti: '>=1.21.0' | |
| 3155 | + less: ^4.0.0 | |
| 3156 | + lightningcss: ^1.21.0 | |
| 3157 | + sass: ^1.70.0 | |
| 3158 | + sass-embedded: ^1.70.0 | |
| 3159 | + stylus: '>=0.54.8' | |
| 3160 | + sugarss: ^5.0.0 | |
| 3161 | + terser: ^5.16.0 | |
| 3162 | + tsx: ^4.8.1 | |
| 3163 | + yaml: ^2.4.2 | |
| 3164 | + peerDependenciesMeta: | |
| 3165 | + '@types/node': | |
| 3166 | + optional: true | |
| 3167 | + jiti: | |
| 3168 | + optional: true | |
| 3169 | + less: | |
| 3170 | + optional: true | |
| 3171 | + lightningcss: | |
| 3172 | + optional: true | |
| 3173 | + sass: | |
| 3174 | + optional: true | |
| 3175 | + sass-embedded: | |
| 3176 | + optional: true | |
| 3177 | + stylus: | |
| 3178 | + optional: true | |
| 3179 | + sugarss: | |
| 3180 | + optional: true | |
| 3181 | + terser: | |
| 3182 | + optional: true | |
| 3183 | + tsx: | |
| 3184 | + optional: true | |
| 3185 | + yaml: | |
| 3186 | + optional: true | |
| 3187 | + | |
| 3188 | + vitest@3.2.7: | |
| 3189 | + resolution: {integrity: sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==} | |
| 3190 | + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} | |
| 3191 | + hasBin: true | |
| 3192 | + peerDependencies: | |
| 3193 | + '@edge-runtime/vm': '*' | |
| 3194 | + '@types/debug': ^4.1.12 | |
| 3195 | + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 | |
| 3196 | + '@vitest/browser': 3.2.7 | |
| 3197 | + '@vitest/ui': 3.2.7 | |
| 3198 | + happy-dom: '*' | |
| 3199 | + jsdom: '*' | |
| 3200 | + peerDependenciesMeta: | |
| 3201 | + '@edge-runtime/vm': | |
| 3202 | + optional: true | |
| 3203 | + '@types/debug': | |
| 3204 | + optional: true | |
| 3205 | + '@types/node': | |
| 3206 | + optional: true | |
| 3207 | + '@vitest/browser': | |
| 3208 | + optional: true | |
| 3209 | + '@vitest/ui': | |
| 3210 | + optional: true | |
| 3211 | + happy-dom: | |
| 3212 | + optional: true | |
| 3213 | + jsdom: | |
| 3214 | + optional: true | |
| 3215 | + | |
| 3216 | + whatwg-encoding@3.1.1: | |
| 3217 | + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} | |
| 3218 | + engines: {node: '>=18'} | |
| 3219 | + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation | |
| 3220 | + | |
| 3221 | + whatwg-mimetype@4.0.0: | |
| 3222 | + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} | |
| 3223 | + engines: {node: '>=18'} | |
| 3224 | + | |
| 3225 | + which-boxed-primitive@1.1.1: | |
| 3226 | + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} | |
| 3227 | + engines: {node: '>= 0.4'} | |
| 3228 | + | |
| 3229 | + which-builtin-type@1.2.1: | |
| 3230 | + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} | |
| 3231 | + engines: {node: '>= 0.4'} | |
| 3232 | + | |
| 3233 | + which-collection@1.0.2: | |
| 3234 | + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} | |
| 3235 | + engines: {node: '>= 0.4'} | |
| 3236 | + | |
| 3237 | + which-typed-array@1.1.22: | |
| 3238 | + resolution: {integrity: sha512-fvO4ExWMFsqyhG3AiPAObMuY1lxaqgYcxbc49CNdWDDECOJNgQyvsOWVwbZc+qf3rzRtxojBK+CMEv0Ld5CYpw==} | |
| 3239 | + engines: {node: '>= 0.4'} | |
| 3240 | + | |
| 3241 | + which@2.0.2: | |
| 3242 | + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} | |
| 3243 | + engines: {node: '>= 8'} | |
| 3244 | + hasBin: true | |
| 3245 | + | |
| 3246 | + why-is-node-running@2.3.0: | |
| 3247 | + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} | |
| 3248 | + engines: {node: '>=8'} | |
| 3249 | + hasBin: true | |
| 3250 | + | |
| 3251 | + word-wrap@1.2.5: | |
| 3252 | + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} | |
| 3253 | + engines: {node: '>=0.10.0'} | |
| 3254 | + | |
| 3255 | + yallist@3.1.1: | |
| 3256 | + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} | |
| 3257 | + | |
| 3258 | + yocto-queue@0.1.0: | |
| 3259 | + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} | |
| 3260 | + engines: {node: '>=10'} | |
| 3261 | + | |
| 3262 | + zod-validation-error@4.0.2: | |
| 3263 | + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} | |
| 3264 | + engines: {node: '>=18.0.0'} | |
| 3265 | + peerDependencies: | |
| 3266 | + zod: ^3.25.0 || ^4.0.0 | |
| 3267 | + | |
| 3268 | + zod@4.5.4: | |
| 3269 | + resolution: {integrity: sha512-sC95tT5iHHH9gtpj6A81kh+NEaRAUFN+qlUPDUbRfOMvNf5QCBqsb3WgvnpVtK5Y+4UfA6KqufotuTvMGiTlsA==} | |
| 3270 | + | |
| 3271 | +snapshots: | |
| 3272 | + | |
| 3273 | + '@alloc/quick-lru@5.3.0': {} | |
| 3274 | + | |
| 3275 | + '@babel/code-frame@7.29.7': | |
| 3276 | + dependencies: | |
| 3277 | + '@babel/helper-validator-identifier': 7.29.7 | |
| 3278 | + js-tokens: 4.0.0 | |
| 3279 | + picocolors: 1.1.1 | |
| 3280 | + | |
| 3281 | + '@babel/compat-data@7.29.7': {} | |
| 3282 | + | |
| 3283 | + '@babel/core@7.29.7': | |
| 3284 | + dependencies: | |
| 3285 | + '@babel/code-frame': 7.29.7 | |
| 3286 | + '@babel/generator': 7.29.8 | |
| 3287 | + '@babel/helper-compilation-targets': 7.29.7 | |
| 3288 | + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) | |
| 3289 | + '@babel/helpers': 7.29.7 | |
| 3290 | + '@babel/parser': 7.29.8 | |
| 3291 | + '@babel/template': 7.29.7 | |
| 3292 | + '@babel/traverse': 7.29.8 | |
| 3293 | + '@babel/types': 7.29.8 | |
| 3294 | + '@jridgewell/remapping': 2.3.5 | |
| 3295 | + convert-source-map: 2.0.0 | |
| 3296 | + debug: 4.4.3 | |
| 3297 | + gensync: 1.0.0-beta.2 | |
| 3298 | + json5: 2.2.3 | |
| 3299 | + semver: 6.3.1 | |
| 3300 | + transitivePeerDependencies: | |
| 3301 | + - supports-color | |
| 3302 | + | |
| 3303 | + '@babel/generator@7.29.8': | |
| 3304 | + dependencies: | |
| 3305 | + '@babel/parser': 7.29.8 | |
| 3306 | + '@babel/types': 7.29.8 | |
| 3307 | + '@jridgewell/gen-mapping': 0.3.13 | |
| 3308 | + '@jridgewell/trace-mapping': 0.3.31 | |
| 3309 | + jsesc: 3.1.0 | |
| 3310 | + | |
| 3311 | + '@babel/helper-compilation-targets@7.29.7': | |
| 3312 | + dependencies: | |
| 3313 | + '@babel/compat-data': 7.29.7 | |
| 3314 | + '@babel/helper-validator-option': 7.29.7 | |
| 3315 | + browserslist: 4.28.9 | |
| 3316 | + lru-cache: 5.1.1 | |
| 3317 | + semver: 6.3.1 | |
| 3318 | + | |
| 3319 | + '@babel/helper-globals@7.29.7': {} | |
| 3320 | + | |
| 3321 | + '@babel/helper-module-imports@7.29.7': | |
| 3322 | + dependencies: | |
| 3323 | + '@babel/traverse': 7.29.8 | |
| 3324 | + '@babel/types': 7.29.8 | |
| 3325 | + transitivePeerDependencies: | |
| 3326 | + - supports-color | |
| 3327 | + | |
| 3328 | + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': | |
| 3329 | + dependencies: | |
| 3330 | + '@babel/core': 7.29.7 | |
| 3331 | + '@babel/helper-module-imports': 7.29.7 | |
| 3332 | + '@babel/helper-validator-identifier': 7.29.7 | |
| 3333 | + '@babel/traverse': 7.29.8 | |
| 3334 | + transitivePeerDependencies: | |
| 3335 | + - supports-color | |
| 3336 | + | |
| 3337 | + '@babel/helper-string-parser@7.29.7': {} | |
| 3338 | + | |
| 3339 | + '@babel/helper-validator-identifier@7.29.7': {} | |
| 3340 | + | |
| 3341 | + '@babel/helper-validator-option@7.29.7': {} | |
| 3342 | + | |
| 3343 | + '@babel/helpers@7.29.7': | |
| 3344 | + dependencies: | |
| 3345 | + '@babel/template': 7.29.7 | |
| 3346 | + '@babel/types': 7.29.8 | |
| 3347 | + | |
| 3348 | + '@babel/parser@7.29.8': | |
| 3349 | + dependencies: | |
| 3350 | + '@babel/types': 7.29.8 | |
| 3351 | + | |
| 3352 | + '@babel/template@7.29.7': | |
| 3353 | + dependencies: | |
| 3354 | + '@babel/code-frame': 7.29.7 | |
| 3355 | + '@babel/parser': 7.29.8 | |
| 3356 | + '@babel/types': 7.29.8 | |
| 3357 | + | |
| 3358 | + '@babel/traverse@7.29.8': | |
| 3359 | + dependencies: | |
| 3360 | + '@babel/code-frame': 7.29.7 | |
| 3361 | + '@babel/generator': 7.29.8 | |
| 3362 | + '@babel/helper-globals': 7.29.7 | |
| 3363 | + '@babel/parser': 7.29.8 | |
| 3364 | + '@babel/template': 7.29.7 | |
| 3365 | + '@babel/types': 7.29.8 | |
| 3366 | + debug: 4.4.3 | |
| 3367 | + transitivePeerDependencies: | |
| 3368 | + - supports-color | |
| 3369 | + | |
| 3370 | + '@babel/types@7.29.8': | |
| 3371 | + dependencies: | |
| 3372 | + '@babel/helper-string-parser': 7.29.7 | |
| 3373 | + '@babel/helper-validator-identifier': 7.29.7 | |
| 3374 | + | |
| 3375 | + '@drizzle-team/brocli@0.10.2': {} | |
| 3376 | + | |
| 3377 | + '@emnapi/core@1.10.0': | |
| 3378 | + dependencies: | |
| 3379 | + '@emnapi/wasi-threads': 1.2.1 | |
| 3380 | + tslib: 2.8.1 | |
| 3381 | + optional: true | |
| 3382 | + | |
| 3383 | + '@emnapi/runtime@1.10.0': | |
| 3384 | + dependencies: | |
| 3385 | + tslib: 2.8.1 | |
| 3386 | + optional: true | |
| 3387 | + | |
| 3388 | + '@emnapi/runtime@1.11.3': | |
| 3389 | + dependencies: | |
| 3390 | + tslib: 2.8.1 | |
| 3391 | + optional: true | |
| 3392 | + | |
| 3393 | + '@emnapi/wasi-threads@1.2.1': | |
| 3394 | + dependencies: | |
| 3395 | + tslib: 2.8.1 | |
| 3396 | + optional: true | |
| 3397 | + | |
| 3398 | + '@esbuild-kit/core-utils@3.3.2': | |
| 3399 | + dependencies: | |
| 3400 | + esbuild: 0.18.20 | |
| 3401 | + source-map-support: 0.5.21 | |
| 3402 | + | |
| 3403 | + '@esbuild-kit/esm-loader@2.6.5': | |
| 3404 | + dependencies: | |
| 3405 | + '@esbuild-kit/core-utils': 3.3.2 | |
| 3406 | + get-tsconfig: 4.14.3 | |
| 3407 | + | |
| 3408 | + '@esbuild/aix-ppc64@0.25.12': | |
| 3409 | + optional: true | |
| 3410 | + | |
| 3411 | + '@esbuild/aix-ppc64@0.28.2': | |
| 3412 | + optional: true | |
| 3413 | + | |
| 3414 | + '@esbuild/android-arm64@0.18.20': | |
| 3415 | + optional: true | |
| 3416 | + | |
| 3417 | + '@esbuild/android-arm64@0.25.12': | |
| 3418 | + optional: true | |
| 3419 | + | |
| 3420 | + '@esbuild/android-arm64@0.28.2': | |
| 3421 | + optional: true | |
| 3422 | + | |
| 3423 | + '@esbuild/android-arm@0.18.20': | |
| 3424 | + optional: true | |
| 3425 | + | |
| 3426 | + '@esbuild/android-arm@0.25.12': | |
| 3427 | + optional: true | |
| 3428 | + | |
| 3429 | + '@esbuild/android-arm@0.28.2': | |
| 3430 | + optional: true | |
| 3431 | + | |
| 3432 | + '@esbuild/android-x64@0.18.20': | |
| 3433 | + optional: true | |
| 3434 | + | |
| 3435 | + '@esbuild/android-x64@0.25.12': | |
| 3436 | + optional: true | |
| 3437 | + | |
| 3438 | + '@esbuild/android-x64@0.28.2': | |
| 3439 | + optional: true | |
| 3440 | + | |
| 3441 | + '@esbuild/darwin-arm64@0.18.20': | |
| 3442 | + optional: true | |
| 3443 | + | |
| 3444 | + '@esbuild/darwin-arm64@0.25.12': | |
| 3445 | + optional: true | |
| 3446 | + | |
| 3447 | + '@esbuild/darwin-arm64@0.28.2': | |
| 3448 | + optional: true | |
| 3449 | + | |
| 3450 | + '@esbuild/darwin-x64@0.18.20': | |
| 3451 | + optional: true | |
| 3452 | + | |
| 3453 | + '@esbuild/darwin-x64@0.25.12': | |
| 3454 | + optional: true | |
| 3455 | + | |
| 3456 | + '@esbuild/darwin-x64@0.28.2': | |
| 3457 | + optional: true | |
| 3458 | + | |
| 3459 | + '@esbuild/freebsd-arm64@0.18.20': | |
| 3460 | + optional: true | |
| 3461 | + | |
| 3462 | + '@esbuild/freebsd-arm64@0.25.12': | |
| 3463 | + optional: true | |
| 3464 | + | |
| 3465 | + '@esbuild/freebsd-arm64@0.28.2': | |
| 3466 | + optional: true | |
| 3467 | + | |
| 3468 | + '@esbuild/freebsd-x64@0.18.20': | |
| 3469 | + optional: true | |
| 3470 | + | |
| 3471 | + '@esbuild/freebsd-x64@0.25.12': | |
| 3472 | + optional: true | |
| 3473 | + | |
| 3474 | + '@esbuild/freebsd-x64@0.28.2': | |
| 3475 | + optional: true | |
| 3476 | + | |
| 3477 | + '@esbuild/linux-arm64@0.18.20': | |
| 3478 | + optional: true | |
| 3479 | + | |
| 3480 | + '@esbuild/linux-arm64@0.25.12': | |
| 3481 | + optional: true | |
| 3482 | + | |
| 3483 | + '@esbuild/linux-arm64@0.28.2': | |
| 3484 | + optional: true | |
| 3485 | + | |
| 3486 | + '@esbuild/linux-arm@0.18.20': | |
| 3487 | + optional: true | |
| 3488 | + | |
| 3489 | + '@esbuild/linux-arm@0.25.12': | |
| 3490 | + optional: true | |
| 3491 | + | |
| 3492 | + '@esbuild/linux-arm@0.28.2': | |
| 3493 | + optional: true | |
| 3494 | + | |
| 3495 | + '@esbuild/linux-ia32@0.18.20': | |
| 3496 | + optional: true | |
| 3497 | + | |
| 3498 | + '@esbuild/linux-ia32@0.25.12': | |
| 3499 | + optional: true | |
| 3500 | + | |
| 3501 | + '@esbuild/linux-ia32@0.28.2': | |
| 3502 | + optional: true | |
| 3503 | + | |
| 3504 | + '@esbuild/linux-loong64@0.18.20': | |
| 3505 | + optional: true | |
| 3506 | + | |
| 3507 | + '@esbuild/linux-loong64@0.25.12': | |
| 3508 | + optional: true | |
| 3509 | + | |
| 3510 | + '@esbuild/linux-loong64@0.28.2': | |
| 3511 | + optional: true | |
| 3512 | + | |
| 3513 | + '@esbuild/linux-mips64el@0.18.20': | |
| 3514 | + optional: true | |
| 3515 | + | |
| 3516 | + '@esbuild/linux-mips64el@0.25.12': | |
| 3517 | + optional: true | |
| 3518 | + | |
| 3519 | + '@esbuild/linux-mips64el@0.28.2': | |
| 3520 | + optional: true | |
| 3521 | + | |
| 3522 | + '@esbuild/linux-ppc64@0.18.20': | |
| 3523 | + optional: true | |
| 3524 | + | |
| 3525 | + '@esbuild/linux-ppc64@0.25.12': | |
| 3526 | + optional: true | |
| 3527 | + | |
| 3528 | + '@esbuild/linux-ppc64@0.28.2': | |
| 3529 | + optional: true | |
| 3530 | + | |
| 3531 | + '@esbuild/linux-riscv64@0.18.20': | |
| 3532 | + optional: true | |
| 3533 | + | |
| 3534 | + '@esbuild/linux-riscv64@0.25.12': | |
| 3535 | + optional: true | |
| 3536 | + | |
| 3537 | + '@esbuild/linux-riscv64@0.28.2': | |
| 3538 | + optional: true | |
| 3539 | + | |
| 3540 | + '@esbuild/linux-s390x@0.18.20': | |
| 3541 | + optional: true | |
| 3542 | + | |
| 3543 | + '@esbuild/linux-s390x@0.25.12': | |
| 3544 | + optional: true | |
| 3545 | + | |
| 3546 | + '@esbuild/linux-s390x@0.28.2': | |
| 3547 | + optional: true | |
| 3548 | + | |
| 3549 | + '@esbuild/linux-x64@0.18.20': | |
| 3550 | + optional: true | |
| 3551 | + | |
| 3552 | + '@esbuild/linux-x64@0.25.12': | |
| 3553 | + optional: true | |
| 3554 | + | |
| 3555 | + '@esbuild/linux-x64@0.28.2': | |
| 3556 | + optional: true | |
| 3557 | + | |
| 3558 | + '@esbuild/netbsd-arm64@0.25.12': | |
| 3559 | + optional: true | |
| 3560 | + | |
| 3561 | + '@esbuild/netbsd-arm64@0.28.2': | |
| 3562 | + optional: true | |
| 3563 | + | |
| 3564 | + '@esbuild/netbsd-x64@0.18.20': | |
| 3565 | + optional: true | |
| 3566 | + | |
| 3567 | + '@esbuild/netbsd-x64@0.25.12': | |
| 3568 | + optional: true | |
| 3569 | + | |
| 3570 | + '@esbuild/netbsd-x64@0.28.2': | |
| 3571 | + optional: true | |
| 3572 | + | |
| 3573 | + '@esbuild/openbsd-arm64@0.25.12': | |
| 3574 | + optional: true | |
| 3575 | + | |
| 3576 | + '@esbuild/openbsd-arm64@0.28.2': | |
| 3577 | + optional: true | |
| 3578 | + | |
| 3579 | + '@esbuild/openbsd-x64@0.18.20': | |
| 3580 | + optional: true | |
| 3581 | + | |
| 3582 | + '@esbuild/openbsd-x64@0.25.12': | |
| 3583 | + optional: true | |
| 3584 | + | |
| 3585 | + '@esbuild/openbsd-x64@0.28.2': | |
| 3586 | + optional: true | |
| 3587 | + | |
| 3588 | + '@esbuild/openharmony-arm64@0.25.12': | |
| 3589 | + optional: true | |
| 3590 | + | |
| 3591 | + '@esbuild/openharmony-arm64@0.28.2': | |
| 3592 | + optional: true | |
| 3593 | + | |
| 3594 | + '@esbuild/sunos-x64@0.18.20': | |
| 3595 | + optional: true | |
| 3596 | + | |
| 3597 | + '@esbuild/sunos-x64@0.25.12': | |
| 3598 | + optional: true | |
| 3599 | + | |
| 3600 | + '@esbuild/sunos-x64@0.28.2': | |
| 3601 | + optional: true | |
| 3602 | + | |
| 3603 | + '@esbuild/win32-arm64@0.18.20': | |
| 3604 | + optional: true | |
| 3605 | + | |
| 3606 | + '@esbuild/win32-arm64@0.25.12': | |
| 3607 | + optional: true | |
| 3608 | + | |
| 3609 | + '@esbuild/win32-arm64@0.28.2': | |
| 3610 | + optional: true | |
| 3611 | + | |
| 3612 | + '@esbuild/win32-ia32@0.18.20': | |
| 3613 | + optional: true | |
| 3614 | + | |
| 3615 | + '@esbuild/win32-ia32@0.25.12': | |
| 3616 | + optional: true | |
| 3617 | + | |
| 3618 | + '@esbuild/win32-ia32@0.28.2': | |
| 3619 | + optional: true | |
| 3620 | + | |
| 3621 | + '@esbuild/win32-x64@0.18.20': | |
| 3622 | + optional: true | |
| 3623 | + | |
| 3624 | + '@esbuild/win32-x64@0.25.12': | |
| 3625 | + optional: true | |
| 3626 | + | |
| 3627 | + '@esbuild/win32-x64@0.28.2': | |
| 3628 | + optional: true | |
| 3629 | + | |
| 3630 | + '@eslint-community/eslint-utils@4.10.1(eslint@9.39.5(jiti@2.7.0))': | |
| 3631 | + dependencies: | |
| 3632 | + eslint: 9.39.5(jiti@2.7.0) | |
| 3633 | + eslint-visitor-keys: 3.4.3 | |
| 3634 | + | |
| 3635 | + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.5(jiti@2.7.0))': | |
| 3636 | + dependencies: | |
| 3637 | + eslint: 9.39.5(jiti@2.7.0) | |
| 3638 | + eslint-visitor-keys: 3.4.3 | |
| 3639 | + | |
| 3640 | + '@eslint-community/regexpp@4.12.2': {} | |
| 3641 | + | |
| 3642 | + '@eslint/config-array@0.21.2': | |
| 3643 | + dependencies: | |
| 3644 | + '@eslint/object-schema': 2.1.7 | |
| 3645 | + debug: 4.4.3 | |
| 3646 | + minimatch: 3.1.5 | |
| 3647 | + transitivePeerDependencies: | |
| 3648 | + - supports-color | |
| 3649 | + | |
| 3650 | + '@eslint/config-helpers@0.4.2': | |
| 3651 | + dependencies: | |
| 3652 | + '@eslint/core': 0.17.0 | |
| 3653 | + | |
| 3654 | + '@eslint/core@0.17.0': | |
| 3655 | + dependencies: | |
| 3656 | + '@types/json-schema': 7.0.15 | |
| 3657 | + | |
| 3658 | + '@eslint/eslintrc@3.3.7': | |
| 3659 | + dependencies: | |
| 3660 | + ajv: 6.15.0 | |
| 3661 | + debug: 4.4.3 | |
| 3662 | + espree: 10.4.0 | |
| 3663 | + globals: 14.0.0 | |
| 3664 | + ignore: 5.3.2 | |
| 3665 | + import-fresh: 3.3.1 | |
| 3666 | + js-yaml: 4.3.2 | |
| 3667 | + minimatch: 3.1.5 | |
| 3668 | + strip-json-comments: 3.1.1 | |
| 3669 | + transitivePeerDependencies: | |
| 3670 | + - supports-color | |
| 3671 | + | |
| 3672 | + '@eslint/js@9.39.5': {} | |
| 3673 | + | |
| 3674 | + '@eslint/object-schema@2.1.7': {} | |
| 3675 | + | |
| 3676 | + '@eslint/plugin-kit@0.4.1': | |
| 3677 | + dependencies: | |
| 3678 | + '@eslint/core': 0.17.0 | |
| 3679 | + levn: 0.4.1 | |
| 3680 | + | |
| 3681 | + '@humanfs/core@0.19.2': | |
| 3682 | + dependencies: | |
| 3683 | + '@humanfs/types': 0.15.0 | |
| 3684 | + | |
| 3685 | + '@humanfs/node@0.16.8': | |
| 3686 | + dependencies: | |
| 3687 | + '@humanfs/core': 0.19.2 | |
| 3688 | + '@humanfs/types': 0.15.0 | |
| 3689 | + '@humanwhocodes/retry': 0.4.3 | |
| 3690 | + | |
| 3691 | + '@humanfs/types@0.15.0': {} | |
| 3692 | + | |
| 3693 | + '@humanwhocodes/module-importer@1.0.1': {} | |
| 3694 | + | |
| 3695 | + '@humanwhocodes/retry@0.4.3': {} | |
| 3696 | + | |
| 3697 | + '@img/colour@1.1.0': | |
| 3698 | + optional: true | |
| 3699 | + | |
| 3700 | + '@img/sharp-darwin-arm64@0.35.4': | |
| 3701 | + optionalDependencies: | |
| 3702 | + '@img/sharp-libvips-darwin-arm64': 1.3.3 | |
| 3703 | + optional: true | |
| 3704 | + | |
| 3705 | + '@img/sharp-darwin-x64@0.35.4': | |
| 3706 | + optionalDependencies: | |
| 3707 | + '@img/sharp-libvips-darwin-x64': 1.3.3 | |
| 3708 | + optional: true | |
| 3709 | + | |
| 3710 | + '@img/sharp-freebsd-wasm32@0.35.4': | |
| 3711 | + dependencies: | |
| 3712 | + '@img/sharp-wasm32': 0.35.4 | |
| 3713 | + optional: true | |
| 3714 | + | |
| 3715 | + '@img/sharp-libvips-darwin-arm64@1.3.3': | |
| 3716 | + optional: true | |
| 3717 | + | |
| 3718 | + '@img/sharp-libvips-darwin-x64@1.3.3': | |
| 3719 | + optional: true | |
| 3720 | + | |
| 3721 | + '@img/sharp-libvips-linux-arm64@1.3.3': | |
| 3722 | + optional: true | |
| 3723 | + | |
| 3724 | + '@img/sharp-libvips-linux-arm@1.3.3': | |
| 3725 | + optional: true | |
| 3726 | + | |
| 3727 | + '@img/sharp-libvips-linux-ppc64@1.3.3': | |
| 3728 | + optional: true | |
| 3729 | + | |
| 3730 | + '@img/sharp-libvips-linux-riscv64@1.3.3': | |
| 3731 | + optional: true | |
| 3732 | + | |
| 3733 | + '@img/sharp-libvips-linux-s390x@1.3.3': | |
| 3734 | + optional: true | |
| 3735 | + | |
| 3736 | + '@img/sharp-libvips-linux-x64@1.3.3': | |
| 3737 | + optional: true | |
| 3738 | + | |
| 3739 | + '@img/sharp-libvips-linuxmusl-arm64@1.3.3': | |
| 3740 | + optional: true | |
| 3741 | + | |
| 3742 | + '@img/sharp-libvips-linuxmusl-x64@1.3.3': | |
| 3743 | + optional: true | |
| 3744 | + | |
| 3745 | + '@img/sharp-linux-arm64@0.35.4': | |
| 3746 | + optionalDependencies: | |
| 3747 | + '@img/sharp-libvips-linux-arm64': 1.3.3 | |
| 3748 | + optional: true | |
| 3749 | + | |
| 3750 | + '@img/sharp-linux-arm@0.35.4': | |
| 3751 | + optionalDependencies: | |
| 3752 | + '@img/sharp-libvips-linux-arm': 1.3.3 | |
| 3753 | + optional: true | |
| 3754 | + | |
| 3755 | + '@img/sharp-linux-ppc64@0.35.4': | |
| 3756 | + optionalDependencies: | |
| 3757 | + '@img/sharp-libvips-linux-ppc64': 1.3.3 | |
| 3758 | + optional: true | |
| 3759 | + | |
| 3760 | + '@img/sharp-linux-riscv64@0.35.4': | |
| 3761 | + optionalDependencies: | |
| 3762 | + '@img/sharp-libvips-linux-riscv64': 1.3.3 | |
| 3763 | + optional: true | |
| 3764 | + | |
| 3765 | + '@img/sharp-linux-s390x@0.35.4': | |
| 3766 | + optionalDependencies: | |
| 3767 | + '@img/sharp-libvips-linux-s390x': 1.3.3 | |
| 3768 | + optional: true | |
| 3769 | + | |
| 3770 | + '@img/sharp-linux-x64@0.35.4': | |
| 3771 | + optionalDependencies: | |
| 3772 | + '@img/sharp-libvips-linux-x64': 1.3.3 | |
| 3773 | + optional: true | |
| 3774 | + | |
| 3775 | + '@img/sharp-linuxmusl-arm64@0.35.4': | |
| 3776 | + optionalDependencies: | |
| 3777 | + '@img/sharp-libvips-linuxmusl-arm64': 1.3.3 | |
| 3778 | + optional: true | |
| 3779 | + | |
| 3780 | + '@img/sharp-linuxmusl-x64@0.35.4': | |
| 3781 | + optionalDependencies: | |
| 3782 | + '@img/sharp-libvips-linuxmusl-x64': 1.3.3 | |
| 3783 | + optional: true | |
| 3784 | + | |
| 3785 | + '@img/sharp-wasm32@0.35.4': | |
| 3786 | + dependencies: | |
| 3787 | + '@emnapi/runtime': 1.11.3 | |
| 3788 | + optional: true | |
| 3789 | + | |
| 3790 | + '@img/sharp-webcontainers-wasm32@0.35.4': | |
| 3791 | + dependencies: | |
| 3792 | + '@img/sharp-wasm32': 0.35.4 | |
| 3793 | + optional: true | |
| 3794 | + | |
| 3795 | + '@img/sharp-win32-arm64@0.35.4': | |
| 3796 | + optional: true | |
| 3797 | + | |
| 3798 | + '@img/sharp-win32-ia32@0.35.4': | |
| 3799 | + optional: true | |
| 3800 | + | |
| 3801 | + '@img/sharp-win32-x64@0.35.4': | |
| 3802 | + optional: true | |
| 3803 | + | |
| 3804 | + '@jridgewell/gen-mapping@0.3.13': | |
| 3805 | + dependencies: | |
| 3806 | + '@jridgewell/sourcemap-codec': 1.6.0 | |
| 3807 | + '@jridgewell/trace-mapping': 0.3.31 | |
| 3808 | + | |
| 3809 | + '@jridgewell/remapping@2.3.5': | |
| 3810 | + dependencies: | |
| 3811 | + '@jridgewell/gen-mapping': 0.3.13 | |
| 3812 | + '@jridgewell/trace-mapping': 0.3.31 | |
| 3813 | + | |
| 3814 | + '@jridgewell/resolve-uri@3.1.2': {} | |
| 3815 | + | |
| 3816 | + '@jridgewell/sourcemap-codec@1.6.0': {} | |
| 3817 | + | |
| 3818 | + '@jridgewell/trace-mapping@0.3.31': | |
| 3819 | + dependencies: | |
| 3820 | + '@jridgewell/resolve-uri': 3.1.2 | |
| 3821 | + '@jridgewell/sourcemap-codec': 1.6.0 | |
| 3822 | + | |
| 3823 | + '@napi-rs/lzma-linux-x64-gnu@1.5.1': | |
| 3824 | + optional: true | |
| 3825 | + | |
| 3826 | + '@napi-rs/wasm-runtime@1.2.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': | |
| 3827 | + dependencies: | |
| 3828 | + '@emnapi/core': 1.10.0 | |
| 3829 | + '@emnapi/runtime': 1.10.0 | |
| 3830 | + '@tybys/wasm-util': 0.10.3 | |
| 3831 | + optional: true | |
| 3832 | + | |
| 3833 | + '@next/env@16.3.4': {} | |
| 3834 | + | |
| 3835 | + '@next/eslint-plugin-next@16.3.4(eslint@9.39.5(jiti@2.7.0))': | |
| 3836 | + dependencies: | |
| 3837 | + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.5(jiti@2.7.0)) | |
| 3838 | + fast-glob: 3.3.1 | |
| 3839 | + transitivePeerDependencies: | |
| 3840 | + - eslint | |
| 3841 | + | |
| 3842 | + '@next/swc-darwin-arm64@16.3.4': | |
| 3843 | + optional: true | |
| 3844 | + | |
| 3845 | + '@next/swc-darwin-x64@16.3.4': | |
| 3846 | + optional: true | |
| 3847 | + | |
| 3848 | + '@next/swc-linux-arm64-gnu@16.3.4': | |
| 3849 | + optional: true | |
| 3850 | + | |
| 3851 | + '@next/swc-linux-arm64-musl@16.3.4': | |
| 3852 | + optional: true | |
| 3853 | + | |
| 3854 | + '@next/swc-linux-x64-gnu@16.3.4': | |
| 3855 | + optional: true | |
| 3856 | + | |
| 3857 | + '@next/swc-linux-x64-musl@16.3.4': | |
| 3858 | + optional: true | |
| 3859 | + | |
| 3860 | + '@next/swc-win32-arm64-msvc@16.3.4': | |
| 3861 | + optional: true | |
| 3862 | + | |
| 3863 | + '@next/swc-win32-x64-msvc@16.3.4': | |
| 3864 | + optional: true | |
| 3865 | + | |
| 3866 | + '@nodelib/fs.scandir@2.1.5': | |
| 3867 | + dependencies: | |
| 3868 | + '@nodelib/fs.stat': 2.0.5 | |
| 3869 | + run-parallel: 1.2.0 | |
| 3870 | + | |
| 3871 | + '@nodelib/fs.stat@2.0.5': {} | |
| 3872 | + | |
| 3873 | + '@nodelib/fs.walk@1.2.8': | |
| 3874 | + dependencies: | |
| 3875 | + '@nodelib/fs.scandir': 2.1.5 | |
| 3876 | + fastq: 1.20.3 | |
| 3877 | + | |
| 3878 | + '@nolyfill/is-core-module@1.0.39': {} | |
| 3879 | + | |
| 3880 | + '@pinojs/redact@0.4.0': {} | |
| 3881 | + | |
| 3882 | + '@rollup/rollup-android-arm-eabi@4.63.1': | |
| 3883 | + optional: true | |
| 3884 | + | |
| 3885 | + '@rollup/rollup-android-arm64@4.63.1': | |
| 3886 | + optional: true | |
| 3887 | + | |
| 3888 | + '@rollup/rollup-darwin-arm64@4.63.1': | |
| 3889 | + optional: true | |
| 3890 | + | |
| 3891 | + '@rollup/rollup-darwin-x64@4.63.1': | |
| 3892 | + optional: true | |
| 3893 | + | |
| 3894 | + '@rollup/rollup-freebsd-arm64@4.63.1': | |
| 3895 | + optional: true | |
| 3896 | + | |
| 3897 | + '@rollup/rollup-freebsd-x64@4.63.1': | |
| 3898 | + optional: true | |
| 3899 | + | |
| 3900 | + '@rollup/rollup-linux-arm-gnueabihf@4.63.1': | |
| 3901 | + optional: true | |
| 3902 | + | |
| 3903 | + '@rollup/rollup-linux-arm-musleabihf@4.63.1': | |
| 3904 | + optional: true | |
| 3905 | + | |
| 3906 | + '@rollup/rollup-linux-arm64-gnu@4.63.1': | |
| 3907 | + optional: true | |
| 3908 | + | |
| 3909 | + '@rollup/rollup-linux-arm64-musl@4.63.1': | |
| 3910 | + optional: true | |
| 3911 | + | |
| 3912 | + '@rollup/rollup-linux-loong64-gnu@4.63.1': | |
| 3913 | + optional: true | |
| 3914 | + | |
| 3915 | + '@rollup/rollup-linux-loong64-musl@4.63.1': | |
| 3916 | + optional: true | |
| 3917 | + | |
| 3918 | + '@rollup/rollup-linux-ppc64-gnu@4.63.1': | |
| 3919 | + optional: true | |
| 3920 | + | |
| 3921 | + '@rollup/rollup-linux-ppc64-musl@4.63.1': | |
| 3922 | + optional: true | |
| 3923 | + | |
| 3924 | + '@rollup/rollup-linux-riscv64-gnu@4.63.1': | |
| 3925 | + optional: true | |
| 3926 | + | |
| 3927 | + '@rollup/rollup-linux-riscv64-musl@4.63.1': | |
| 3928 | + optional: true | |
| 3929 | + | |
| 3930 | + '@rollup/rollup-linux-s390x-gnu@4.63.1': | |
| 3931 | + optional: true | |
| 3932 | + | |
| 3933 | + '@rollup/rollup-linux-x64-gnu@4.63.1': | |
| 3934 | + optional: true | |
| 3935 | + | |
| 3936 | + '@rollup/rollup-linux-x64-musl@4.63.1': | |
| 3937 | + optional: true | |
| 3938 | + | |
| 3939 | + '@rollup/rollup-openbsd-x64@4.63.1': | |
| 3940 | + optional: true | |
| 3941 | + | |
| 3942 | + '@rollup/rollup-openharmony-arm64@4.63.1': | |
| 3943 | + optional: true | |
| 3944 | + | |
| 3945 | + '@rollup/rollup-win32-arm64-msvc@4.63.1': | |
| 3946 | + optional: true | |
| 3947 | + | |
| 3948 | + '@rollup/rollup-win32-ia32-msvc@4.63.1': | |
| 3949 | + optional: true | |
| 3950 | + | |
| 3951 | + '@rollup/rollup-win32-x64-gnu@4.63.1': | |
| 3952 | + optional: true | |
| 3953 | + | |
| 3954 | + '@rollup/rollup-win32-x64-msvc@4.63.1': | |
| 3955 | + optional: true | |
| 3956 | + | |
| 3957 | + '@rtsao/scc@1.1.0': {} | |
| 3958 | + | |
| 3959 | + '@swc/helpers@0.5.23': | |
| 3960 | + dependencies: | |
| 3961 | + tslib: 2.8.1 | |
| 3962 | + | |
| 3963 | + '@tailwindcss/node@4.3.3': | |
| 3964 | + dependencies: | |
| 3965 | + '@jridgewell/remapping': 2.3.5 | |
| 3966 | + enhanced-resolve: 5.24.5 | |
| 3967 | + jiti: 2.7.0 | |
| 3968 | + lightningcss: 1.32.0 | |
| 3969 | + magic-string: 0.30.21 | |
| 3970 | + source-map-js: 1.2.1 | |
| 3971 | + tailwindcss: 4.3.3 | |
| 3972 | + | |
| 3973 | + '@tailwindcss/oxide-android-arm64@4.3.3': | |
| 3974 | + optional: true | |
| 3975 | + | |
| 3976 | + '@tailwindcss/oxide-darwin-arm64@4.3.3': | |
| 3977 | + optional: true | |
| 3978 | + | |
| 3979 | + '@tailwindcss/oxide-darwin-x64@4.3.3': | |
| 3980 | + optional: true | |
| 3981 | + | |
| 3982 | + '@tailwindcss/oxide-freebsd-x64@4.3.3': | |
| 3983 | + optional: true | |
| 3984 | + | |
| 3985 | + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': | |
| 3986 | + optional: true | |
| 3987 | + | |
| 3988 | + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': | |
| 3989 | + optional: true | |
| 3990 | + | |
| 3991 | + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': | |
| 3992 | + optional: true | |
| 3993 | + | |
| 3994 | + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': | |
| 3995 | + optional: true | |
| 3996 | + | |
| 3997 | + '@tailwindcss/oxide-linux-x64-musl@4.3.3': | |
| 3998 | + optional: true | |
| 3999 | + | |
| 4000 | + '@tailwindcss/oxide-wasm32-wasi@4.3.3': | |
| 4001 | + optional: true | |
| 4002 | + | |
| 4003 | + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': | |
| 4004 | + optional: true | |
| 4005 | + | |
| 4006 | + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': | |
| 4007 | + optional: true | |
| 4008 | + | |
| 4009 | + '@tailwindcss/oxide@4.3.3': | |
| 4010 | + optionalDependencies: | |
| 4011 | + '@tailwindcss/oxide-android-arm64': 4.3.3 | |
| 4012 | + '@tailwindcss/oxide-darwin-arm64': 4.3.3 | |
| 4013 | + '@tailwindcss/oxide-darwin-x64': 4.3.3 | |
| 4014 | + '@tailwindcss/oxide-freebsd-x64': 4.3.3 | |
| 4015 | + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.3 | |
| 4016 | + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.3 | |
| 4017 | + '@tailwindcss/oxide-linux-arm64-musl': 4.3.3 | |
| 4018 | + '@tailwindcss/oxide-linux-x64-gnu': 4.3.3 | |
| 4019 | + '@tailwindcss/oxide-linux-x64-musl': 4.3.3 | |
| 4020 | + '@tailwindcss/oxide-wasm32-wasi': 4.3.3 | |
| 4021 | + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3 | |
| 4022 | + '@tailwindcss/oxide-win32-x64-msvc': 4.3.3 | |
| 4023 | + | |
| 4024 | + '@tailwindcss/postcss@4.3.3': | |
| 4025 | + dependencies: | |
| 4026 | + '@alloc/quick-lru': 5.3.0 | |
| 4027 | + '@tailwindcss/node': 4.3.3 | |
| 4028 | + '@tailwindcss/oxide': 4.3.3 | |
| 4029 | + postcss: 8.5.28 | |
| 4030 | + tailwindcss: 4.3.3 | |
| 4031 | + | |
| 4032 | + '@tanstack/query-core@5.102.8': {} | |
| 4033 | + | |
| 4034 | + '@tanstack/react-query@5.102.8(react@19.2.8)': | |
| 4035 | + dependencies: | |
| 4036 | + '@tanstack/query-core': 5.102.8 | |
| 4037 | + react: 19.2.8 | |
| 4038 | + | |
| 4039 | + '@tybys/wasm-util@0.10.3': | |
| 4040 | + dependencies: | |
| 4041 | + tslib: 2.8.1 | |
| 4042 | + optional: true | |
| 4043 | + | |
| 4044 | + '@types/chai@5.2.3': | |
| 4045 | + dependencies: | |
| 4046 | + '@types/deep-eql': 4.0.2 | |
| 4047 | + assertion-error: 2.0.1 | |
| 4048 | + | |
| 4049 | + '@types/deep-eql@4.0.2': {} | |
| 4050 | + | |
| 4051 | + '@types/estree@1.0.9': {} | |
| 4052 | + | |
| 4053 | + '@types/json-schema@7.0.15': {} | |
| 4054 | + | |
| 4055 | + '@types/json5@0.0.29': {} | |
| 4056 | + | |
| 4057 | + '@types/node@24.13.3': | |
| 4058 | + dependencies: | |
| 4059 | + undici-types: 7.18.2 | |
| 4060 | + | |
| 4061 | + '@types/react-dom@19.2.7(@types/react@19.2.18)': | |
| 4062 | + dependencies: | |
| 4063 | + '@types/react': 19.2.18 | |
| 4064 | + | |
| 4065 | + '@types/react@19.2.18': | |
| 4066 | + dependencies: | |
| 4067 | + csstype: 3.2.3 | |
| 4068 | + | |
| 4069 | + '@typescript-eslint/eslint-plugin@8.69.0(@typescript-eslint/parser@8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3)': | |
| 4070 | + dependencies: | |
| 4071 | + '@eslint-community/regexpp': 4.12.2 | |
| 4072 | + '@typescript-eslint/parser': 8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) | |
| 4073 | + '@typescript-eslint/scope-manager': 8.69.0 | |
| 4074 | + '@typescript-eslint/type-utils': 8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) | |
| 4075 | + '@typescript-eslint/utils': 8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) | |
| 4076 | + '@typescript-eslint/visitor-keys': 8.69.0 | |
| 4077 | + eslint: 9.39.5(jiti@2.7.0) | |
| 4078 | + ignore: 7.0.8 | |
| 4079 | + natural-compare: 1.4.0 | |
| 4080 | + ts-api-utils: 2.5.0(typescript@5.9.3) | |
| 4081 | + typescript: 5.9.3 | |
| 4082 | + transitivePeerDependencies: | |
| 4083 | + - supports-color | |
| 4084 | + | |
| 4085 | + '@typescript-eslint/parser@8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3)': | |
| 4086 | + dependencies: | |
| 4087 | + '@typescript-eslint/scope-manager': 8.69.0 | |
| 4088 | + '@typescript-eslint/types': 8.69.0 | |
| 4089 | + '@typescript-eslint/typescript-estree': 8.69.0(typescript@5.9.3) | |
| 4090 | + '@typescript-eslint/visitor-keys': 8.69.0 | |
| 4091 | + debug: 4.4.3 | |
| 4092 | + eslint: 9.39.5(jiti@2.7.0) | |
| 4093 | + typescript: 5.9.3 | |
| 4094 | + transitivePeerDependencies: | |
| 4095 | + - supports-color | |
| 4096 | + | |
| 4097 | + '@typescript-eslint/project-service@8.69.0(typescript@5.9.3)': | |
| 4098 | + dependencies: | |
| 4099 | + '@typescript-eslint/tsconfig-utils': 8.69.0(typescript@5.9.3) | |
| 4100 | + '@typescript-eslint/types': 8.69.0 | |
| 4101 | + debug: 4.4.3 | |
| 4102 | + typescript: 5.9.3 | |
| 4103 | + transitivePeerDependencies: | |
| 4104 | + - supports-color | |
| 4105 | + | |
| 4106 | + '@typescript-eslint/scope-manager@8.69.0': | |
| 4107 | + dependencies: | |
| 4108 | + '@typescript-eslint/types': 8.69.0 | |
| 4109 | + '@typescript-eslint/visitor-keys': 8.69.0 | |
| 4110 | + | |
| 4111 | + '@typescript-eslint/tsconfig-utils@8.69.0(typescript@5.9.3)': | |
| 4112 | + dependencies: | |
| 4113 | + typescript: 5.9.3 | |
| 4114 | + | |
| 4115 | + '@typescript-eslint/type-utils@8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3)': | |
| 4116 | + dependencies: | |
| 4117 | + '@typescript-eslint/types': 8.69.0 | |
| 4118 | + '@typescript-eslint/typescript-estree': 8.69.0(typescript@5.9.3) | |
| 4119 | + '@typescript-eslint/utils': 8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) | |
| 4120 | + debug: 4.4.3 | |
| 4121 | + eslint: 9.39.5(jiti@2.7.0) | |
| 4122 | + ts-api-utils: 2.5.0(typescript@5.9.3) | |
| 4123 | + typescript: 5.9.3 | |
| 4124 | + transitivePeerDependencies: | |
| 4125 | + - supports-color | |
| 4126 | + | |
| 4127 | + '@typescript-eslint/types@8.69.0': {} | |
| 4128 | + | |
| 4129 | + '@typescript-eslint/typescript-estree@8.69.0(typescript@5.9.3)': | |
| 4130 | + dependencies: | |
| 4131 | + '@typescript-eslint/project-service': 8.69.0(typescript@5.9.3) | |
| 4132 | + '@typescript-eslint/tsconfig-utils': 8.69.0(typescript@5.9.3) | |
| 4133 | + '@typescript-eslint/types': 8.69.0 | |
| 4134 | + '@typescript-eslint/visitor-keys': 8.69.0 | |
| 4135 | + debug: 4.4.3 | |
| 4136 | + minimatch: 10.2.6 | |
| 4137 | + semver: 7.8.5 | |
| 4138 | + tinyglobby: 0.2.17 | |
| 4139 | + ts-api-utils: 2.5.0(typescript@5.9.3) | |
| 4140 | + typescript: 5.9.3 | |
| 4141 | + transitivePeerDependencies: | |
| 4142 | + - supports-color | |
| 4143 | + | |
| 4144 | + '@typescript-eslint/utils@8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3)': | |
| 4145 | + dependencies: | |
| 4146 | + '@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(jiti@2.7.0)) | |
| 4147 | + '@typescript-eslint/scope-manager': 8.69.0 | |
| 4148 | + '@typescript-eslint/types': 8.69.0 | |
| 4149 | + '@typescript-eslint/typescript-estree': 8.69.0(typescript@5.9.3) | |
| 4150 | + eslint: 9.39.5(jiti@2.7.0) | |
| 4151 | + typescript: 5.9.3 | |
| 4152 | + transitivePeerDependencies: | |
| 4153 | + - supports-color | |
| 4154 | + | |
| 4155 | + '@typescript-eslint/visitor-keys@8.69.0': | |
| 4156 | + dependencies: | |
| 4157 | + '@typescript-eslint/types': 8.69.0 | |
| 4158 | + eslint-visitor-keys: 5.0.1 | |
| 4159 | + | |
| 4160 | + '@unrs/resolver-binding-android-arm-eabi@1.12.2': | |
| 4161 | + optional: true | |
| 4162 | + | |
| 4163 | + '@unrs/resolver-binding-android-arm64@1.12.2': | |
| 4164 | + optional: true | |
| 4165 | + | |
| 4166 | + '@unrs/resolver-binding-darwin-arm64@1.12.2': | |
| 4167 | + optional: true | |
| 4168 | + | |
| 4169 | + '@unrs/resolver-binding-darwin-x64@1.12.2': | |
| 4170 | + optional: true | |
| 4171 | + | |
| 4172 | + '@unrs/resolver-binding-freebsd-x64@1.12.2': | |
| 4173 | + optional: true | |
| 4174 | + | |
| 4175 | + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': | |
| 4176 | + optional: true | |
| 4177 | + | |
| 4178 | + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': | |
| 4179 | + optional: true | |
| 4180 | + | |
| 4181 | + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': | |
| 4182 | + optional: true | |
| 4183 | + | |
| 4184 | + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': | |
| 4185 | + optional: true | |
| 4186 | + | |
| 4187 | + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': | |
| 4188 | + optional: true | |
| 4189 | + | |
| 4190 | + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': | |
| 4191 | + optional: true | |
| 4192 | + | |
| 4193 | + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': | |
| 4194 | + optional: true | |
| 4195 | + | |
| 4196 | + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': | |
| 4197 | + optional: true | |
| 4198 | + | |
| 4199 | + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': | |
| 4200 | + optional: true | |
| 4201 | + | |
| 4202 | + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': | |
| 4203 | + optional: true | |
| 4204 | + | |
| 4205 | + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': | |
| 4206 | + optional: true | |
| 4207 | + | |
| 4208 | + '@unrs/resolver-binding-linux-x64-musl@1.12.2': | |
| 4209 | + optional: true | |
| 4210 | + | |
| 4211 | + '@unrs/resolver-binding-openharmony-arm64@1.12.2': | |
| 4212 | + optional: true | |
| 4213 | + | |
| 4214 | + '@unrs/resolver-binding-wasm32-wasi@1.12.2': | |
| 4215 | + dependencies: | |
| 4216 | + '@emnapi/core': 1.10.0 | |
| 4217 | + '@emnapi/runtime': 1.10.0 | |
| 4218 | + '@napi-rs/wasm-runtime': 1.2.3(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) | |
| 4219 | + optional: true | |
| 4220 | + | |
| 4221 | + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': | |
| 4222 | + optional: true | |
| 4223 | + | |
| 4224 | + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': | |
| 4225 | + optional: true | |
| 4226 | + | |
| 4227 | + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': | |
| 4228 | + optional: true | |
| 4229 | + | |
| 4230 | + '@vitest/expect@3.2.7': | |
| 4231 | + dependencies: | |
| 4232 | + '@types/chai': 5.2.3 | |
| 4233 | + '@vitest/spy': 3.2.7 | |
| 4234 | + '@vitest/utils': 3.2.7 | |
| 4235 | + chai: 5.3.3 | |
| 4236 | + tinyrainbow: 2.0.0 | |
| 4237 | + | |
| 4238 | + '@vitest/mocker@3.2.7(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.13))': | |
| 4239 | + dependencies: | |
| 4240 | + '@vitest/spy': 3.2.7 | |
| 4241 | + estree-walker: 3.0.3 | |
| 4242 | + magic-string: 0.30.21 | |
| 4243 | + optionalDependencies: | |
| 4244 | + vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.13) | |
| 4245 | + | |
| 4246 | + '@vitest/pretty-format@3.2.7': | |
| 4247 | + dependencies: | |
| 4248 | + tinyrainbow: 2.0.0 | |
| 4249 | + | |
| 4250 | + '@vitest/runner@3.2.7': | |
| 4251 | + dependencies: | |
| 4252 | + '@vitest/utils': 3.2.7 | |
| 4253 | + pathe: 2.0.3 | |
| 4254 | + strip-literal: 3.1.0 | |
| 4255 | + | |
| 4256 | + '@vitest/snapshot@3.2.7': | |
| 4257 | + dependencies: | |
| 4258 | + '@vitest/pretty-format': 3.2.7 | |
| 4259 | + magic-string: 0.30.21 | |
| 4260 | + pathe: 2.0.3 | |
| 4261 | + | |
| 4262 | + '@vitest/spy@3.2.7': | |
| 4263 | + dependencies: | |
| 4264 | + tinyspy: 4.0.6 | |
| 4265 | + | |
| 4266 | + '@vitest/utils@3.2.7': | |
| 4267 | + dependencies: | |
| 4268 | + '@vitest/pretty-format': 3.2.7 | |
| 4269 | + loupe: 3.2.1 | |
| 4270 | + tinyrainbow: 2.0.0 | |
| 4271 | + | |
| 4272 | + acorn-jsx@5.3.2(acorn@8.18.0): | |
| 4273 | + dependencies: | |
| 4274 | + acorn: 8.18.0 | |
| 4275 | + | |
| 4276 | + acorn@8.18.0: {} | |
| 4277 | + | |
| 4278 | + ajv@6.15.0: | |
| 4279 | + dependencies: | |
| 4280 | + fast-deep-equal: 3.1.3 | |
| 4281 | + fast-json-stable-stringify: 2.1.0 | |
| 4282 | + json-schema-traverse: 0.4.1 | |
| 4283 | + uri-js: 4.4.1 | |
| 4284 | + | |
| 4285 | + ansi-styles@4.3.0: | |
| 4286 | + dependencies: | |
| 4287 | + color-convert: 2.0.1 | |
| 4288 | + | |
| 4289 | + argparse@2.0.1: {} | |
| 4290 | + | |
| 4291 | + aria-query@5.3.2: {} | |
| 4292 | + | |
| 4293 | + array-buffer-byte-length@1.0.2: | |
| 4294 | + dependencies: | |
| 4295 | + call-bound: 1.0.4 | |
| 4296 | + is-array-buffer: 3.0.5 | |
| 4297 | + | |
| 4298 | + array-includes@3.1.9: | |
| 4299 | + dependencies: | |
| 4300 | + call-bind: 1.0.9 | |
| 4301 | + call-bound: 1.0.4 | |
| 4302 | + define-properties: 1.2.1 | |
| 4303 | + es-abstract: 1.24.2 | |
| 4304 | + es-object-atoms: 1.1.2 | |
| 4305 | + get-intrinsic: 1.3.0 | |
| 4306 | + is-string: 1.1.1 | |
| 4307 | + math-intrinsics: 1.1.0 | |
| 4308 | + | |
| 4309 | + array.prototype.findlast@1.2.5: | |
| 4310 | + dependencies: | |
| 4311 | + call-bind: 1.0.9 | |
| 4312 | + define-properties: 1.2.1 | |
| 4313 | + es-abstract: 1.24.2 | |
| 4314 | + es-errors: 1.3.0 | |
| 4315 | + es-object-atoms: 1.1.2 | |
| 4316 | + es-shim-unscopables: 1.1.0 | |
| 4317 | + | |
| 4318 | + array.prototype.findlastindex@1.2.6: | |
| 4319 | + dependencies: | |
| 4320 | + call-bind: 1.0.9 | |
| 4321 | + call-bound: 1.0.4 | |
| 4322 | + define-properties: 1.2.1 | |
| 4323 | + es-abstract: 1.24.2 | |
| 4324 | + es-errors: 1.3.0 | |
| 4325 | + es-object-atoms: 1.1.2 | |
| 4326 | + es-shim-unscopables: 1.1.0 | |
| 4327 | + | |
| 4328 | + array.prototype.flat@1.3.3: | |
| 4329 | + dependencies: | |
| 4330 | + call-bind: 1.0.9 | |
| 4331 | + define-properties: 1.2.1 | |
| 4332 | + es-abstract: 1.24.2 | |
| 4333 | + es-shim-unscopables: 1.1.0 | |
| 4334 | + | |
| 4335 | + array.prototype.flatmap@1.3.3: | |
| 4336 | + dependencies: | |
| 4337 | + call-bind: 1.0.9 | |
| 4338 | + define-properties: 1.2.1 | |
| 4339 | + es-abstract: 1.24.2 | |
| 4340 | + es-shim-unscopables: 1.1.0 | |
| 4341 | + | |
| 4342 | + array.prototype.tosorted@1.1.4: | |
| 4343 | + dependencies: | |
| 4344 | + call-bind: 1.0.9 | |
| 4345 | + define-properties: 1.2.1 | |
| 4346 | + es-abstract: 1.24.2 | |
| 4347 | + es-errors: 1.3.0 | |
| 4348 | + es-shim-unscopables: 1.1.0 | |
| 4349 | + | |
| 4350 | + arraybuffer.prototype.slice@1.0.4: | |
| 4351 | + dependencies: | |
| 4352 | + array-buffer-byte-length: 1.0.2 | |
| 4353 | + call-bind: 1.0.9 | |
| 4354 | + define-properties: 1.2.1 | |
| 4355 | + es-abstract: 1.24.2 | |
| 4356 | + es-errors: 1.3.0 | |
| 4357 | + get-intrinsic: 1.3.0 | |
| 4358 | + is-array-buffer: 3.0.5 | |
| 4359 | + | |
| 4360 | + assertion-error@2.0.1: {} | |
| 4361 | + | |
| 4362 | + ast-types-flow@0.0.8: {} | |
| 4363 | + | |
| 4364 | + async-function@1.0.0: {} | |
| 4365 | + | |
| 4366 | + atomic-sleep@1.0.0: {} | |
| 4367 | + | |
| 4368 | + available-typed-arrays@1.0.7: | |
| 4369 | + dependencies: | |
| 4370 | + possible-typed-array-names: 1.1.0 | |
| 4371 | + | |
| 4372 | + axe-core@4.13.0: {} | |
| 4373 | + | |
| 4374 | + axobject-query@4.1.0: {} | |
| 4375 | + | |
| 4376 | + balanced-match@1.0.2: {} | |
| 4377 | + | |
| 4378 | + balanced-match@4.0.4: {} | |
| 4379 | + | |
| 4380 | + baseline-browser-mapping@2.11.21: {} | |
| 4381 | + | |
| 4382 | + boolbase@1.0.0: {} | |
| 4383 | + | |
| 4384 | + brace-expansion@1.1.18: | |
| 4385 | + dependencies: | |
| 4386 | + balanced-match: 1.0.2 | |
| 4387 | + concat-map: 0.0.1 | |
| 4388 | + | |
| 4389 | + brace-expansion@5.0.9: | |
| 4390 | + dependencies: | |
| 4391 | + balanced-match: 4.0.4 | |
| 4392 | + | |
| 4393 | + braces@3.0.3: | |
| 4394 | + dependencies: | |
| 4395 | + fill-range: 7.1.1 | |
| 4396 | + | |
| 4397 | + browserslist@4.28.9: | |
| 4398 | + dependencies: | |
| 4399 | + baseline-browser-mapping: 2.11.21 | |
| 4400 | + caniuse-lite: 1.0.30001810 | |
| 4401 | + electron-to-chromium: 1.5.422 | |
| 4402 | + node-releases: 2.0.54 | |
| 4403 | + update-browserslist-db: 1.3.2(browserslist@4.28.9) | |
| 4404 | + | |
| 4405 | + buffer-from@1.1.2: {} | |
| 4406 | + | |
| 4407 | + cac@6.7.14: {} | |
| 4408 | + | |
| 4409 | + call-bind-apply-helpers@1.0.2: | |
| 4410 | + dependencies: | |
| 4411 | + es-errors: 1.3.0 | |
| 4412 | + function-bind: 1.1.2 | |
| 4413 | + | |
| 4414 | + call-bind@1.0.9: | |
| 4415 | + dependencies: | |
| 4416 | + call-bind-apply-helpers: 1.0.2 | |
| 4417 | + es-define-property: 1.0.1 | |
| 4418 | + get-intrinsic: 1.3.0 | |
| 4419 | + set-function-length: 1.2.2 | |
| 4420 | + | |
| 4421 | + call-bound@1.0.4: | |
| 4422 | + dependencies: | |
| 4423 | + call-bind-apply-helpers: 1.0.2 | |
| 4424 | + get-intrinsic: 1.3.0 | |
| 4425 | + | |
| 4426 | + callsites@3.1.0: {} | |
| 4427 | + | |
| 4428 | + caniuse-lite@1.0.30001810: {} | |
| 4429 | + | |
| 4430 | + chai@5.3.3: | |
| 4431 | + dependencies: | |
| 4432 | + assertion-error: 2.0.1 | |
| 4433 | + check-error: 2.1.3 | |
| 4434 | + deep-eql: 5.0.2 | |
| 4435 | + loupe: 3.2.1 | |
| 4436 | + pathval: 2.0.1 | |
| 4437 | + | |
| 4438 | + chalk@4.1.2: | |
| 4439 | + dependencies: | |
| 4440 | + ansi-styles: 4.3.0 | |
| 4441 | + supports-color: 7.2.0 | |
| 4442 | + | |
| 4443 | + check-error@2.1.3: {} | |
| 4444 | + | |
| 4445 | + cheerio-select@2.1.0: | |
| 4446 | + dependencies: | |
| 4447 | + boolbase: 1.0.0 | |
| 4448 | + css-select: 5.2.2 | |
| 4449 | + css-what: 6.2.2 | |
| 4450 | + domelementtype: 2.3.0 | |
| 4451 | + domhandler: 5.0.3 | |
| 4452 | + domutils: 3.2.2 | |
| 4453 | + | |
| 4454 | + cheerio@1.2.0: | |
| 4455 | + dependencies: | |
| 4456 | + cheerio-select: 2.1.0 | |
| 4457 | + dom-serializer: 2.0.0 | |
| 4458 | + domhandler: 5.0.3 | |
| 4459 | + domutils: 3.2.2 | |
| 4460 | + encoding-sniffer: 0.2.1 | |
| 4461 | + htmlparser2: 10.1.0 | |
| 4462 | + parse5: 7.3.0 | |
| 4463 | + parse5-htmlparser2-tree-adapter: 7.1.0 | |
| 4464 | + parse5-parser-stream: 7.1.2 | |
| 4465 | + undici: 7.29.1 | |
| 4466 | + whatwg-mimetype: 4.0.0 | |
| 4467 | + | |
| 4468 | + client-only@0.0.1: {} | |
| 4469 | + | |
| 4470 | + color-convert@2.0.1: | |
| 4471 | + dependencies: | |
| 4472 | + color-name: 1.1.4 | |
| 4473 | + | |
| 4474 | + color-name@1.1.4: {} | |
| 4475 | + | |
| 4476 | + concat-map@0.0.1: {} | |
| 4477 | + | |
| 4478 | + convert-source-map@2.0.0: {} | |
| 4479 | + | |
| 4480 | + cross-spawn@7.0.6: | |
| 4481 | + dependencies: | |
| 4482 | + path-key: 3.1.1 | |
| 4483 | + shebang-command: 2.0.0 | |
| 4484 | + which: 2.0.2 | |
| 4485 | + | |
| 4486 | + css-select@5.2.2: | |
| 4487 | + dependencies: | |
| 4488 | + boolbase: 1.0.0 | |
| 4489 | + css-what: 6.2.2 | |
| 4490 | + domhandler: 5.0.3 | |
| 4491 | + domutils: 3.2.2 | |
| 4492 | + nth-check: 2.1.1 | |
| 4493 | + | |
| 4494 | + css-what@6.2.2: {} | |
| 4495 | + | |
| 4496 | + csstype@3.2.3: {} | |
| 4497 | + | |
| 4498 | + damerau-levenshtein@1.0.8: {} | |
| 4499 | + | |
| 4500 | + data-view-buffer@1.0.2: | |
| 4501 | + dependencies: | |
| 4502 | + call-bound: 1.0.4 | |
| 4503 | + es-errors: 1.3.0 | |
| 4504 | + is-data-view: 1.0.2 | |
| 4505 | + | |
| 4506 | + data-view-byte-length@1.0.2: | |
| 4507 | + dependencies: | |
| 4508 | + call-bound: 1.0.4 | |
| 4509 | + es-errors: 1.3.0 | |
| 4510 | + is-data-view: 1.0.2 | |
| 4511 | + | |
| 4512 | + data-view-byte-offset@1.0.1: | |
| 4513 | + dependencies: | |
| 4514 | + call-bound: 1.0.4 | |
| 4515 | + es-errors: 1.3.0 | |
| 4516 | + is-data-view: 1.0.2 | |
| 4517 | + | |
| 4518 | + debug@3.2.7: | |
| 4519 | + dependencies: | |
| 4520 | + ms: 2.1.3 | |
| 4521 | + | |
| 4522 | + debug@4.4.3: | |
| 4523 | + dependencies: | |
| 4524 | + ms: 2.1.3 | |
| 4525 | + | |
| 4526 | + deep-eql@5.0.2: {} | |
| 4527 | + | |
| 4528 | + deep-is@0.1.4: {} | |
| 4529 | + | |
| 4530 | + define-data-property@1.1.4: | |
| 4531 | + dependencies: | |
| 4532 | + es-define-property: 1.0.1 | |
| 4533 | + es-errors: 1.3.0 | |
| 4534 | + gopd: 1.2.0 | |
| 4535 | + | |
| 4536 | + define-properties@1.2.1: | |
| 4537 | + dependencies: | |
| 4538 | + define-data-property: 1.1.4 | |
| 4539 | + has-property-descriptors: 1.0.2 | |
| 4540 | + object-keys: 1.1.1 | |
| 4541 | + | |
| 4542 | + detect-libc@2.1.2: {} | |
| 4543 | + | |
| 4544 | + doctrine@2.1.0: | |
| 4545 | + dependencies: | |
| 4546 | + esutils: 2.0.3 | |
| 4547 | + | |
| 4548 | + dom-serializer@2.0.0: | |
| 4549 | + dependencies: | |
| 4550 | + domelementtype: 2.3.0 | |
| 4551 | + domhandler: 5.0.3 | |
| 4552 | + entities: 4.5.0 | |
| 4553 | + | |
| 4554 | + domelementtype@2.3.0: {} | |
| 4555 | + | |
| 4556 | + domhandler@5.0.3: | |
| 4557 | + dependencies: | |
| 4558 | + domelementtype: 2.3.0 | |
| 4559 | + | |
| 4560 | + domutils@3.2.2: | |
| 4561 | + dependencies: | |
| 4562 | + dom-serializer: 2.0.0 | |
| 4563 | + domelementtype: 2.3.0 | |
| 4564 | + domhandler: 5.0.3 | |
| 4565 | + | |
| 4566 | + drizzle-kit@0.31.10: | |
| 4567 | + dependencies: | |
| 4568 | + '@drizzle-team/brocli': 0.10.2 | |
| 4569 | + '@esbuild-kit/esm-loader': 2.6.5 | |
| 4570 | + esbuild: 0.25.12 | |
| 4571 | + tsx: 4.23.13 | |
| 4572 | + | |
| 4573 | + drizzle-orm@0.45.2(postgres@3.4.9): | |
| 4574 | + optionalDependencies: | |
| 4575 | + postgres: 3.4.9 | |
| 4576 | + | |
| 4577 | + dunder-proto@1.0.1: | |
| 4578 | + dependencies: | |
| 4579 | + call-bind-apply-helpers: 1.0.2 | |
| 4580 | + es-errors: 1.3.0 | |
| 4581 | + gopd: 1.2.0 | |
| 4582 | + | |
| 4583 | + electron-to-chromium@1.5.422: {} | |
| 4584 | + | |
| 4585 | + emoji-regex@9.2.2: {} | |
| 4586 | + | |
| 4587 | + encoding-sniffer@0.2.1: | |
| 4588 | + dependencies: | |
| 4589 | + iconv-lite: 0.6.3 | |
| 4590 | + whatwg-encoding: 3.1.1 | |
| 4591 | + | |
| 4592 | + enhanced-resolve@5.24.5: | |
| 4593 | + dependencies: | |
| 4594 | + graceful-fs: 4.2.11 | |
| 4595 | + tapable: 2.3.3 | |
| 4596 | + | |
| 4597 | + entities@4.5.0: {} | |
| 4598 | + | |
| 4599 | + entities@6.0.1: {} | |
| 4600 | + | |
| 4601 | + entities@7.0.1: {} | |
| 4602 | + | |
| 4603 | + es-abstract-get@1.0.0: | |
| 4604 | + dependencies: | |
| 4605 | + es-errors: 1.3.0 | |
| 4606 | + es-object-atoms: 1.1.2 | |
| 4607 | + is-callable: 1.2.7 | |
| 4608 | + object-inspect: 1.13.4 | |
| 4609 | + | |
| 4610 | + es-abstract@1.24.2: | |
| 4611 | + dependencies: | |
| 4612 | + array-buffer-byte-length: 1.0.2 | |
| 4613 | + arraybuffer.prototype.slice: 1.0.4 | |
| 4614 | + available-typed-arrays: 1.0.7 | |
| 4615 | + call-bind: 1.0.9 | |
| 4616 | + call-bound: 1.0.4 | |
| 4617 | + data-view-buffer: 1.0.2 | |
| 4618 | + data-view-byte-length: 1.0.2 | |
| 4619 | + data-view-byte-offset: 1.0.1 | |
| 4620 | + es-define-property: 1.0.1 | |
| 4621 | + es-errors: 1.3.0 | |
| 4622 | + es-object-atoms: 1.1.2 | |
| 4623 | + es-set-tostringtag: 2.1.0 | |
| 4624 | + es-to-primitive: 1.3.4 | |
| 4625 | + function.prototype.name: 1.2.0 | |
| 4626 | + get-intrinsic: 1.3.0 | |
| 4627 | + get-proto: 1.0.1 | |
| 4628 | + get-symbol-description: 1.1.0 | |
| 4629 | + globalthis: 1.0.4 | |
| 4630 | + gopd: 1.2.0 | |
| 4631 | + has-property-descriptors: 1.0.2 | |
| 4632 | + has-proto: 1.2.0 | |
| 4633 | + has-symbols: 1.1.0 | |
| 4634 | + hasown: 2.0.4 | |
| 4635 | + internal-slot: 1.1.0 | |
| 4636 | + is-array-buffer: 3.0.5 | |
| 4637 | + is-callable: 1.2.7 | |
| 4638 | + is-data-view: 1.0.2 | |
| 4639 | + is-negative-zero: 2.0.3 | |
| 4640 | + is-regex: 1.2.1 | |
| 4641 | + is-set: 2.0.3 | |
| 4642 | + is-shared-array-buffer: 1.0.4 | |
| 4643 | + is-string: 1.1.1 | |
| 4644 | + is-typed-array: 1.1.15 | |
| 4645 | + is-weakref: 1.1.1 | |
| 4646 | + math-intrinsics: 1.1.0 | |
| 4647 | + object-inspect: 1.13.4 | |
| 4648 | + object-keys: 1.1.1 | |
| 4649 | + object.assign: 4.1.7 | |
| 4650 | + own-keys: 1.0.2 | |
| 4651 | + regexp.prototype.flags: 1.5.4 | |
| 4652 | + safe-array-concat: 1.1.4 | |
| 4653 | + safe-push-apply: 1.0.0 | |
| 4654 | + safe-regex-test: 1.1.0 | |
| 4655 | + set-proto: 1.0.0 | |
| 4656 | + stop-iteration-iterator: 1.1.0 | |
| 4657 | + string.prototype.trim: 1.2.11 | |
| 4658 | + string.prototype.trimend: 1.0.10 | |
| 4659 | + string.prototype.trimstart: 1.0.8 | |
| 4660 | + typed-array-buffer: 1.0.3 | |
| 4661 | + typed-array-byte-length: 1.0.3 | |
| 4662 | + typed-array-byte-offset: 1.0.4 | |
| 4663 | + typed-array-length: 1.0.8 | |
| 4664 | + unbox-primitive: 1.1.0 | |
| 4665 | + which-typed-array: 1.1.22 | |
| 4666 | + | |
| 4667 | + es-define-property@1.0.1: {} | |
| 4668 | + | |
| 4669 | + es-errors@1.3.0: {} | |
| 4670 | + | |
| 4671 | + es-iterator-helpers@1.4.0: | |
| 4672 | + dependencies: | |
| 4673 | + call-bind: 1.0.9 | |
| 4674 | + call-bound: 1.0.4 | |
| 4675 | + define-properties: 1.2.1 | |
| 4676 | + es-abstract: 1.24.2 | |
| 4677 | + es-errors: 1.3.0 | |
| 4678 | + es-set-tostringtag: 2.1.0 | |
| 4679 | + function-bind: 1.1.2 | |
| 4680 | + get-intrinsic: 1.3.0 | |
| 4681 | + globalthis: 1.0.4 | |
| 4682 | + gopd: 1.2.0 | |
| 4683 | + has-property-descriptors: 1.0.2 | |
| 4684 | + has-proto: 1.2.0 | |
| 4685 | + has-symbols: 1.1.0 | |
| 4686 | + internal-slot: 1.1.0 | |
| 4687 | + iterator.prototype: 1.1.5 | |
| 4688 | + math-intrinsics: 1.1.0 | |
| 4689 | + | |
| 4690 | + es-module-lexer@1.7.0: {} | |
| 4691 | + | |
| 4692 | + es-object-atoms@1.1.2: | |
| 4693 | + dependencies: | |
| 4694 | + es-errors: 1.3.0 | |
| 4695 | + | |
| 4696 | + es-set-tostringtag@2.1.0: | |
| 4697 | + dependencies: | |
| 4698 | + es-errors: 1.3.0 | |
| 4699 | + get-intrinsic: 1.3.0 | |
| 4700 | + has-tostringtag: 1.0.2 | |
| 4701 | + hasown: 2.0.4 | |
| 4702 | + | |
| 4703 | + es-shim-unscopables@1.1.0: | |
| 4704 | + dependencies: | |
| 4705 | + hasown: 2.0.4 | |
| 4706 | + | |
| 4707 | + es-to-primitive@1.3.4: | |
| 4708 | + dependencies: | |
| 4709 | + es-abstract-get: 1.0.0 | |
| 4710 | + es-define-property: 1.0.1 | |
| 4711 | + es-errors: 1.3.0 | |
| 4712 | + is-callable: 1.2.7 | |
| 4713 | + is-date-object: 1.1.0 | |
| 4714 | + is-symbol: 1.1.1 | |
| 4715 | + | |
| 4716 | + esbuild@0.18.20: | |
| 4717 | + optionalDependencies: | |
| 4718 | + '@esbuild/android-arm': 0.18.20 | |
| 4719 | + '@esbuild/android-arm64': 0.18.20 | |
| 4720 | + '@esbuild/android-x64': 0.18.20 | |
| 4721 | + '@esbuild/darwin-arm64': 0.18.20 | |
| 4722 | + '@esbuild/darwin-x64': 0.18.20 | |
| 4723 | + '@esbuild/freebsd-arm64': 0.18.20 | |
| 4724 | + '@esbuild/freebsd-x64': 0.18.20 | |
| 4725 | + '@esbuild/linux-arm': 0.18.20 | |
| 4726 | + '@esbuild/linux-arm64': 0.18.20 | |
| 4727 | + '@esbuild/linux-ia32': 0.18.20 | |
| 4728 | + '@esbuild/linux-loong64': 0.18.20 | |
| 4729 | + '@esbuild/linux-mips64el': 0.18.20 | |
| 4730 | + '@esbuild/linux-ppc64': 0.18.20 | |
| 4731 | + '@esbuild/linux-riscv64': 0.18.20 | |
| 4732 | + '@esbuild/linux-s390x': 0.18.20 | |
| 4733 | + '@esbuild/linux-x64': 0.18.20 | |
| 4734 | + '@esbuild/netbsd-x64': 0.18.20 | |
| 4735 | + '@esbuild/openbsd-x64': 0.18.20 | |
| 4736 | + '@esbuild/sunos-x64': 0.18.20 | |
| 4737 | + '@esbuild/win32-arm64': 0.18.20 | |
| 4738 | + '@esbuild/win32-ia32': 0.18.20 | |
| 4739 | + '@esbuild/win32-x64': 0.18.20 | |
| 4740 | + | |
| 4741 | + esbuild@0.25.12: | |
| 4742 | + optionalDependencies: | |
| 4743 | + '@esbuild/aix-ppc64': 0.25.12 | |
| 4744 | + '@esbuild/android-arm': 0.25.12 | |
| 4745 | + '@esbuild/android-arm64': 0.25.12 | |
| 4746 | + '@esbuild/android-x64': 0.25.12 | |
| 4747 | + '@esbuild/darwin-arm64': 0.25.12 | |
| 4748 | + '@esbuild/darwin-x64': 0.25.12 | |
| 4749 | + '@esbuild/freebsd-arm64': 0.25.12 | |
| 4750 | + '@esbuild/freebsd-x64': 0.25.12 | |
| 4751 | + '@esbuild/linux-arm': 0.25.12 | |
| 4752 | + '@esbuild/linux-arm64': 0.25.12 | |
| 4753 | + '@esbuild/linux-ia32': 0.25.12 | |
| 4754 | + '@esbuild/linux-loong64': 0.25.12 | |
| 4755 | + '@esbuild/linux-mips64el': 0.25.12 | |
| 4756 | + '@esbuild/linux-ppc64': 0.25.12 | |
| 4757 | + '@esbuild/linux-riscv64': 0.25.12 | |
| 4758 | + '@esbuild/linux-s390x': 0.25.12 | |
| 4759 | + '@esbuild/linux-x64': 0.25.12 | |
| 4760 | + '@esbuild/netbsd-arm64': 0.25.12 | |
| 4761 | + '@esbuild/netbsd-x64': 0.25.12 | |
| 4762 | + '@esbuild/openbsd-arm64': 0.25.12 | |
| 4763 | + '@esbuild/openbsd-x64': 0.25.12 | |
| 4764 | + '@esbuild/openharmony-arm64': 0.25.12 | |
| 4765 | + '@esbuild/sunos-x64': 0.25.12 | |
| 4766 | + '@esbuild/win32-arm64': 0.25.12 | |
| 4767 | + '@esbuild/win32-ia32': 0.25.12 | |
| 4768 | + '@esbuild/win32-x64': 0.25.12 | |
| 4769 | + | |
| 4770 | + esbuild@0.28.2: | |
| 4771 | + optionalDependencies: | |
| 4772 | + '@esbuild/aix-ppc64': 0.28.2 | |
| 4773 | + '@esbuild/android-arm': 0.28.2 | |
| 4774 | + '@esbuild/android-arm64': 0.28.2 | |
| 4775 | + '@esbuild/android-x64': 0.28.2 | |
| 4776 | + '@esbuild/darwin-arm64': 0.28.2 | |
| 4777 | + '@esbuild/darwin-x64': 0.28.2 | |
| 4778 | + '@esbuild/freebsd-arm64': 0.28.2 | |
| 4779 | + '@esbuild/freebsd-x64': 0.28.2 | |
| 4780 | + '@esbuild/linux-arm': 0.28.2 | |
| 4781 | + '@esbuild/linux-arm64': 0.28.2 | |
| 4782 | + '@esbuild/linux-ia32': 0.28.2 | |
| 4783 | + '@esbuild/linux-loong64': 0.28.2 | |
| 4784 | + '@esbuild/linux-mips64el': 0.28.2 | |
| 4785 | + '@esbuild/linux-ppc64': 0.28.2 | |
| 4786 | + '@esbuild/linux-riscv64': 0.28.2 | |
| 4787 | + '@esbuild/linux-s390x': 0.28.2 | |
| 4788 | + '@esbuild/linux-x64': 0.28.2 | |
| 4789 | + '@esbuild/netbsd-arm64': 0.28.2 | |
| 4790 | + '@esbuild/netbsd-x64': 0.28.2 | |
| 4791 | + '@esbuild/openbsd-arm64': 0.28.2 | |
| 4792 | + '@esbuild/openbsd-x64': 0.28.2 | |
| 4793 | + '@esbuild/openharmony-arm64': 0.28.2 | |
| 4794 | + '@esbuild/sunos-x64': 0.28.2 | |
| 4795 | + '@esbuild/win32-arm64': 0.28.2 | |
| 4796 | + '@esbuild/win32-ia32': 0.28.2 | |
| 4797 | + '@esbuild/win32-x64': 0.28.2 | |
| 4798 | + | |
| 4799 | + escalade@3.2.0: {} | |
| 4800 | + | |
| 4801 | + escape-string-regexp@4.0.0: {} | |
| 4802 | + | |
| 4803 | + eslint-config-next@16.3.4(@typescript-eslint/parser@8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3): | |
| 4804 | + dependencies: | |
| 4805 | + '@next/eslint-plugin-next': 16.3.4(eslint@9.39.5(jiti@2.7.0)) | |
| 4806 | + eslint: 9.39.5(jiti@2.7.0) | |
| 4807 | + eslint-import-resolver-node: 0.3.10 | |
| 4808 | + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0)) | |
| 4809 | + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)) | |
| 4810 | + eslint-plugin-jsx-a11y: 6.10.2(eslint@9.39.5(jiti@2.7.0)) | |
| 4811 | + eslint-plugin-react: 7.37.5(eslint@9.39.5(jiti@2.7.0)) | |
| 4812 | + eslint-plugin-react-hooks: 7.1.1(eslint@9.39.5(jiti@2.7.0)) | |
| 4813 | + globals: 16.4.0 | |
| 4814 | + typescript-eslint: 8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) | |
| 4815 | + optionalDependencies: | |
| 4816 | + typescript: 5.9.3 | |
| 4817 | + transitivePeerDependencies: | |
| 4818 | + - '@typescript-eslint/parser' | |
| 4819 | + - eslint-import-resolver-webpack | |
| 4820 | + - eslint-plugin-import-x | |
| 4821 | + - supports-color | |
| 4822 | + | |
| 4823 | + eslint-import-resolver-node@0.3.10: | |
| 4824 | + dependencies: | |
| 4825 | + debug: 3.2.7 | |
| 4826 | + is-core-module: 2.16.2 | |
| 4827 | + resolve: 2.0.0-next.7 | |
| 4828 | + transitivePeerDependencies: | |
| 4829 | + - supports-color | |
| 4830 | + | |
| 4831 | + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0)): | |
| 4832 | + dependencies: | |
| 4833 | + '@nolyfill/is-core-module': 1.0.39 | |
| 4834 | + debug: 4.4.3 | |
| 4835 | + eslint: 9.39.5(jiti@2.7.0) | |
| 4836 | + get-tsconfig: 4.14.3 | |
| 4837 | + is-bun-module: 2.0.0 | |
| 4838 | + stable-hash: 0.0.5 | |
| 4839 | + tinyglobby: 0.2.17 | |
| 4840 | + unrs-resolver: 1.12.2 | |
| 4841 | + optionalDependencies: | |
| 4842 | + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)) | |
| 4843 | + transitivePeerDependencies: | |
| 4844 | + - supports-color | |
| 4845 | + | |
| 4846 | + eslint-module-utils@2.14.0(@typescript-eslint/parser@8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0)): | |
| 4847 | + dependencies: | |
| 4848 | + debug: 3.2.7 | |
| 4849 | + optionalDependencies: | |
| 4850 | + '@typescript-eslint/parser': 8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) | |
| 4851 | + eslint: 9.39.5(jiti@2.7.0) | |
| 4852 | + eslint-import-resolver-node: 0.3.10 | |
| 4853 | + eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0)) | |
| 4854 | + transitivePeerDependencies: | |
| 4855 | + - supports-color | |
| 4856 | + | |
| 4857 | + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.39.5(jiti@2.7.0)): | |
| 4858 | + dependencies: | |
| 4859 | + '@rtsao/scc': 1.1.0 | |
| 4860 | + array-includes: 3.1.9 | |
| 4861 | + array.prototype.findlastindex: 1.2.6 | |
| 4862 | + array.prototype.flat: 1.3.3 | |
| 4863 | + array.prototype.flatmap: 1.3.3 | |
| 4864 | + debug: 3.2.7 | |
| 4865 | + doctrine: 2.1.0 | |
| 4866 | + eslint: 9.39.5(jiti@2.7.0) | |
| 4867 | + eslint-import-resolver-node: 0.3.10 | |
| 4868 | + eslint-module-utils: 2.14.0(@typescript-eslint/parser@8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint-import-resolver-node@0.3.10)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0)))(eslint@9.39.5(jiti@2.7.0)) | |
| 4869 | + hasown: 2.0.4 | |
| 4870 | + is-core-module: 2.16.2 | |
| 4871 | + is-glob: 4.0.3 | |
| 4872 | + minimatch: 3.1.5 | |
| 4873 | + object.fromentries: 2.0.8 | |
| 4874 | + object.groupby: 1.0.3 | |
| 4875 | + object.values: 1.2.1 | |
| 4876 | + semver: 6.3.1 | |
| 4877 | + string.prototype.trimend: 1.0.10 | |
| 4878 | + tsconfig-paths: 3.15.0 | |
| 4879 | + optionalDependencies: | |
| 4880 | + '@typescript-eslint/parser': 8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) | |
| 4881 | + transitivePeerDependencies: | |
| 4882 | + - eslint-import-resolver-typescript | |
| 4883 | + - eslint-import-resolver-webpack | |
| 4884 | + - supports-color | |
| 4885 | + | |
| 4886 | + eslint-plugin-jsx-a11y@6.10.2(eslint@9.39.5(jiti@2.7.0)): | |
| 4887 | + dependencies: | |
| 4888 | + aria-query: 5.3.2 | |
| 4889 | + array-includes: 3.1.9 | |
| 4890 | + array.prototype.flatmap: 1.3.3 | |
| 4891 | + ast-types-flow: 0.0.8 | |
| 4892 | + axe-core: 4.13.0 | |
| 4893 | + axobject-query: 4.1.0 | |
| 4894 | + damerau-levenshtein: 1.0.8 | |
| 4895 | + emoji-regex: 9.2.2 | |
| 4896 | + eslint: 9.39.5(jiti@2.7.0) | |
| 4897 | + hasown: 2.0.4 | |
| 4898 | + jsx-ast-utils: 3.3.5 | |
| 4899 | + language-tags: 1.0.9 | |
| 4900 | + minimatch: 3.1.5 | |
| 4901 | + object.fromentries: 2.0.8 | |
| 4902 | + safe-regex-test: 1.1.0 | |
| 4903 | + string.prototype.includes: 2.0.1 | |
| 4904 | + | |
| 4905 | + eslint-plugin-react-hooks@7.1.1(eslint@9.39.5(jiti@2.7.0)): | |
| 4906 | + dependencies: | |
| 4907 | + '@babel/core': 7.29.7 | |
| 4908 | + '@babel/parser': 7.29.8 | |
| 4909 | + eslint: 9.39.5(jiti@2.7.0) | |
| 4910 | + hermes-parser: 0.25.1 | |
| 4911 | + zod: 4.5.4 | |
| 4912 | + zod-validation-error: 4.0.2(zod@4.5.4) | |
| 4913 | + transitivePeerDependencies: | |
| 4914 | + - supports-color | |
| 4915 | + | |
| 4916 | + eslint-plugin-react@7.37.5(eslint@9.39.5(jiti@2.7.0)): | |
| 4917 | + dependencies: | |
| 4918 | + array-includes: 3.1.9 | |
| 4919 | + array.prototype.findlast: 1.2.5 | |
| 4920 | + array.prototype.flatmap: 1.3.3 | |
| 4921 | + array.prototype.tosorted: 1.1.4 | |
| 4922 | + doctrine: 2.1.0 | |
| 4923 | + es-iterator-helpers: 1.4.0 | |
| 4924 | + eslint: 9.39.5(jiti@2.7.0) | |
| 4925 | + estraverse: 5.3.0 | |
| 4926 | + hasown: 2.0.4 | |
| 4927 | + jsx-ast-utils: 3.3.5 | |
| 4928 | + minimatch: 3.1.5 | |
| 4929 | + object.entries: 1.1.9 | |
| 4930 | + object.fromentries: 2.0.8 | |
| 4931 | + object.values: 1.2.1 | |
| 4932 | + prop-types: 15.8.1 | |
| 4933 | + resolve: 2.0.0-next.7 | |
| 4934 | + semver: 6.3.1 | |
| 4935 | + string.prototype.matchall: 4.1.0 | |
| 4936 | + string.prototype.repeat: 1.0.0 | |
| 4937 | + | |
| 4938 | + eslint-scope@8.4.0: | |
| 4939 | + dependencies: | |
| 4940 | + esrecurse: 4.3.0 | |
| 4941 | + estraverse: 5.3.0 | |
| 4942 | + | |
| 4943 | + eslint-visitor-keys@3.4.3: {} | |
| 4944 | + | |
| 4945 | + eslint-visitor-keys@4.2.1: {} | |
| 4946 | + | |
| 4947 | + eslint-visitor-keys@5.0.1: {} | |
| 4948 | + | |
| 4949 | + eslint@9.39.5(jiti@2.7.0): | |
| 4950 | + dependencies: | |
| 4951 | + '@eslint-community/eslint-utils': 4.10.1(eslint@9.39.5(jiti@2.7.0)) | |
| 4952 | + '@eslint-community/regexpp': 4.12.2 | |
| 4953 | + '@eslint/config-array': 0.21.2 | |
| 4954 | + '@eslint/config-helpers': 0.4.2 | |
| 4955 | + '@eslint/core': 0.17.0 | |
| 4956 | + '@eslint/eslintrc': 3.3.7 | |
| 4957 | + '@eslint/js': 9.39.5 | |
| 4958 | + '@eslint/plugin-kit': 0.4.1 | |
| 4959 | + '@humanfs/node': 0.16.8 | |
| 4960 | + '@humanwhocodes/module-importer': 1.0.1 | |
| 4961 | + '@humanwhocodes/retry': 0.4.3 | |
| 4962 | + '@types/estree': 1.0.9 | |
| 4963 | + ajv: 6.15.0 | |
| 4964 | + chalk: 4.1.2 | |
| 4965 | + cross-spawn: 7.0.6 | |
| 4966 | + debug: 4.4.3 | |
| 4967 | + escape-string-regexp: 4.0.0 | |
| 4968 | + eslint-scope: 8.4.0 | |
| 4969 | + eslint-visitor-keys: 4.2.1 | |
| 4970 | + espree: 10.4.0 | |
| 4971 | + esquery: 1.7.0 | |
| 4972 | + esutils: 2.0.3 | |
| 4973 | + fast-deep-equal: 3.1.3 | |
| 4974 | + file-entry-cache: 8.0.0 | |
| 4975 | + find-up: 5.0.0 | |
| 4976 | + glob-parent: 6.0.2 | |
| 4977 | + ignore: 5.3.2 | |
| 4978 | + imurmurhash: 0.1.4 | |
| 4979 | + is-glob: 4.0.3 | |
| 4980 | + json-stable-stringify-without-jsonify: 1.0.1 | |
| 4981 | + lodash.merge: 4.6.2 | |
| 4982 | + minimatch: 3.1.5 | |
| 4983 | + natural-compare: 1.4.0 | |
| 4984 | + optionator: 0.9.4 | |
| 4985 | + optionalDependencies: | |
| 4986 | + jiti: 2.7.0 | |
| 4987 | + transitivePeerDependencies: | |
| 4988 | + - supports-color | |
| 4989 | + | |
| 4990 | + espree@10.4.0: | |
| 4991 | + dependencies: | |
| 4992 | + acorn: 8.18.0 | |
| 4993 | + acorn-jsx: 5.3.2(acorn@8.18.0) | |
| 4994 | + eslint-visitor-keys: 4.2.1 | |
| 4995 | + | |
| 4996 | + esquery@1.7.0: | |
| 4997 | + dependencies: | |
| 4998 | + estraverse: 5.3.0 | |
| 4999 | + | |
| 5000 | + esrecurse@4.3.0: | |
| 5001 | + dependencies: | |
| 5002 | + estraverse: 5.3.0 | |
| 5003 | + | |
| 5004 | + estraverse@5.3.0: {} | |
| 5005 | + | |
| 5006 | + estree-walker@3.0.3: | |
| 5007 | + dependencies: | |
| 5008 | + '@types/estree': 1.0.9 | |
| 5009 | + | |
| 5010 | + esutils@2.0.3: {} | |
| 5011 | + | |
| 5012 | + expect-type@1.4.0: {} | |
| 5013 | + | |
| 5014 | + fast-deep-equal@3.1.3: {} | |
| 5015 | + | |
| 5016 | + fast-glob@3.3.1: | |
| 5017 | + dependencies: | |
| 5018 | + '@nodelib/fs.stat': 2.0.5 | |
| 5019 | + '@nodelib/fs.walk': 1.2.8 | |
| 5020 | + glob-parent: 5.1.2 | |
| 5021 | + merge2: 1.4.1 | |
| 5022 | + micromatch: 4.0.8 | |
| 5023 | + | |
| 5024 | + fast-json-stable-stringify@2.1.0: {} | |
| 5025 | + | |
| 5026 | + fast-levenshtein@2.0.6: {} | |
| 5027 | + | |
| 5028 | + fastq@1.20.3: | |
| 5029 | + dependencies: | |
| 5030 | + reusify: 1.1.0 | |
| 5031 | + | |
| 5032 | + fdir@6.5.0(picomatch@4.0.7): | |
| 5033 | + optionalDependencies: | |
| 5034 | + picomatch: 4.0.7 | |
| 5035 | + | |
| 5036 | + file-entry-cache@8.0.0: | |
| 5037 | + dependencies: | |
| 5038 | + flat-cache: 4.0.1 | |
| 5039 | + | |
| 5040 | + fill-range@7.1.1: | |
| 5041 | + dependencies: | |
| 5042 | + to-regex-range: 5.0.1 | |
| 5043 | + | |
| 5044 | + find-up@5.0.0: | |
| 5045 | + dependencies: | |
| 5046 | + locate-path: 6.0.0 | |
| 5047 | + path-exists: 4.0.0 | |
| 5048 | + | |
| 5049 | + flat-cache@4.0.1: | |
| 5050 | + dependencies: | |
| 5051 | + flatted: 3.4.4 | |
| 5052 | + keyv: 4.5.4 | |
| 5053 | + | |
| 5054 | + flatted@3.4.4: {} | |
| 5055 | + | |
| 5056 | + for-each@0.3.5: | |
| 5057 | + dependencies: | |
| 5058 | + is-callable: 1.2.7 | |
| 5059 | + | |
| 5060 | + fsevents@2.3.3: | |
| 5061 | + optional: true | |
| 5062 | + | |
| 5063 | + function-bind@1.1.2: {} | |
| 5064 | + | |
| 5065 | + function.prototype.name@1.2.0: | |
| 5066 | + dependencies: | |
| 5067 | + call-bind: 1.0.9 | |
| 5068 | + call-bound: 1.0.4 | |
| 5069 | + es-define-property: 1.0.1 | |
| 5070 | + es-errors: 1.3.0 | |
| 5071 | + functions-have-names: 1.2.3 | |
| 5072 | + has-property-descriptors: 1.0.2 | |
| 5073 | + hasown: 2.0.4 | |
| 5074 | + is-callable: 1.2.7 | |
| 5075 | + is-document.all: 1.0.0 | |
| 5076 | + | |
| 5077 | + functions-have-names@1.2.3: {} | |
| 5078 | + | |
| 5079 | + generator-function@2.0.1: {} | |
| 5080 | + | |
| 5081 | + gensync@1.0.0-beta.2: {} | |
| 5082 | + | |
| 5083 | + get-intrinsic@1.3.0: | |
| 5084 | + dependencies: | |
| 5085 | + call-bind-apply-helpers: 1.0.2 | |
| 5086 | + es-define-property: 1.0.1 | |
| 5087 | + es-errors: 1.3.0 | |
| 5088 | + es-object-atoms: 1.1.2 | |
| 5089 | + function-bind: 1.1.2 | |
| 5090 | + get-proto: 1.0.1 | |
| 5091 | + gopd: 1.2.0 | |
| 5092 | + has-symbols: 1.1.0 | |
| 5093 | + hasown: 2.0.4 | |
| 5094 | + math-intrinsics: 1.1.0 | |
| 5095 | + | |
| 5096 | + get-proto@1.0.1: | |
| 5097 | + dependencies: | |
| 5098 | + dunder-proto: 1.0.1 | |
| 5099 | + es-object-atoms: 1.1.2 | |
| 5100 | + | |
| 5101 | + get-symbol-description@1.1.0: | |
| 5102 | + dependencies: | |
| 5103 | + call-bound: 1.0.4 | |
| 5104 | + es-errors: 1.3.0 | |
| 5105 | + get-intrinsic: 1.3.0 | |
| 5106 | + | |
| 5107 | + get-tsconfig@4.14.3: | |
| 5108 | + dependencies: | |
| 5109 | + resolve-pkg-maps: 1.0.0 | |
| 5110 | + | |
| 5111 | + glob-parent@5.1.2: | |
| 5112 | + dependencies: | |
| 5113 | + is-glob: 4.0.3 | |
| 5114 | + | |
| 5115 | + glob-parent@6.0.2: | |
| 5116 | + dependencies: | |
| 5117 | + is-glob: 4.0.3 | |
| 5118 | + | |
| 5119 | + globals@14.0.0: {} | |
| 5120 | + | |
| 5121 | + globals@16.4.0: {} | |
| 5122 | + | |
| 5123 | + globalthis@1.0.4: | |
| 5124 | + dependencies: | |
| 5125 | + define-properties: 1.2.1 | |
| 5126 | + gopd: 1.2.0 | |
| 5127 | + | |
| 5128 | + gopd@1.2.0: {} | |
| 5129 | + | |
| 5130 | + graceful-fs@4.2.11: {} | |
| 5131 | + | |
| 5132 | + has-bigints@1.1.0: {} | |
| 5133 | + | |
| 5134 | + has-flag@4.0.0: {} | |
| 5135 | + | |
| 5136 | + has-property-descriptors@1.0.2: | |
| 5137 | + dependencies: | |
| 5138 | + es-define-property: 1.0.1 | |
| 5139 | + | |
| 5140 | + has-proto@1.2.0: | |
| 5141 | + dependencies: | |
| 5142 | + dunder-proto: 1.0.1 | |
| 5143 | + | |
| 5144 | + has-symbols@1.1.0: {} | |
| 5145 | + | |
| 5146 | + has-tostringtag@1.0.2: | |
| 5147 | + dependencies: | |
| 5148 | + has-symbols: 1.1.0 | |
| 5149 | + | |
| 5150 | + hasown@2.0.4: | |
| 5151 | + dependencies: | |
| 5152 | + function-bind: 1.1.2 | |
| 5153 | + | |
| 5154 | + hermes-estree@0.25.1: {} | |
| 5155 | + | |
| 5156 | + hermes-parser@0.25.1: | |
| 5157 | + dependencies: | |
| 5158 | + hermes-estree: 0.25.1 | |
| 5159 | + | |
| 5160 | + htmlparser2@10.1.0: | |
| 5161 | + dependencies: | |
| 5162 | + domelementtype: 2.3.0 | |
| 5163 | + domhandler: 5.0.3 | |
| 5164 | + domutils: 3.2.2 | |
| 5165 | + entities: 7.0.1 | |
| 5166 | + | |
| 5167 | + iconv-lite@0.6.3: | |
| 5168 | + dependencies: | |
| 5169 | + safer-buffer: 2.1.2 | |
| 5170 | + | |
| 5171 | + ignore@5.3.2: {} | |
| 5172 | + | |
| 5173 | + ignore@7.0.8: {} | |
| 5174 | + | |
| 5175 | + import-fresh@3.3.1: | |
| 5176 | + dependencies: | |
| 5177 | + parent-module: 1.0.1 | |
| 5178 | + resolve-from: 4.0.0 | |
| 5179 | + | |
| 5180 | + imurmurhash@0.1.4: {} | |
| 5181 | + | |
| 5182 | + internal-slot@1.1.0: | |
| 5183 | + dependencies: | |
| 5184 | + es-errors: 1.3.0 | |
| 5185 | + hasown: 2.0.4 | |
| 5186 | + side-channel: 1.1.1 | |
| 5187 | + | |
| 5188 | + is-array-buffer@3.0.5: | |
| 5189 | + dependencies: | |
| 5190 | + call-bind: 1.0.9 | |
| 5191 | + call-bound: 1.0.4 | |
| 5192 | + get-intrinsic: 1.3.0 | |
| 5193 | + | |
| 5194 | + is-async-function@2.1.1: | |
| 5195 | + dependencies: | |
| 5196 | + async-function: 1.0.0 | |
| 5197 | + call-bound: 1.0.4 | |
| 5198 | + get-proto: 1.0.1 | |
| 5199 | + has-tostringtag: 1.0.2 | |
| 5200 | + safe-regex-test: 1.1.0 | |
| 5201 | + | |
| 5202 | + is-bigint@1.1.0: | |
| 5203 | + dependencies: | |
| 5204 | + has-bigints: 1.1.0 | |
| 5205 | + | |
| 5206 | + is-boolean-object@1.2.2: | |
| 5207 | + dependencies: | |
| 5208 | + call-bound: 1.0.4 | |
| 5209 | + has-tostringtag: 1.0.2 | |
| 5210 | + | |
| 5211 | + is-bun-module@2.0.0: | |
| 5212 | + dependencies: | |
| 5213 | + semver: 7.8.5 | |
| 5214 | + | |
| 5215 | + is-callable@1.2.7: {} | |
| 5216 | + | |
| 5217 | + is-core-module@2.16.2: | |
| 5218 | + dependencies: | |
| 5219 | + hasown: 2.0.4 | |
| 5220 | + | |
| 5221 | + is-data-view@1.0.2: | |
| 5222 | + dependencies: | |
| 5223 | + call-bound: 1.0.4 | |
| 5224 | + get-intrinsic: 1.3.0 | |
| 5225 | + is-typed-array: 1.1.15 | |
| 5226 | + | |
| 5227 | + is-date-object@1.1.0: | |
| 5228 | + dependencies: | |
| 5229 | + call-bound: 1.0.4 | |
| 5230 | + has-tostringtag: 1.0.2 | |
| 5231 | + | |
| 5232 | + is-document.all@1.0.0: | |
| 5233 | + dependencies: | |
| 5234 | + call-bound: 1.0.4 | |
| 5235 | + | |
| 5236 | + is-extglob@2.1.1: {} | |
| 5237 | + | |
| 5238 | + is-finalizationregistry@1.1.1: | |
| 5239 | + dependencies: | |
| 5240 | + call-bound: 1.0.4 | |
| 5241 | + | |
| 5242 | + is-generator-function@1.1.2: | |
| 5243 | + dependencies: | |
| 5244 | + call-bound: 1.0.4 | |
| 5245 | + generator-function: 2.0.1 | |
| 5246 | + get-proto: 1.0.1 | |
| 5247 | + has-tostringtag: 1.0.2 | |
| 5248 | + safe-regex-test: 1.1.0 | |
| 5249 | + | |
| 5250 | + is-glob@4.0.3: | |
| 5251 | + dependencies: | |
| 5252 | + is-extglob: 2.1.1 | |
| 5253 | + | |
| 5254 | + is-map@2.0.3: {} | |
| 5255 | + | |
| 5256 | + is-negative-zero@2.0.3: {} | |
| 5257 | + | |
| 5258 | + is-number-object@1.1.1: | |
| 5259 | + dependencies: | |
| 5260 | + call-bound: 1.0.4 | |
| 5261 | + has-tostringtag: 1.0.2 | |
| 5262 | + | |
| 5263 | + is-number@7.0.0: {} | |
| 5264 | + | |
| 5265 | + is-regex@1.2.1: | |
| 5266 | + dependencies: | |
| 5267 | + call-bound: 1.0.4 | |
| 5268 | + gopd: 1.2.0 | |
| 5269 | + has-tostringtag: 1.0.2 | |
| 5270 | + hasown: 2.0.4 | |
| 5271 | + | |
| 5272 | + is-set@2.0.3: {} | |
| 5273 | + | |
| 5274 | + is-shared-array-buffer@1.0.4: | |
| 5275 | + dependencies: | |
| 5276 | + call-bound: 1.0.4 | |
| 5277 | + | |
| 5278 | + is-string@1.1.1: | |
| 5279 | + dependencies: | |
| 5280 | + call-bound: 1.0.4 | |
| 5281 | + has-tostringtag: 1.0.2 | |
| 5282 | + | |
| 5283 | + is-symbol@1.1.1: | |
| 5284 | + dependencies: | |
| 5285 | + call-bound: 1.0.4 | |
| 5286 | + has-symbols: 1.1.0 | |
| 5287 | + safe-regex-test: 1.1.0 | |
| 5288 | + | |
| 5289 | + is-typed-array@1.1.15: | |
| 5290 | + dependencies: | |
| 5291 | + which-typed-array: 1.1.22 | |
| 5292 | + | |
| 5293 | + is-weakmap@2.0.2: {} | |
| 5294 | + | |
| 5295 | + is-weakref@1.1.1: | |
| 5296 | + dependencies: | |
| 5297 | + call-bound: 1.0.4 | |
| 5298 | + | |
| 5299 | + is-weakset@2.0.4: | |
| 5300 | + dependencies: | |
| 5301 | + call-bound: 1.0.4 | |
| 5302 | + get-intrinsic: 1.3.0 | |
| 5303 | + | |
| 5304 | + isarray@2.0.5: {} | |
| 5305 | + | |
| 5306 | + isexe@2.0.0: {} | |
| 5307 | + | |
| 5308 | + iterator.prototype@1.1.5: | |
| 5309 | + dependencies: | |
| 5310 | + define-data-property: 1.1.4 | |
| 5311 | + es-object-atoms: 1.1.2 | |
| 5312 | + get-intrinsic: 1.3.0 | |
| 5313 | + get-proto: 1.0.1 | |
| 5314 | + has-symbols: 1.1.0 | |
| 5315 | + set-function-name: 2.0.2 | |
| 5316 | + | |
| 5317 | + jiti@2.7.0: {} | |
| 5318 | + | |
| 5319 | + js-tokens@4.0.0: {} | |
| 5320 | + | |
| 5321 | + js-tokens@9.0.1: {} | |
| 5322 | + | |
| 5323 | + js-yaml@4.3.2: | |
| 5324 | + dependencies: | |
| 5325 | + argparse: 2.0.1 | |
| 5326 | + | |
| 5327 | + jsesc@3.1.0: {} | |
| 5328 | + | |
| 5329 | + json-buffer@3.0.1: {} | |
| 5330 | + | |
| 5331 | + json-schema-traverse@0.4.1: {} | |
| 5332 | + | |
| 5333 | + json-stable-stringify-without-jsonify@1.0.1: {} | |
| 5334 | + | |
| 5335 | + json5@1.0.2: | |
| 5336 | + dependencies: | |
| 5337 | + minimist: 1.2.8 | |
| 5338 | + | |
| 5339 | + json5@2.2.3: {} | |
| 5340 | + | |
| 5341 | + jsx-ast-utils@3.3.5: | |
| 5342 | + dependencies: | |
| 5343 | + array-includes: 3.1.9 | |
| 5344 | + array.prototype.flat: 1.3.3 | |
| 5345 | + object.assign: 4.1.7 | |
| 5346 | + object.values: 1.2.1 | |
| 5347 | + | |
| 5348 | + keyv@4.5.4: | |
| 5349 | + dependencies: | |
| 5350 | + json-buffer: 3.0.1 | |
| 5351 | + | |
| 5352 | + language-subtag-registry@0.3.23: {} | |
| 5353 | + | |
| 5354 | + language-tags@1.0.9: | |
| 5355 | + dependencies: | |
| 5356 | + language-subtag-registry: 0.3.23 | |
| 5357 | + | |
| 5358 | + levn@0.4.1: | |
| 5359 | + dependencies: | |
| 5360 | + prelude-ls: 1.2.1 | |
| 5361 | + type-check: 0.4.0 | |
| 5362 | + | |
| 5363 | + lightningcss-android-arm64@1.32.0: | |
| 5364 | + optional: true | |
| 5365 | + | |
| 5366 | + lightningcss-darwin-arm64@1.32.0: | |
| 5367 | + optional: true | |
| 5368 | + | |
| 5369 | + lightningcss-darwin-x64@1.32.0: | |
| 5370 | + optional: true | |
| 5371 | + | |
| 5372 | + lightningcss-freebsd-x64@1.32.0: | |
| 5373 | + optional: true | |
| 5374 | + | |
| 5375 | + lightningcss-linux-arm-gnueabihf@1.32.0: | |
| 5376 | + optional: true | |
| 5377 | + | |
| 5378 | + lightningcss-linux-arm64-gnu@1.32.0: | |
| 5379 | + optional: true | |
| 5380 | + | |
| 5381 | + lightningcss-linux-arm64-musl@1.32.0: | |
| 5382 | + optional: true | |
| 5383 | + | |
| 5384 | + lightningcss-linux-x64-gnu@1.32.0: | |
| 5385 | + optional: true | |
| 5386 | + | |
| 5387 | + lightningcss-linux-x64-musl@1.32.0: | |
| 5388 | + optional: true | |
| 5389 | + | |
| 5390 | + lightningcss-win32-arm64-msvc@1.32.0: | |
| 5391 | + optional: true | |
| 5392 | + | |
| 5393 | + lightningcss-win32-x64-msvc@1.32.0: | |
| 5394 | + optional: true | |
| 5395 | + | |
| 5396 | + lightningcss@1.32.0: | |
| 5397 | + dependencies: | |
| 5398 | + detect-libc: 2.1.2 | |
| 5399 | + optionalDependencies: | |
| 5400 | + lightningcss-android-arm64: 1.32.0 | |
| 5401 | + lightningcss-darwin-arm64: 1.32.0 | |
| 5402 | + lightningcss-darwin-x64: 1.32.0 | |
| 5403 | + lightningcss-freebsd-x64: 1.32.0 | |
| 5404 | + lightningcss-linux-arm-gnueabihf: 1.32.0 | |
| 5405 | + lightningcss-linux-arm64-gnu: 1.32.0 | |
| 5406 | + lightningcss-linux-arm64-musl: 1.32.0 | |
| 5407 | + lightningcss-linux-x64-gnu: 1.32.0 | |
| 5408 | + lightningcss-linux-x64-musl: 1.32.0 | |
| 5409 | + lightningcss-win32-arm64-msvc: 1.32.0 | |
| 5410 | + lightningcss-win32-x64-msvc: 1.32.0 | |
| 5411 | + | |
| 5412 | + locate-path@6.0.0: | |
| 5413 | + dependencies: | |
| 5414 | + p-locate: 5.0.0 | |
| 5415 | + | |
| 5416 | + lodash.merge@4.6.2: {} | |
| 5417 | + | |
| 5418 | + loose-envify@1.4.0: | |
| 5419 | + dependencies: | |
| 5420 | + js-tokens: 4.0.0 | |
| 5421 | + | |
| 5422 | + loupe@3.2.1: {} | |
| 5423 | + | |
| 5424 | + lru-cache@5.1.1: | |
| 5425 | + dependencies: | |
| 5426 | + yallist: 3.1.1 | |
| 5427 | + | |
| 5428 | + lucide-react@1.41.0(react@19.2.8): | |
| 5429 | + dependencies: | |
| 5430 | + react: 19.2.8 | |
| 5431 | + | |
| 5432 | + magic-string@0.30.21: | |
| 5433 | + dependencies: | |
| 5434 | + '@jridgewell/sourcemap-codec': 1.6.0 | |
| 5435 | + | |
| 5436 | + math-intrinsics@1.1.0: {} | |
| 5437 | + | |
| 5438 | + merge2@1.4.1: {} | |
| 5439 | + | |
| 5440 | + micromatch@4.0.8: | |
| 5441 | + dependencies: | |
| 5442 | + braces: 3.0.3 | |
| 5443 | + picomatch: 2.3.2 | |
| 5444 | + | |
| 5445 | + minimatch@10.2.6: | |
| 5446 | + dependencies: | |
| 5447 | + brace-expansion: 5.0.9 | |
| 5448 | + | |
| 5449 | + minimatch@3.1.5: | |
| 5450 | + dependencies: | |
| 5451 | + brace-expansion: 1.1.18 | |
| 5452 | + | |
| 5453 | + minimist@1.2.8: {} | |
| 5454 | + | |
| 5455 | + ms@2.1.3: {} | |
| 5456 | + | |
| 5457 | + nanoid@3.3.18: {} | |
| 5458 | + | |
| 5459 | + napi-postinstall@0.3.4: {} | |
| 5460 | + | |
| 5461 | + natural-compare@1.4.0: {} | |
| 5462 | + | |
| 5463 | + next@16.3.4(@babel/core@7.29.7)(@types/node@24.13.3)(react-dom@19.2.8(react@19.2.8))(react@19.2.8): | |
| 5464 | + dependencies: | |
| 5465 | + '@next/env': 16.3.4 | |
| 5466 | + '@swc/helpers': 0.5.23 | |
| 5467 | + baseline-browser-mapping: 2.11.21 | |
| 5468 | + caniuse-lite: 1.0.30001810 | |
| 5469 | + postcss: 8.5.23 | |
| 5470 | + react: 19.2.8 | |
| 5471 | + react-dom: 19.2.8(react@19.2.8) | |
| 5472 | + styled-jsx: 5.1.6(@babel/core@7.29.7)(react@19.2.8) | |
| 5473 | + optionalDependencies: | |
| 5474 | + '@next/swc-darwin-arm64': 16.3.4 | |
| 5475 | + '@next/swc-darwin-x64': 16.3.4 | |
| 5476 | + '@next/swc-linux-arm64-gnu': 16.3.4 | |
| 5477 | + '@next/swc-linux-arm64-musl': 16.3.4 | |
| 5478 | + '@next/swc-linux-x64-gnu': 16.3.4 | |
| 5479 | + '@next/swc-linux-x64-musl': 16.3.4 | |
| 5480 | + '@next/swc-win32-arm64-msvc': 16.3.4 | |
| 5481 | + '@next/swc-win32-x64-msvc': 16.3.4 | |
| 5482 | + sharp: 0.35.4(@types/node@24.13.3) | |
| 5483 | + transitivePeerDependencies: | |
| 5484 | + - '@babel/core' | |
| 5485 | + - '@types/node' | |
| 5486 | + - babel-plugin-macros | |
| 5487 | + | |
| 5488 | + node-exports-info@1.6.2: | |
| 5489 | + dependencies: | |
| 5490 | + array.prototype.flatmap: 1.3.3 | |
| 5491 | + es-errors: 1.3.0 | |
| 5492 | + object.entries: 1.1.9 | |
| 5493 | + semver: 6.3.1 | |
| 5494 | + | |
| 5495 | + node-releases@2.0.54: {} | |
| 5496 | + | |
| 5497 | + nth-check@2.1.1: | |
| 5498 | + dependencies: | |
| 5499 | + boolbase: 1.0.0 | |
| 5500 | + | |
| 5501 | + object-assign@4.1.1: {} | |
| 5502 | + | |
| 5503 | + object-inspect@1.13.4: {} | |
| 5504 | + | |
| 5505 | + object-keys@1.1.1: {} | |
| 5506 | + | |
| 5507 | + object.assign@4.1.7: | |
| 5508 | + dependencies: | |
| 5509 | + call-bind: 1.0.9 | |
| 5510 | + call-bound: 1.0.4 | |
| 5511 | + define-properties: 1.2.1 | |
| 5512 | + es-object-atoms: 1.1.2 | |
| 5513 | + has-symbols: 1.1.0 | |
| 5514 | + object-keys: 1.1.1 | |
| 5515 | + | |
| 5516 | + object.entries@1.1.9: | |
| 5517 | + dependencies: | |
| 5518 | + call-bind: 1.0.9 | |
| 5519 | + call-bound: 1.0.4 | |
| 5520 | + define-properties: 1.2.1 | |
| 5521 | + es-object-atoms: 1.1.2 | |
| 5522 | + | |
| 5523 | + object.fromentries@2.0.8: | |
| 5524 | + dependencies: | |
| 5525 | + call-bind: 1.0.9 | |
| 5526 | + define-properties: 1.2.1 | |
| 5527 | + es-abstract: 1.24.2 | |
| 5528 | + es-object-atoms: 1.1.2 | |
| 5529 | + | |
| 5530 | + object.groupby@1.0.3: | |
| 5531 | + dependencies: | |
| 5532 | + call-bind: 1.0.9 | |
| 5533 | + define-properties: 1.2.1 | |
| 5534 | + es-abstract: 1.24.2 | |
| 5535 | + | |
| 5536 | + object.values@1.2.1: | |
| 5537 | + dependencies: | |
| 5538 | + call-bind: 1.0.9 | |
| 5539 | + call-bound: 1.0.4 | |
| 5540 | + define-properties: 1.2.1 | |
| 5541 | + es-object-atoms: 1.1.2 | |
| 5542 | + | |
| 5543 | + on-exit-leak-free@2.1.2: {} | |
| 5544 | + | |
| 5545 | + optionator@0.9.4: | |
| 5546 | + dependencies: | |
| 5547 | + deep-is: 0.1.4 | |
| 5548 | + fast-levenshtein: 2.0.6 | |
| 5549 | + levn: 0.4.1 | |
| 5550 | + prelude-ls: 1.2.1 | |
| 5551 | + type-check: 0.4.0 | |
| 5552 | + word-wrap: 1.2.5 | |
| 5553 | + | |
| 5554 | + own-keys@1.0.2: | |
| 5555 | + dependencies: | |
| 5556 | + call-bound: 1.0.4 | |
| 5557 | + get-intrinsic: 1.3.0 | |
| 5558 | + object-keys: 1.1.1 | |
| 5559 | + safe-push-apply: 1.0.0 | |
| 5560 | + | |
| 5561 | + p-limit@3.1.0: | |
| 5562 | + dependencies: | |
| 5563 | + yocto-queue: 0.1.0 | |
| 5564 | + | |
| 5565 | + p-locate@5.0.0: | |
| 5566 | + dependencies: | |
| 5567 | + p-limit: 3.1.0 | |
| 5568 | + | |
| 5569 | + parent-module@1.0.1: | |
| 5570 | + dependencies: | |
| 5571 | + callsites: 3.1.0 | |
| 5572 | + | |
| 5573 | + parse5-htmlparser2-tree-adapter@7.1.0: | |
| 5574 | + dependencies: | |
| 5575 | + domhandler: 5.0.3 | |
| 5576 | + parse5: 7.3.0 | |
| 5577 | + | |
| 5578 | + parse5-parser-stream@7.1.2: | |
| 5579 | + dependencies: | |
| 5580 | + parse5: 7.3.0 | |
| 5581 | + | |
| 5582 | + parse5@7.3.0: | |
| 5583 | + dependencies: | |
| 5584 | + entities: 6.0.1 | |
| 5585 | + | |
| 5586 | + path-exists@4.0.0: {} | |
| 5587 | + | |
| 5588 | + path-key@3.1.1: {} | |
| 5589 | + | |
| 5590 | + path-parse@1.0.7: {} | |
| 5591 | + | |
| 5592 | + pathe@2.0.3: {} | |
| 5593 | + | |
| 5594 | + pathval@2.0.1: {} | |
| 5595 | + | |
| 5596 | + picocolors@1.1.1: {} | |
| 5597 | + | |
| 5598 | + picomatch@2.3.2: {} | |
| 5599 | + | |
| 5600 | + picomatch@4.0.7: {} | |
| 5601 | + | |
| 5602 | + pino-abstract-transport@2.0.0: | |
| 5603 | + dependencies: | |
| 5604 | + split2: 4.2.0 | |
| 5605 | + | |
| 5606 | + pino-std-serializers@7.1.0: {} | |
| 5607 | + | |
| 5608 | + pino@9.14.0: | |
| 5609 | + dependencies: | |
| 5610 | + '@pinojs/redact': 0.4.0 | |
| 5611 | + atomic-sleep: 1.0.0 | |
| 5612 | + on-exit-leak-free: 2.1.2 | |
| 5613 | + pino-abstract-transport: 2.0.0 | |
| 5614 | + pino-std-serializers: 7.1.0 | |
| 5615 | + process-warning: 5.1.0 | |
| 5616 | + quick-format-unescaped: 4.0.4 | |
| 5617 | + real-require: 0.2.0 | |
| 5618 | + safe-stable-stringify: 2.5.0 | |
| 5619 | + sonic-boom: 4.2.1 | |
| 5620 | + thread-stream: 3.2.0 | |
| 5621 | + | |
| 5622 | + possible-typed-array-names@1.1.0: {} | |
| 5623 | + | |
| 5624 | + postcss@8.5.23: | |
| 5625 | + dependencies: | |
| 5626 | + nanoid: 3.3.18 | |
| 5627 | + picocolors: 1.1.1 | |
| 5628 | + source-map-js: 1.2.1 | |
| 5629 | + | |
| 5630 | + postcss@8.5.28: | |
| 5631 | + dependencies: | |
| 5632 | + nanoid: 3.3.18 | |
| 5633 | + picocolors: 1.1.1 | |
| 5634 | + source-map-js: 1.2.1 | |
| 5635 | + | |
| 5636 | + postgres@3.4.9: {} | |
| 5637 | + | |
| 5638 | + prelude-ls@1.2.1: {} | |
| 5639 | + | |
| 5640 | + process-warning@5.1.0: {} | |
| 5641 | + | |
| 5642 | + prop-types@15.8.1: | |
| 5643 | + dependencies: | |
| 5644 | + loose-envify: 1.4.0 | |
| 5645 | + object-assign: 4.1.1 | |
| 5646 | + react-is: 16.13.1 | |
| 5647 | + | |
| 5648 | + punycode@2.3.1: {} | |
| 5649 | + | |
| 5650 | + queue-microtask@1.2.3: {} | |
| 5651 | + | |
| 5652 | + quick-format-unescaped@4.0.4: {} | |
| 5653 | + | |
| 5654 | + react-dom@19.2.8(react@19.2.8): | |
| 5655 | + dependencies: | |
| 5656 | + react: 19.2.8 | |
| 5657 | + scheduler: 0.27.0 | |
| 5658 | + | |
| 5659 | + react-is@16.13.1: {} | |
| 5660 | + | |
| 5661 | + react@19.2.8: {} | |
| 5662 | + | |
| 5663 | + real-require@0.2.0: {} | |
| 5664 | + | |
| 5665 | + reflect.getprototypeof@1.0.10: | |
| 5666 | + dependencies: | |
| 5667 | + call-bind: 1.0.9 | |
| 5668 | + define-properties: 1.2.1 | |
| 5669 | + es-abstract: 1.24.2 | |
| 5670 | + es-errors: 1.3.0 | |
| 5671 | + es-object-atoms: 1.1.2 | |
| 5672 | + get-intrinsic: 1.3.0 | |
| 5673 | + get-proto: 1.0.1 | |
| 5674 | + which-builtin-type: 1.2.1 | |
| 5675 | + | |
| 5676 | + regexp.prototype.flags@1.5.4: | |
| 5677 | + dependencies: | |
| 5678 | + call-bind: 1.0.9 | |
| 5679 | + define-properties: 1.2.1 | |
| 5680 | + es-errors: 1.3.0 | |
| 5681 | + get-proto: 1.0.1 | |
| 5682 | + gopd: 1.2.0 | |
| 5683 | + set-function-name: 2.0.2 | |
| 5684 | + | |
| 5685 | + resolve-from@4.0.0: {} | |
| 5686 | + | |
| 5687 | + resolve-pkg-maps@1.0.0: {} | |
| 5688 | + | |
| 5689 | + resolve@2.0.0-next.7: | |
| 5690 | + dependencies: | |
| 5691 | + es-errors: 1.3.0 | |
| 5692 | + is-core-module: 2.16.2 | |
| 5693 | + node-exports-info: 1.6.2 | |
| 5694 | + object-keys: 1.1.1 | |
| 5695 | + path-parse: 1.0.7 | |
| 5696 | + supports-preserve-symlinks-flag: 1.0.0 | |
| 5697 | + | |
| 5698 | + reusify@1.1.0: {} | |
| 5699 | + | |
| 5700 | + rollup@4.63.1: | |
| 5701 | + dependencies: | |
| 5702 | + '@types/estree': 1.0.9 | |
| 5703 | + optionalDependencies: | |
| 5704 | + '@napi-rs/lzma-linux-x64-gnu': 1.5.1 | |
| 5705 | + '@rollup/rollup-android-arm-eabi': 4.63.1 | |
| 5706 | + '@rollup/rollup-android-arm64': 4.63.1 | |
| 5707 | + '@rollup/rollup-darwin-arm64': 4.63.1 | |
| 5708 | + '@rollup/rollup-darwin-x64': 4.63.1 | |
| 5709 | + '@rollup/rollup-freebsd-arm64': 4.63.1 | |
| 5710 | + '@rollup/rollup-freebsd-x64': 4.63.1 | |
| 5711 | + '@rollup/rollup-linux-arm-gnueabihf': 4.63.1 | |
| 5712 | + '@rollup/rollup-linux-arm-musleabihf': 4.63.1 | |
| 5713 | + '@rollup/rollup-linux-arm64-gnu': 4.63.1 | |
| 5714 | + '@rollup/rollup-linux-arm64-musl': 4.63.1 | |
| 5715 | + '@rollup/rollup-linux-loong64-gnu': 4.63.1 | |
| 5716 | + '@rollup/rollup-linux-loong64-musl': 4.63.1 | |
| 5717 | + '@rollup/rollup-linux-ppc64-gnu': 4.63.1 | |
| 5718 | + '@rollup/rollup-linux-ppc64-musl': 4.63.1 | |
| 5719 | + '@rollup/rollup-linux-riscv64-gnu': 4.63.1 | |
| 5720 | + '@rollup/rollup-linux-riscv64-musl': 4.63.1 | |
| 5721 | + '@rollup/rollup-linux-s390x-gnu': 4.63.1 | |
| 5722 | + '@rollup/rollup-linux-x64-gnu': 4.63.1 | |
| 5723 | + '@rollup/rollup-linux-x64-musl': 4.63.1 | |
| 5724 | + '@rollup/rollup-openbsd-x64': 4.63.1 | |
| 5725 | + '@rollup/rollup-openharmony-arm64': 4.63.1 | |
| 5726 | + '@rollup/rollup-win32-arm64-msvc': 4.63.1 | |
| 5727 | + '@rollup/rollup-win32-ia32-msvc': 4.63.1 | |
| 5728 | + '@rollup/rollup-win32-x64-gnu': 4.63.1 | |
| 5729 | + '@rollup/rollup-win32-x64-msvc': 4.63.1 | |
| 5730 | + fsevents: 2.3.3 | |
| 5731 | + | |
| 5732 | + run-parallel@1.2.0: | |
| 5733 | + dependencies: | |
| 5734 | + queue-microtask: 1.2.3 | |
| 5735 | + | |
| 5736 | + safe-array-concat@1.1.4: | |
| 5737 | + dependencies: | |
| 5738 | + call-bind: 1.0.9 | |
| 5739 | + call-bound: 1.0.4 | |
| 5740 | + get-intrinsic: 1.3.0 | |
| 5741 | + has-symbols: 1.1.0 | |
| 5742 | + isarray: 2.0.5 | |
| 5743 | + | |
| 5744 | + safe-push-apply@1.0.0: | |
| 5745 | + dependencies: | |
| 5746 | + es-errors: 1.3.0 | |
| 5747 | + isarray: 2.0.5 | |
| 5748 | + | |
| 5749 | + safe-regex-test@1.1.0: | |
| 5750 | + dependencies: | |
| 5751 | + call-bound: 1.0.4 | |
| 5752 | + es-errors: 1.3.0 | |
| 5753 | + is-regex: 1.2.1 | |
| 5754 | + | |
| 5755 | + safe-stable-stringify@2.5.0: {} | |
| 5756 | + | |
| 5757 | + safer-buffer@2.1.2: {} | |
| 5758 | + | |
| 5759 | + scheduler@0.27.0: {} | |
| 5760 | + | |
| 5761 | + semver@6.3.1: {} | |
| 5762 | + | |
| 5763 | + semver@7.8.5: {} | |
| 5764 | + | |
| 5765 | + server-only@0.0.1: {} | |
| 5766 | + | |
| 5767 | + set-function-length@1.2.2: | |
| 5768 | + dependencies: | |
| 5769 | + define-data-property: 1.1.4 | |
| 5770 | + es-errors: 1.3.0 | |
| 5771 | + function-bind: 1.1.2 | |
| 5772 | + get-intrinsic: 1.3.0 | |
| 5773 | + gopd: 1.2.0 | |
| 5774 | + has-property-descriptors: 1.0.2 | |
| 5775 | + | |
| 5776 | + set-function-name@2.0.2: | |
| 5777 | + dependencies: | |
| 5778 | + define-data-property: 1.1.4 | |
| 5779 | + es-errors: 1.3.0 | |
| 5780 | + functions-have-names: 1.2.3 | |
| 5781 | + has-property-descriptors: 1.0.2 | |
| 5782 | + | |
| 5783 | + set-proto@1.0.0: | |
| 5784 | + dependencies: | |
| 5785 | + dunder-proto: 1.0.1 | |
| 5786 | + es-errors: 1.3.0 | |
| 5787 | + es-object-atoms: 1.1.2 | |
| 5788 | + | |
| 5789 | + sharp@0.35.4(@types/node@24.13.3): | |
| 5790 | + dependencies: | |
| 5791 | + '@img/colour': 1.1.0 | |
| 5792 | + detect-libc: 2.1.2 | |
| 5793 | + semver: 7.8.5 | |
| 5794 | + optionalDependencies: | |
| 5795 | + '@img/sharp-darwin-arm64': 0.35.4 | |
| 5796 | + '@img/sharp-darwin-x64': 0.35.4 | |
| 5797 | + '@img/sharp-freebsd-wasm32': 0.35.4 | |
| 5798 | + '@img/sharp-libvips-darwin-arm64': 1.3.3 | |
| 5799 | + '@img/sharp-libvips-darwin-x64': 1.3.3 | |
| 5800 | + '@img/sharp-libvips-linux-arm': 1.3.3 | |
| 5801 | + '@img/sharp-libvips-linux-arm64': 1.3.3 | |
| 5802 | + '@img/sharp-libvips-linux-ppc64': 1.3.3 | |
| 5803 | + '@img/sharp-libvips-linux-riscv64': 1.3.3 | |
| 5804 | + '@img/sharp-libvips-linux-s390x': 1.3.3 | |
| 5805 | + '@img/sharp-libvips-linux-x64': 1.3.3 | |
| 5806 | + '@img/sharp-libvips-linuxmusl-arm64': 1.3.3 | |
| 5807 | + '@img/sharp-libvips-linuxmusl-x64': 1.3.3 | |
| 5808 | + '@img/sharp-linux-arm': 0.35.4 | |
| 5809 | + '@img/sharp-linux-arm64': 0.35.4 | |
| 5810 | + '@img/sharp-linux-ppc64': 0.35.4 | |
| 5811 | + '@img/sharp-linux-riscv64': 0.35.4 | |
| 5812 | + '@img/sharp-linux-s390x': 0.35.4 | |
| 5813 | + '@img/sharp-linux-x64': 0.35.4 | |
| 5814 | + '@img/sharp-linuxmusl-arm64': 0.35.4 | |
| 5815 | + '@img/sharp-linuxmusl-x64': 0.35.4 | |
| 5816 | + '@img/sharp-webcontainers-wasm32': 0.35.4 | |
| 5817 | + '@img/sharp-win32-arm64': 0.35.4 | |
| 5818 | + '@img/sharp-win32-ia32': 0.35.4 | |
| 5819 | + '@img/sharp-win32-x64': 0.35.4 | |
| 5820 | + '@types/node': 24.13.3 | |
| 5821 | + optional: true | |
| 5822 | + | |
| 5823 | + shebang-command@2.0.0: | |
| 5824 | + dependencies: | |
| 5825 | + shebang-regex: 3.0.0 | |
| 5826 | + | |
| 5827 | + shebang-regex@3.0.0: {} | |
| 5828 | + | |
| 5829 | + side-channel-list@1.0.1: | |
| 5830 | + dependencies: | |
| 5831 | + es-errors: 1.3.0 | |
| 5832 | + object-inspect: 1.13.4 | |
| 5833 | + | |
| 5834 | + side-channel-map@1.0.1: | |
| 5835 | + dependencies: | |
| 5836 | + call-bound: 1.0.4 | |
| 5837 | + es-errors: 1.3.0 | |
| 5838 | + get-intrinsic: 1.3.0 | |
| 5839 | + object-inspect: 1.13.4 | |
| 5840 | + | |
| 5841 | + side-channel-weakmap@1.0.2: | |
| 5842 | + dependencies: | |
| 5843 | + call-bound: 1.0.4 | |
| 5844 | + es-errors: 1.3.0 | |
| 5845 | + get-intrinsic: 1.3.0 | |
| 5846 | + object-inspect: 1.13.4 | |
| 5847 | + side-channel-map: 1.0.1 | |
| 5848 | + | |
| 5849 | + side-channel@1.1.1: | |
| 5850 | + dependencies: | |
| 5851 | + es-errors: 1.3.0 | |
| 5852 | + object-inspect: 1.13.4 | |
| 5853 | + side-channel-list: 1.0.1 | |
| 5854 | + side-channel-map: 1.0.1 | |
| 5855 | + side-channel-weakmap: 1.0.2 | |
| 5856 | + | |
| 5857 | + siginfo@2.0.0: {} | |
| 5858 | + | |
| 5859 | + sonic-boom@4.2.1: | |
| 5860 | + dependencies: | |
| 5861 | + atomic-sleep: 1.0.0 | |
| 5862 | + | |
| 5863 | + source-map-js@1.2.1: {} | |
| 5864 | + | |
| 5865 | + source-map-support@0.5.21: | |
| 5866 | + dependencies: | |
| 5867 | + buffer-from: 1.1.2 | |
| 5868 | + source-map: 0.6.1 | |
| 5869 | + | |
| 5870 | + source-map@0.6.1: {} | |
| 5871 | + | |
| 5872 | + split2@4.2.0: {} | |
| 5873 | + | |
| 5874 | + stable-hash@0.0.5: {} | |
| 5875 | + | |
| 5876 | + stackback@0.0.2: {} | |
| 5877 | + | |
| 5878 | + std-env@3.10.0: {} | |
| 5879 | + | |
| 5880 | + stop-iteration-iterator@1.1.0: | |
| 5881 | + dependencies: | |
| 5882 | + es-errors: 1.3.0 | |
| 5883 | + internal-slot: 1.1.0 | |
| 5884 | + | |
| 5885 | + string.prototype.includes@2.0.1: | |
| 5886 | + dependencies: | |
| 5887 | + call-bind: 1.0.9 | |
| 5888 | + define-properties: 1.2.1 | |
| 5889 | + es-abstract: 1.24.2 | |
| 5890 | + | |
| 5891 | + string.prototype.matchall@4.1.0: | |
| 5892 | + dependencies: | |
| 5893 | + call-bind: 1.0.9 | |
| 5894 | + call-bound: 1.0.4 | |
| 5895 | + define-properties: 1.2.1 | |
| 5896 | + es-abstract: 1.24.2 | |
| 5897 | + es-errors: 1.3.0 | |
| 5898 | + es-object-atoms: 1.1.2 | |
| 5899 | + get-intrinsic: 1.3.0 | |
| 5900 | + gopd: 1.2.0 | |
| 5901 | + has-symbols: 1.1.0 | |
| 5902 | + internal-slot: 1.1.0 | |
| 5903 | + regexp.prototype.flags: 1.5.4 | |
| 5904 | + set-function-name: 2.0.2 | |
| 5905 | + side-channel: 1.1.1 | |
| 5906 | + | |
| 5907 | + string.prototype.repeat@1.0.0: | |
| 5908 | + dependencies: | |
| 5909 | + define-properties: 1.2.1 | |
| 5910 | + es-abstract: 1.24.2 | |
| 5911 | + | |
| 5912 | + string.prototype.trim@1.2.11: | |
| 5913 | + dependencies: | |
| 5914 | + call-bind: 1.0.9 | |
| 5915 | + call-bound: 1.0.4 | |
| 5916 | + define-data-property: 1.1.4 | |
| 5917 | + define-properties: 1.2.1 | |
| 5918 | + es-abstract: 1.24.2 | |
| 5919 | + es-object-atoms: 1.1.2 | |
| 5920 | + has-property-descriptors: 1.0.2 | |
| 5921 | + safe-regex-test: 1.1.0 | |
| 5922 | + | |
| 5923 | + string.prototype.trimend@1.0.10: | |
| 5924 | + dependencies: | |
| 5925 | + call-bind: 1.0.9 | |
| 5926 | + call-bound: 1.0.4 | |
| 5927 | + define-properties: 1.2.1 | |
| 5928 | + es-object-atoms: 1.1.2 | |
| 5929 | + | |
| 5930 | + string.prototype.trimstart@1.0.8: | |
| 5931 | + dependencies: | |
| 5932 | + call-bind: 1.0.9 | |
| 5933 | + define-properties: 1.2.1 | |
| 5934 | + es-object-atoms: 1.1.2 | |
| 5935 | + | |
| 5936 | + strip-bom@3.0.0: {} | |
| 5937 | + | |
| 5938 | + strip-json-comments@3.1.1: {} | |
| 5939 | + | |
| 5940 | + strip-literal@3.1.0: | |
| 5941 | + dependencies: | |
| 5942 | + js-tokens: 9.0.1 | |
| 5943 | + | |
| 5944 | + styled-jsx@5.1.6(@babel/core@7.29.7)(react@19.2.8): | |
| 5945 | + dependencies: | |
| 5946 | + client-only: 0.0.1 | |
| 5947 | + react: 19.2.8 | |
| 5948 | + optionalDependencies: | |
| 5949 | + '@babel/core': 7.29.7 | |
| 5950 | + | |
| 5951 | + supports-color@7.2.0: | |
| 5952 | + dependencies: | |
| 5953 | + has-flag: 4.0.0 | |
| 5954 | + | |
| 5955 | + supports-preserve-symlinks-flag@1.0.0: {} | |
| 5956 | + | |
| 5957 | + tailwindcss@4.3.3: {} | |
| 5958 | + | |
| 5959 | + tapable@2.3.3: {} | |
| 5960 | + | |
| 5961 | + thread-stream@3.2.0: | |
| 5962 | + dependencies: | |
| 5963 | + real-require: 0.2.0 | |
| 5964 | + | |
| 5965 | + tinybench@2.9.0: {} | |
| 5966 | + | |
| 5967 | + tinyexec@0.3.2: {} | |
| 5968 | + | |
| 5969 | + tinyglobby@0.2.17: | |
| 5970 | + dependencies: | |
| 5971 | + fdir: 6.5.0(picomatch@4.0.7) | |
| 5972 | + picomatch: 4.0.7 | |
| 5973 | + | |
| 5974 | + tinypool@1.1.1: {} | |
| 5975 | + | |
| 5976 | + tinyrainbow@2.0.0: {} | |
| 5977 | + | |
| 5978 | + tinyspy@4.0.6: {} | |
| 5979 | + | |
| 5980 | + to-regex-range@5.0.1: | |
| 5981 | + dependencies: | |
| 5982 | + is-number: 7.0.0 | |
| 5983 | + | |
| 5984 | + ts-api-utils@2.5.0(typescript@5.9.3): | |
| 5985 | + dependencies: | |
| 5986 | + typescript: 5.9.3 | |
| 5987 | + | |
| 5988 | + tsconfig-paths@3.15.0: | |
| 5989 | + dependencies: | |
| 5990 | + '@types/json5': 0.0.29 | |
| 5991 | + json5: 1.0.2 | |
| 5992 | + minimist: 1.2.8 | |
| 5993 | + strip-bom: 3.0.0 | |
| 5994 | + | |
| 5995 | + tslib@2.8.1: {} | |
| 5996 | + | |
| 5997 | + tsx@4.23.13: | |
| 5998 | + dependencies: | |
| 5999 | + esbuild: 0.28.2 | |
| 6000 | + optionalDependencies: | |
| 6001 | + fsevents: 2.3.3 | |
| 6002 | + | |
| 6003 | + type-check@0.4.0: | |
| 6004 | + dependencies: | |
| 6005 | + prelude-ls: 1.2.1 | |
| 6006 | + | |
| 6007 | + typed-array-buffer@1.0.3: | |
| 6008 | + dependencies: | |
| 6009 | + call-bound: 1.0.4 | |
| 6010 | + es-errors: 1.3.0 | |
| 6011 | + is-typed-array: 1.1.15 | |
| 6012 | + | |
| 6013 | + typed-array-byte-length@1.0.3: | |
| 6014 | + dependencies: | |
| 6015 | + call-bind: 1.0.9 | |
| 6016 | + for-each: 0.3.5 | |
| 6017 | + gopd: 1.2.0 | |
| 6018 | + has-proto: 1.2.0 | |
| 6019 | + is-typed-array: 1.1.15 | |
| 6020 | + | |
| 6021 | + typed-array-byte-offset@1.0.4: | |
| 6022 | + dependencies: | |
| 6023 | + available-typed-arrays: 1.0.7 | |
| 6024 | + call-bind: 1.0.9 | |
| 6025 | + for-each: 0.3.5 | |
| 6026 | + gopd: 1.2.0 | |
| 6027 | + has-proto: 1.2.0 | |
| 6028 | + is-typed-array: 1.1.15 | |
| 6029 | + reflect.getprototypeof: 1.0.10 | |
| 6030 | + | |
| 6031 | + typed-array-length@1.0.8: | |
| 6032 | + dependencies: | |
| 6033 | + call-bind: 1.0.9 | |
| 6034 | + for-each: 0.3.5 | |
| 6035 | + gopd: 1.2.0 | |
| 6036 | + is-typed-array: 1.1.15 | |
| 6037 | + possible-typed-array-names: 1.1.0 | |
| 6038 | + reflect.getprototypeof: 1.0.10 | |
| 6039 | + | |
| 6040 | + typescript-eslint@8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3): | |
| 6041 | + dependencies: | |
| 6042 | + '@typescript-eslint/eslint-plugin': 8.69.0(@typescript-eslint/parser@8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) | |
| 6043 | + '@typescript-eslint/parser': 8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) | |
| 6044 | + '@typescript-eslint/typescript-estree': 8.69.0(typescript@5.9.3) | |
| 6045 | + '@typescript-eslint/utils': 8.69.0(eslint@9.39.5(jiti@2.7.0))(typescript@5.9.3) | |
| 6046 | + eslint: 9.39.5(jiti@2.7.0) | |
| 6047 | + typescript: 5.9.3 | |
| 6048 | + transitivePeerDependencies: | |
| 6049 | + - supports-color | |
| 6050 | + | |
| 6051 | + typescript@5.9.3: {} | |
| 6052 | + | |
| 6053 | + unbox-primitive@1.1.0: | |
| 6054 | + dependencies: | |
| 6055 | + call-bound: 1.0.4 | |
| 6056 | + has-bigints: 1.1.0 | |
| 6057 | + has-symbols: 1.1.0 | |
| 6058 | + which-boxed-primitive: 1.1.1 | |
| 6059 | + | |
| 6060 | + undici-types@7.18.2: {} | |
| 6061 | + | |
| 6062 | + undici@7.29.1: {} | |
| 6063 | + | |
| 6064 | + unrs-resolver@1.12.2: | |
| 6065 | + dependencies: | |
| 6066 | + napi-postinstall: 0.3.4 | |
| 6067 | + optionalDependencies: | |
| 6068 | + '@unrs/resolver-binding-android-arm-eabi': 1.12.2 | |
| 6069 | + '@unrs/resolver-binding-android-arm64': 1.12.2 | |
| 6070 | + '@unrs/resolver-binding-darwin-arm64': 1.12.2 | |
| 6071 | + '@unrs/resolver-binding-darwin-x64': 1.12.2 | |
| 6072 | + '@unrs/resolver-binding-freebsd-x64': 1.12.2 | |
| 6073 | + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.12.2 | |
| 6074 | + '@unrs/resolver-binding-linux-arm-musleabihf': 1.12.2 | |
| 6075 | + '@unrs/resolver-binding-linux-arm64-gnu': 1.12.2 | |
| 6076 | + '@unrs/resolver-binding-linux-arm64-musl': 1.12.2 | |
| 6077 | + '@unrs/resolver-binding-linux-loong64-gnu': 1.12.2 | |
| 6078 | + '@unrs/resolver-binding-linux-loong64-musl': 1.12.2 | |
| 6079 | + '@unrs/resolver-binding-linux-ppc64-gnu': 1.12.2 | |
| 6080 | + '@unrs/resolver-binding-linux-riscv64-gnu': 1.12.2 | |
| 6081 | + '@unrs/resolver-binding-linux-riscv64-musl': 1.12.2 | |
| 6082 | + '@unrs/resolver-binding-linux-s390x-gnu': 1.12.2 | |
| 6083 | + '@unrs/resolver-binding-linux-x64-gnu': 1.12.2 | |
| 6084 | + '@unrs/resolver-binding-linux-x64-musl': 1.12.2 | |
| 6085 | + '@unrs/resolver-binding-openharmony-arm64': 1.12.2 | |
| 6086 | + '@unrs/resolver-binding-wasm32-wasi': 1.12.2 | |
| 6087 | + '@unrs/resolver-binding-win32-arm64-msvc': 1.12.2 | |
| 6088 | + '@unrs/resolver-binding-win32-ia32-msvc': 1.12.2 | |
| 6089 | + '@unrs/resolver-binding-win32-x64-msvc': 1.12.2 | |
| 6090 | + | |
| 6091 | + update-browserslist-db@1.3.2(browserslist@4.28.9): | |
| 6092 | + dependencies: | |
| 6093 | + browserslist: 4.28.9 | |
| 6094 | + escalade: 3.2.0 | |
| 6095 | + picocolors: 1.1.1 | |
| 6096 | + | |
| 6097 | + uri-js@4.4.1: | |
| 6098 | + dependencies: | |
| 6099 | + punycode: 2.3.1 | |
| 6100 | + | |
| 6101 | + vite-node@3.2.4(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.13): | |
| 6102 | + dependencies: | |
| 6103 | + cac: 6.7.14 | |
| 6104 | + debug: 4.4.3 | |
| 6105 | + es-module-lexer: 1.7.0 | |
| 6106 | + pathe: 2.0.3 | |
| 6107 | + vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.13) | |
| 6108 | + transitivePeerDependencies: | |
| 6109 | + - '@types/node' | |
| 6110 | + - jiti | |
| 6111 | + - less | |
| 6112 | + - lightningcss | |
| 6113 | + - sass | |
| 6114 | + - sass-embedded | |
| 6115 | + - stylus | |
| 6116 | + - sugarss | |
| 6117 | + - supports-color | |
| 6118 | + - terser | |
| 6119 | + - tsx | |
| 6120 | + - yaml | |
| 6121 | + | |
| 6122 | + vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.13): | |
| 6123 | + dependencies: | |
| 6124 | + esbuild: 0.28.2 | |
| 6125 | + fdir: 6.5.0(picomatch@4.0.7) | |
| 6126 | + picomatch: 4.0.7 | |
| 6127 | + postcss: 8.5.28 | |
| 6128 | + rollup: 4.63.1 | |
| 6129 | + tinyglobby: 0.2.17 | |
| 6130 | + optionalDependencies: | |
| 6131 | + '@types/node': 24.13.3 | |
| 6132 | + fsevents: 2.3.3 | |
| 6133 | + jiti: 2.7.0 | |
| 6134 | + lightningcss: 1.32.0 | |
| 6135 | + tsx: 4.23.13 | |
| 6136 | + | |
| 6137 | + vitest@3.2.7(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.13): | |
| 6138 | + dependencies: | |
| 6139 | + '@types/chai': 5.2.3 | |
| 6140 | + '@vitest/expect': 3.2.7 | |
| 6141 | + '@vitest/mocker': 3.2.7(vite@7.3.6(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.13)) | |
| 6142 | + '@vitest/pretty-format': 3.2.7 | |
| 6143 | + '@vitest/runner': 3.2.7 | |
| 6144 | + '@vitest/snapshot': 3.2.7 | |
| 6145 | + '@vitest/spy': 3.2.7 | |
| 6146 | + '@vitest/utils': 3.2.7 | |
| 6147 | + chai: 5.3.3 | |
| 6148 | + debug: 4.4.3 | |
| 6149 | + expect-type: 1.4.0 | |
| 6150 | + magic-string: 0.30.21 | |
| 6151 | + pathe: 2.0.3 | |
| 6152 | + picomatch: 4.0.7 | |
| 6153 | + std-env: 3.10.0 | |
| 6154 | + tinybench: 2.9.0 | |
| 6155 | + tinyexec: 0.3.2 | |
| 6156 | + tinyglobby: 0.2.17 | |
| 6157 | + tinypool: 1.1.1 | |
| 6158 | + tinyrainbow: 2.0.0 | |
| 6159 | + vite: 7.3.6(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.13) | |
| 6160 | + vite-node: 3.2.4(@types/node@24.13.3)(jiti@2.7.0)(lightningcss@1.32.0)(tsx@4.23.13) | |
| 6161 | + why-is-node-running: 2.3.0 | |
| 6162 | + optionalDependencies: | |
| 6163 | + '@types/node': 24.13.3 | |
| 6164 | + transitivePeerDependencies: | |
| 6165 | + - jiti | |
| 6166 | + - less | |
| 6167 | + - lightningcss | |
| 6168 | + - msw | |
| 6169 | + - sass | |
| 6170 | + - sass-embedded | |
| 6171 | + - stylus | |
| 6172 | + - sugarss | |
| 6173 | + - supports-color | |
| 6174 | + - terser | |
| 6175 | + - tsx | |
| 6176 | + - yaml | |
| 6177 | + | |
| 6178 | + whatwg-encoding@3.1.1: | |
| 6179 | + dependencies: | |
| 6180 | + iconv-lite: 0.6.3 | |
| 6181 | + | |
| 6182 | + whatwg-mimetype@4.0.0: {} | |
| 6183 | + | |
| 6184 | + which-boxed-primitive@1.1.1: | |
| 6185 | + dependencies: | |
| 6186 | + is-bigint: 1.1.0 | |
| 6187 | + is-boolean-object: 1.2.2 | |
| 6188 | + is-number-object: 1.1.1 | |
| 6189 | + is-string: 1.1.1 | |
| 6190 | + is-symbol: 1.1.1 | |
| 6191 | + | |
| 6192 | + which-builtin-type@1.2.1: | |
| 6193 | + dependencies: | |
| 6194 | + call-bound: 1.0.4 | |
| 6195 | + function.prototype.name: 1.2.0 | |
| 6196 | + has-tostringtag: 1.0.2 | |
| 6197 | + is-async-function: 2.1.1 | |
| 6198 | + is-date-object: 1.1.0 | |
| 6199 | + is-finalizationregistry: 1.1.1 | |
| 6200 | + is-generator-function: 1.1.2 | |
| 6201 | + is-regex: 1.2.1 | |
| 6202 | + is-weakref: 1.1.1 | |
| 6203 | + isarray: 2.0.5 | |
| 6204 | + which-boxed-primitive: 1.1.1 | |
| 6205 | + which-collection: 1.0.2 | |
| 6206 | + which-typed-array: 1.1.22 | |
| 6207 | + | |
| 6208 | + which-collection@1.0.2: | |
| 6209 | + dependencies: | |
| 6210 | + is-map: 2.0.3 | |
| 6211 | + is-set: 2.0.3 | |
| 6212 | + is-weakmap: 2.0.2 | |
| 6213 | + is-weakset: 2.0.4 | |
| 6214 | + | |
| 6215 | + which-typed-array@1.1.22: | |
| 6216 | + dependencies: | |
| 6217 | + available-typed-arrays: 1.0.7 | |
| 6218 | + call-bind: 1.0.9 | |
| 6219 | + call-bound: 1.0.4 | |
| 6220 | + for-each: 0.3.5 | |
| 6221 | + get-proto: 1.0.1 | |
| 6222 | + gopd: 1.2.0 | |
| 6223 | + has-tostringtag: 1.0.2 | |
| 6224 | + | |
| 6225 | + which@2.0.2: | |
| 6226 | + dependencies: | |
| 6227 | + isexe: 2.0.0 | |
| 6228 | + | |
| 6229 | + why-is-node-running@2.3.0: | |
| 6230 | + dependencies: | |
| 6231 | + siginfo: 2.0.0 | |
| 6232 | + stackback: 0.0.2 | |
| 6233 | + | |
| 6234 | + word-wrap@1.2.5: {} | |
| 6235 | + | |
| 6236 | + yallist@3.1.1: {} | |
| 6237 | + | |
| 6238 | + yocto-queue@0.1.0: {} | |
| 6239 | + | |
| 6240 | + zod-validation-error@4.0.2(zod@4.5.4): | |
| 6241 | + dependencies: | |
| 6242 | + zod: 4.5.4 | |
| 6243 | + | |
| 6244 | + zod@4.5.4: {} | |
added
pnpm-workspace.yaml
+5 −0
@@ -0,0 +1,5 @@ | ||
| 1 | +packages: | |
| 2 | + - apps/* | |
| 3 | + - packages/* | |
| 4 | + - workers | |
| 5 | + - connectors | |
added
scripts/build-registry.ts
+33 −0
@@ -0,0 +1,33 @@ | ||
| 1 | +/** | |
| 2 | + * Assemble connectors/registry.json from every connectors/<engine>/<id>/meta.json. | |
| 3 | + * Per-connector meta files avoid merge conflicts; registry.json stays the machine-readable | |
| 4 | + * registry required by CLAUDE.md §106. Run: pnpm tsx scripts/build-registry.ts | |
| 5 | + */ | |
| 6 | +import { readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs'; | |
| 7 | +import path from 'node:path'; | |
| 8 | +import { fileURLToPath } from 'node:url'; | |
| 9 | +import { RegistrySchema, ConnectorMetaSchema } from '../packages/connectors/src/types.ts'; | |
| 10 | + | |
| 11 | +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); | |
| 12 | +const dir = path.join(root, 'connectors'); | |
| 13 | +const metas: unknown[] = []; | |
| 14 | +for (const engine of readdirSync(dir)) { | |
| 15 | + const p = path.join(dir, engine); | |
| 16 | + if (!statSync(p).isDirectory() || engine === 'node_modules') continue; | |
| 17 | + for (const id of readdirSync(p)) { | |
| 18 | + const metaPath = path.join(p, id, 'meta.json'); | |
| 19 | + try { | |
| 20 | + const meta = JSON.parse(readFileSync(metaPath, 'utf8')); | |
| 21 | + const parsed = ConnectorMetaSchema.parse({ ...meta, module: meta.module ?? `${engine}/${id}` }); | |
| 22 | + if (parsed.id !== id) throw new Error(`meta.id ${parsed.id} ≠ folder ${id}`); | |
| 23 | + metas.push(parsed); | |
| 24 | + } catch (err) { | |
| 25 | + if ((err as NodeJS.ErrnoException).code === 'ENOENT') continue; | |
| 26 | + throw new Error(`${metaPath}: ${err instanceof Error ? err.message : String(err)}`); | |
| 27 | + } | |
| 28 | + } | |
| 29 | +} | |
| 30 | +metas.sort((a, b) => ((a as { id: string }).id < (b as { id: string }).id ? -1 : 1)); | |
| 31 | +const registry = RegistrySchema.parse({ version: '1.0', connectors: metas }); | |
| 32 | +writeFileSync(path.join(dir, 'registry.json'), JSON.stringify(registry, null, 2) + '\n'); | |
| 33 | +console.log(`[registry] ${registry.connectors.length} connectors written to connectors/registry.json`); | |
added
tsconfig.base.json
+22 −0
@@ -0,0 +1,22 @@ | ||
| 1 | +{ | |
| 2 | + "compilerOptions": { | |
| 3 | + "target": "ES2023", | |
| 4 | + "lib": ["ES2023"], | |
| 5 | + "module": "NodeNext", | |
| 6 | + "moduleResolution": "NodeNext", | |
| 7 | + "strict": true, | |
| 8 | + "noUncheckedIndexedAccess": true, | |
| 9 | + "noImplicitOverride": true, | |
| 10 | + "noFallthroughCasesInSwitch": true, | |
| 11 | + "exactOptionalPropertyTypes": false, | |
| 12 | + "esModuleInterop": true, | |
| 13 | + "skipLibCheck": true, | |
| 14 | + "resolveJsonModule": true, | |
| 15 | + "declaration": true, | |
| 16 | + "declarationMap": true, | |
| 17 | + "sourceMap": true, | |
| 18 | + "isolatedModules": true, | |
| 19 | + "verbatimModuleSyntax": true, | |
| 20 | + "forceConsistentCasingInFileNames": true | |
| 21 | + } | |
| 22 | +} | |
added
vitest.workspace.ts
+6 −0
@@ -0,0 +1,6 @@ | ||
| 1 | +export default [ | |
| 2 | + 'packages/*/vitest.config.ts', | |
| 3 | + 'connectors/vitest.config.ts', | |
| 4 | + 'workers/vitest.config.ts', | |
| 5 | + 'apps/api/vitest.config.ts', | |
| 6 | +]; | |
added
workers/package.json
+1 −0
@@ -0,0 +1 @@ | ||
| 1 | +{"name":"@rareindex/workers","version":"0.1.0","private":true,"type":"module","scripts":{"typecheck":"tsc -p tsconfig.json --noEmit","test":"vitest run --passWithNoTests"},"dependencies":{"@rareindex/shared":"workspace:*"},"devDependencies":{"@types/node":"^24.0.0","typescript":"^5.9.3","vitest":"^3.2.0"}} | |
| 2 | ||