diff --git a/.cursor/commands/do-it-right.md b/.cursor/commands/do-it-right.md deleted file mode 100644 index 30cbe271..00000000 --- a/.cursor/commands/do-it-right.md +++ /dev/null @@ -1,15 +0,0 @@ -# do-it-right - -NON-NEGOTIABLE RULES: - -You should not start to create: - -1. Helper methods -2. Abstractions -3. Additional complexity - -It is much more useful to keep everything in place, close together while we are first trying to make things correct, before we start adding obscurity. - -And do not touch any code not directly relevant to the current task/problem. - -Focus on the task you have been given and write highly relevant, effective, and rigerous tests that prove that what you are delivering actually works. \ No newline at end of file diff --git a/.cursor/commands/review.md b/.cursor/commands/review.md deleted file mode 100644 index efaa5bac..00000000 --- a/.cursor/commands/review.md +++ /dev/null @@ -1,33 +0,0 @@ -# review - -THE OVERALL SYSTEM WORKS LIKE THIS: - -1. Signals convert raw market data into Measurement - Each Signal MUST emit a Measurement on each Tick, which includes a CONFIDENCE, and SNR (SURPRISE) - Each Signal decides for themselves which asset pairs to subscribe to. -2. Measurements are picked up by the Story - The Story uses Measurements to run a decision Tree and Branches, which can results in an Action -3. The trader acts upon those Actions via the broker Desk -4. The paper websocket emulation takes care of everything that is different between paper and live trading - -WHAT YOU SHOULD NOT DO: - -1. Do NOT create frivolous files, helper methods, or abstractions -2. Do NOT ignore the rules in @AGENTS.md -3. Do NOT hide flaws, silence errors (always use errnie.Error(err)), or use silent fallbacks -4. Do NOT change any code that is not part of what you are solving, your opinion is not useful -5. Do NOT restore code from git, also not by memory, always look forwards not backwards - -WHAT YOU SHOULD DO: - -1. Let the system fail and halt immediately the moment something isn't as it is supposed to be -2. Provide the minimal amount of changes for a correct solution -3. Build on the existing code, and provide your best quality solutions -4. Make sure your tests are highly relevant, useful, and test edge conditions and adverserial scenarios -5. Verify everything is working before you deliver - -COMPLEXITY IS EARNED, DO NOT UNDER ANY CIRCUMSTANCE INTRODUCE MORE THAN ABSOLUTELY NEEDED! - -1. Please perform in-depth and critical review of this project according to @AGENTS.md -2. Resolve any issues you encounter correctly, with a high-quality solution, and tests -3. Refactor any code that can be simplified (without losing functionality), and remove duplication \ No newline at end of file diff --git a/.cursor/rules/ponytail.mdc b/.cursor/rules/ponytail.mdc deleted file mode 100644 index 09c66998..00000000 --- a/.cursor/rules/ponytail.mdc +++ /dev/null @@ -1,30 +0,0 @@ ---- -description: Ponytail, lazy senior dev mode. Always pick the simplest solution that works. -globs: -alwaysApply: true ---- - -# Ponytail, lazy senior dev mode - -You are a lazy senior developer. Lazy means efficient, not careless. The best code is the code never written. - -Before writing any code, stop at the first rung that holds: - -1. Does this need to be built at all? (YAGNI) -2. Does the standard library already do this? Use it. -3. Does a native platform feature cover it? Use it. -4. Does an already-installed dependency solve it? Use it. -5. Can this be one line? Make it one line. -6. Only then: write the minimum code that works. - -Rules: - -- No abstractions that weren't explicitly requested. -- No new dependency if it can be avoided. -- No boilerplate nobody asked for. -- Deletion over addition. Boring over clever. Fewest files possible. -- Question complex requests: "Do you actually need X, or does Y cover it?" -- Pick the edge-case-correct option when two stdlib approaches are the same size, lazy means less code, not the flimsier algorithm. -- Mark intentional simplifications with a `ponytail:` comment. If the shortcut has a known ceiling (global lock, O(n²) scan, naive heuristic), the comment names the ceiling and the upgrade path. - -Not lazy about: input validation at trust boundaries, error handling that prevents data loss, security, accessibility, the calibration real hardware needs (the platform is never the spec ideal, a clock drifts, a sensor reads off), anything explicitly requested. Lazy code without its check is unfinished: non-trivial logic leaves ONE runnable check behind, the smallest thing that fails if the logic breaks (an assert-based demo/self-check or one small test file; no frameworks, no fixtures). Trivial one-liners need no test. diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml new file mode 100644 index 00000000..f343501f --- /dev/null +++ b/.github/workflows/verify.yml @@ -0,0 +1,71 @@ +name: verify + +on: + pull_request: + push: + branches: + - main + +jobs: + verify: + runs-on: ubuntu-latest + steps: + - name: Checkout symm + uses: actions/checkout@v4 + with: + path: symm + + - name: Checkout datura + uses: actions/checkout@v4 + with: + repository: theapemachine/datura + path: datura + + - name: Checkout nomagique + uses: actions/checkout@v4 + with: + repository: theapemachine/nomagique + path: nomagique + + - name: Checkout errnie + uses: actions/checkout@v4 + with: + repository: theapemachine/errnie + path: errnie + + - name: Checkout qpool + uses: actions/checkout@v4 + with: + repository: theapemachine/qpool + path: qpool + + - name: Checkout sonic + uses: actions/checkout@v4 + with: + repository: bytedance/sonic + path: sonic + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: symm/go.mod + cache-dependency-path: | + symm/go.sum + datura/go.sum + nomagique/go.sum + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + package_json_file: symm/frontend/package.json + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: 24 + cache: pnpm + cache-dependency-path: symm/frontend/pnpm-lock.yaml + + - name: Verify + working-directory: symm + run: ./scripts/verify.sh diff --git a/.gitignore b/.gitignore index bd6baa6f..381f6ffd 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,5 @@ kraken/public/runs/ kraken/paper/runs/ market/runs/ runs/effective-config.json +.codebase-memory/graph.db.zst +.codebase-memory/artifact.json \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index dc5cf240..b265a116 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -34,5 +34,6 @@ }, "editor.codeActionsOnSave": { "source.organizeImports.biome": "explicit" - } + }, + "workbench.colorCustomizations": {} } diff --git a/AGENTS.md b/AGENTS.md index 3720539a..deeb3894 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,61 +1,34 @@ # AGENTS.md -You are a lazy senior developer. Lazy means efficient, not careless. The best code is the code never written. +## Project objective -Before writing any code, stop at the first rung that holds: +**Maximize the wallet. Minimize the time to do so.** -1. Does this need to be built at all? (YAGNI) -2. Does the standard library already do this? Use it. -3. Does a native platform feature cover it? Use it. -4. Does an already-installed dependency solve it? Use it. -5. Can this be one line? Make it one line. -6. Only then: write the minimum code that works. +Miracles are not expected. A best-effort, highly principled system is. The goal is to detect as many real opportunity types as the market presents — pumps, coils, exhaustion, liquidity vacuums, sector lifts, thin-book traps — and to act on them with dynamically derived thresholds only. -Rules: - -- No abstractions that weren't explicitly requested. -- No new dependency if it can be avoided. -- No boilerplate nobody asked for. -- Deletion over addition. Boring over clever. Fewest files possible. -- Question complex requests: "Do you actually need X, or does Y cover it?" -- Pick the edge-case-correct option when two stdlib approaches are the same size, lazy means less code, not the flimsier algorithm. -- Mark intentional simplifications with a `ponytail:` comment. If the shortcut has a known ceiling (global lock, O(n²) scan, naive heuristic), the comment names the ceiling and the upgrade path. - -Not lazy about: input validation at trust boundaries, error handling that prevents data loss, security, accessibility, the calibration real hardware needs (the platform is never the spec ideal, a clock drifts, a sensor reads off), anything explicitly requested. Lazy code without its check is unfinished: non-trivial logic leaves ONE runnable check behind, the smallest thing that fails if the logic breaks (an assert-based demo/self-check or one small test file; no frameworks, no fixtures). Trivial one-liners need no test. +Failure after an honest principled try is acceptable. Failure from magic numbers, incomplete data sources, or comment blocks that do not match implementation is not. --- -### Signal Integrity and Dynamic Calculations - -Hardcoded thresholds, static multipliers, or guessed parameters are not permitted. All logic must dynamically adjust to real-time market data. - -#### Incorrect (Magic Numbers) - -```go -// This uses an arbitrary, hardcoded percentage threshold -func (signalCalculator *SignalCalculator) IsSignalTriggered() bool { - threshold := 0.015 - return (signalCalculator.CurrentPrice - signalCalculator.EntryPrice) / signalCalculator.EntryPrice > threshold -} -``` - -#### Correct (Dynamically Derived) - -```go -// This derives the threshold dynamically using Average True Range (ATR) to adjust to market volatility -func (signalCalculator *SignalCalculator) IsSignalTriggered(averageTrueRange float64) bool { - if signalCalculator.EntryPrice == 0 { - return false - } +> real, solid, rigerous, and principled implementations of each signal using the extensive comment above the Signal type as the spec. Or refer to [DECISION.md](/Users/theapemachine/go/src/github.com/theapemachine/symm/DECISION.md) if the comment has been removed or altered. +> +> This also means: +> +> 1. No shortcuts, workarounds, and especially no fallbacks (unless highly defensible, usually not) +> 2. No magic numbers, no static math (time horizons, windows, etc.), and no assumptions that all symbols operate on the same temporal or any other scale. +> 3. Absolutely no fakery, performative math or implementation, or otherwise compromised mechanisms. +> 4. No "good enough" and no "lesser" implementation when a better one exists, which also includes being honest about what each signal needs to consume regarding market data, to make all of the above work. - volatilityMultiplier := averageTrueRange / signalCalculator.EntryPrice - percentageChange := (signalCalculator.CurrentPrice - signalCalculator.EntryPrice) / signalCalculator.EntryPrice +--- - return percentageChange > volatilityMultiplier -} -``` +## Anti-patterns (learned the hard way) ---- +- Fixed time windows (e.g. 60 seconds) copied from external repos. +- Scoring ticker summary fields and calling it "microstructure." +- Positive-only returns for dump detection — exhaustion needs lift decline **and** price rejection context. +- One-shot test fixtures (single spike) without multi-leg replay (use the tests/fixture system). +- Category masses merged invisibly (e.g. `trendMass + flatMass` with one wire key). +- Bare multipliers (`*2`, `(1-x)`) in classifiers without a statistic in the denominator. ## Definition of Done & Verification @@ -175,8 +148,19 @@ func NewObjectName(ctx context.Context) (*ObjectName, error) { "cancel": obj.cancel, }) } + +/* +SomeMethod +*/ +func (object *ObjectName) SomeMethod() { + // ... Do work ... + results := object.composed.SomeMethod() // Do work using the composed object. + // ... Do more work with results ... +} ``` +> It is very important that you use composed objects and then encapsulate the logic in that object. Do not encapsulate and then add helper methods to call the methods in the encapsulation. + You should recognize objects that do too much when you have naming that is longer than two segments in either method names or object names. ```go @@ -204,6 +188,7 @@ Now ObjectName is clearly updating itself. ### Control Flow * **Early Returns:** Write guard clauses with early returns. Keep the primary logic path at indentation level 1. +* **Over Guarding:** Do not overly guard things, just let the system crash, at least we will know what goes wrong. * **No Else Blocks:** Do not use `else`. Invert conditions to return early or exit. * **Nesting Ceiling:** Do not nest `if` blocks deeper than two levels. Extract deeply nested logic into a helper method. * **No Silent Failures:** If a precondition fails or an unexpected state occurs, return a descriptive error. Substituting default fallbacks or silently skipping errors is prohibited. @@ -211,9 +196,17 @@ Now ObjectName is clearly updating itself. ### Naming & Formatting * **No Single-Character Names:** Variable names and method receivers must be descriptive (e.g., use `signalCalculator`, not `s`), the exception here is the `testing.TB` instance variable which should always be `t`. -* **Block Separation:** Insert an empty newline between distinct logical code blocks, except where there are only a few lines lines in a block or method/function. +* **Block Separation:** Insert an empty newline between distinct logical code blocks, except where there are only a few lines lines in a block or method/function. And `if` statements ALWAYS have an empty line above them. * **Line Breaks:** Wrap long function signatures to prevent lines from running past split-view boundaries. +* **Errors** Instance variables for errors are always `err` and nothing else. Errors are logged with `errnie` +```go +errnie.Error(errnie.Err( + errnie.Validation, // Not the default, use the correct errnie.Kind + "some message", // or err.Error() + err, // or nil +)) +``` --- ## Environment & Tooling Constraints @@ -226,410 +219,3 @@ Now ObjectName is clearly updating itself. ### Compiler Configuration & Linker Errors * **dropg Linker Error:** If you encounter a `dropg` linker error, refer to the `Makefile` located in the project root to ensure environment flags and compiler options match the project targets. Do not bypass build constraints with temporary flags. - ---- - -## Interaction Protocol - -1. **No Summarization:** Do not explain the existing system architecture back to the user. Reference specific file names and types when discussing changes. -2. **Opinions on Request Only:** Provide design opinions or alternative paradigms only when explicitly asked. Otherwise, implement the requested change directly according to this contract. -3. **Preserve Load-Bearing Structure:** Read and trace existing code paths before proposing modifications. Do not rewrite structural components unless you can document exactly why the existing implementation is broken or incorrect. -4. Keep your answers brief. The user cannot process language like you do, and requires your answer to roughly match their own levels of verbosity. - ---- - -## Signal, Artifact, and nomagique Composition - -This section records the canonical architecture. If a task requires wiring beyond what is described here, the gap is in **nomagique** (missing or mis-shaped primitive) or **ingestion** (artifact not written to the tree with the right prefix), not in the signal or trader. - -### One tree, write at the source, query everywhere else - -Market data enters the system once: **websockets write directly to `dmt.Tree`**. - -```go -tree.Insert(artifact.Prefix(), artifact.Marshal()) -``` - -`kraken/public/websocket.go` (and private/user websockets) acquire an artifact from raw Kraken JSON, set Role/Scope/Origin, and insert. No trader fan-out, no per-signal `Update`, no intermediate book/trade/ticker types relaying the same frame. - -**Traders, signals, and stories do not ingest.** They **query** what they need by prefix: - -```go -for artifact := range tree.Seek(query.Prefix()) { - transport.NewFlipFlop(&artifact, algo) - // use or aggregate result -} -``` - -Do not reproduce the orchestration in `trader/crypto.go` — wiring every channel through `book.Update` → `updateSignals` → `signal.Update` is redundant once the tree is the bus. That layer exists to be removed, not extended. - -### The signal contract - -A signal has one job: **Measure** — seek the tree by prefix, run the `nomagique.Number` pipeline, return artifacts. - -Reference implementation: `signal/toxicity/signal.go` (minus `Update`; the tree insert moves to the websocket). - -Do not add tracker access, category switches, feature encoding, or ingestion inside `Measure`. If that seems necessary, the pipeline or the stored artifact schema is incomplete. - -### nomagique is math, not domain - -`nomagique` holds composable math primitives — ratios, margins, circuits, classifiers — each exposing only: - -* `New*(artifact *datura.Artifact)` — constructor; specialized config comes from the artifact, not from Go function parameters -* `Write(p []byte)` — buffer the incoming artifact -* `Read(p []byte)` — evaluate lazily, emit result artifact -* `Close()` — dispose - -Constructors must not return errors. Log failures with `errnie.Error(errnie.Err(...))` and return a degraded stage. Data arrives on **Write**, never at construction time via `inputCount`, `func([]float64) float64`, or fixed float layouts. - -**Do not** add domain types to nomagique (e.g. `BookQuality`, `Bookflow`). Domain classification is composed in the signal's `NewSignal` from atomic primitives. - -### Pipeline shape - -The target composition is a single nested `nomagique.Number`. If this cannot be written as one expression, nomagique has not reached its true form yet — adapt the primitives, do not add signal glue. - -```go -nomagique.Number( - vector.NewFeatureExtractor(schemaArtifact), - probability.NewClassifier( - logic.NewCircuit(bluffRules...), - logic.NewCircuit(vacuumRules...), - logic.NewCircuit(supportRules...), - ), -) -``` - -* **FeatureExtractor** — reads payload JSON using schema attributes; derives scalars -* **Classifier** — score source order *is* the category index; no symm-side `switch categoryIndex` -* **Circuit** — priority-ordered rules (`Match` on conditions, `Then` runs a margin/ratio stage) - -Complex routing uses `datura/transport` (FlipFlop, Feedback, Graph). Prefer transport over custom wiring. - -### datura.Artifact: payload, attributes, prefix - -| Field | Role | -|-------|------| -| **Payload** | The data — usually JSON (raw Kraken book/trade/order events) | -| **Type** | Describes payload encoding (`json`, `artifacts`, …) | -| **Role / Scope / Origin** | Semantic indexing; together they determine **Prefix** | -| **Attributes** | Schema for the payload — key names, types, relationships, extraction rules. Not a second data store. | - -Do not abuse attributes for operational data. Put market data in the payload; describe how to read and process it in attributes. - -**Attributes are the configuration surface.** Conventions are chosen and kept consistent across the codebase — they are not fixed by capnp schema. A primitive reads attributes at `Read` time to decide how to handle payload fields. This is why `datura.Artifact` exists: rigid Go structs cannot express per-field transforms, optional pipelines, or evolving schemas without constant type churn. The trade-off is slightly higher risk of typos in attribute keys; the gain is a system that adapts without recompilation. - -#### Per-field transforms - -When one payload key needs EMA and another needs raw value, do not fork the pipeline or add signal glue. Declare it on the schema artifact: - -```go -artifact.WithAttributes(datura.Map{ - "keys": datura.Map{ - "cancelBid": "float", - "fillBid": "float", - }, - "transforms": datura.Map{ - "cancelBid": "ema", - "fillBid": "raw", - }, -}) -``` - -The nomagique primitive reads `transforms.` and applies the matching stage (`adaptive.NewEMA`, pass-through, etc.). Same extractor, different behavior per key — driven by attributes, not constructor parameters. - -#### How far attributes can go - -In principle, attributes can describe almost anything a Go type would: - -* **Schema** — key names, types, units, relationships between fields -* **Transforms** — ema, zscore, fracdiff, per key or per path -* **Rules** — thresholds, gates, priority order (could mirror `nomagique/logic` in attribute form) - -Replicating entire `nomagique/logic` circuits purely in attributes is possible but not recommended in practice — use `logic.NewCircuit` in the pipeline for branching, attributes for field-level config. Prefer composition in Go where the graph is stable; use attributes where the graph varies by signal, scope, or instrument without new types. - -#### When pipeline composition is not enough - -If a value cannot be wrapped cleanly in `nomagique.Number(...)`: - -1. First — can an attribute convention express it? (transform, gate source, aggregation window) -2. Second — does a nomagique primitive need to grow to honor that attribute? -3. Last — only then consider `datura/transport` (Graph, Feedback) for routing - -Never add a new Go struct or signal method when an attribute on the schema artifact would do. - -**Prefix** is the tree query API. `Artifact.Prefix()` builds `role/scope/origin/.../timestamp/uuid.type`. - -Example — Origin `toxicity`, Role `measurement`, Scope `book`: - -``` -measurement/book/toxicity. -``` - -Consumers seek by prefix: - -* `book` — all book events (raw Kraken feed) -* `measurement` — all measurements across signals -* `measurement/book` — book measurements from every signal that emits them - -Ingestion prefixes describe **what arrived** (e.g. Role `book`, Scope `BTC/USD`). Measurement prefixes describe **what was derived** (e.g. Role `measurement`, Scope `book`, Origin `toxicity`). Same tree, different queries. - -Plug raw Kraken JSON into the payload at ingest time. Primitives parse it on `Read` using attribute schema — not pre-serialized float batches. - -### Incorrect vs correct - -#### Incorrect — trader orchestrates ingest, signal has Update, domain blob in nomagique - -```go -// crypto.go: websocket → book.Update → updateSignals → toxicity.Update → tree -bookQuality := algorithm.NewBookQuality() -signal.Update(artifact) // redundant relay -signal.Measure(...) // maps classifier.category → logic.CategoryType -``` - -#### Correct — websocket writes once, signal queries, composed pipeline - -```go -// kraken/public/websocket.go — on book frame: -artifact := datura.Acquire("kraken", datura.APPJSON). - WithRole("book").WithScope(symbol).WithPayload(rawJSON) -tree.Insert(artifact.Prefix(), artifact.Marshal()) - -// signal/toxicity — NewSignal composes algo only; Measure seeks and classifies: -schema := datura.Acquire("toxicity", datura.APPJSON). - WithRole("measurement").WithScope("book"). - WithAttribute("cancelBid", "float") // schema, not data - -algo := nomagique.Number( - vector.NewFeatureExtractor(schema), - probability.NewClassifier( - logic.NewCircuit(...), - logic.NewCircuit(...), - logic.NewCircuit(...), - ), -) - -for artifact := range tree.Seek(measurementQuery.Prefix()) { - transport.NewFlipFlop(&artifact, algo) -} -``` - -If extra wiring is needed beyond **websocket → tree → Seek → FlipFlop → Number**, stop and fix nomagique, the artifact schema, or where ingest writes — do not grow the signal or trader. - -## nomagique - -Write stages data, Read lazily computes, and only overwrite the Payload (of the initial artifact coming in via the constructors): For the nomagique Write actions, not for the artifact. The artifact works already as it should, I have been using it for years. The only thing that is different in this version is the way we do attributes now. - -The feature_extractor works, because we read the inputs array and root to know how to access the data in payload. We then handle the sample, potentially through a transformer, and finally we write a slice of floats to the "features" key in the payload, and write "features" to the "root" (key), and the part I already flagged as wrong, we copy the inputs to inputs, though technically this would still allow you to identify the original field of the inputs since it is all handled in order. - -The bigger idea is that we come up with a rigid convention, and make sure all nomoagique compute primitives work in the same way, always referencing the same fields for teh same type of data, and using dynamic maps (like inputs) for (domain) specific data referencing. The compute primitives must remain generic, and they should all be able to fit in a nomagique.Number() pipeline. - -Two other ideas that are in there. "equation" sub-package is used to create "presets" basically just precomposed primitives for well-known equations, and "algorithm" is the same idea, it could be pre-composed equations, primitives, or a mix of both. - -But the core idea is this: atomic computational primitives that expose *only* io.ReadWriteCloser, which means anything can be connected to anything. - -And this is where my biggest problem has been the past 48 hours or more. To just have this be understood. It is relative simple, once you just think about what this could do. You can build entire algorithms, using the transport primitives in datura/transport. - -And datura (Artifact) is the real secret ingredient. No marshalling/unmarshalling tax, and with sonic, not even when you want to access the payload, but you do need to overwrite the whole artifact on write yes, because when I retrieve an artifact from the radix trie for instance, I would do something like: datura.Acquire("pumpdump-ignition", datura.APPJSON).Write(data), and as long as I know that I am storing/using Artifact everywhere it will restore the full artifact. - -If you have an issue in the compute pipelines, *then* you can do: - -func (extractor *FeatureExtractor) Write(p []byte) (int, error) { - tmp := datura.Empty.Write(p) - return extractor.artifact.WithPayload(tmp.DecryptPayload()) -} - -Something like that, and you would set your initial config via the constructor. - -The artifact on your constructor, that is your config. Its payload is your buffer (transfers the p artifact from Write to Read, because the Payload can also host one or even multiple full artifacts), and p is your compute state. There is NO other model. However, if you do it wrong and need to rely on more, you could always do what I did in the feature extractor to deal with the transforms. Just create a quick temp artifact to move a detached compute state into EMA (in this case) and capture the results. - -There is a more important and fundamental thing that needs to be solved: - -"rvol": map[string]any{ - "input": "volume", - "useDelta": 1.0, - "shortWindow": 5.0, - "longWindow": 60.0, - "outputKey": "rvol", - "scale": 2.5, -}, -"precursor": map[string]any{ - "input": "last", - "returnLag": 1.0, - "longWindow": 60.0, - "positiveOnly": 1.0, - "outputKey": "precursor", - "scale": 2.0, -}, -"compression": map[string]any{ - "source": "value", - "scale": 1.5, -}, - -The package is called: nomagique (no magic), and the main pipeline component is the Number function. This is deliberate, so you literally have to say: nomagique.Number(...) - -No. Magic. Number. - -It's the whole reason I started building this package as composable elements. So you never have to guess at a number, not even config. Because we work a lot with physics simulations, and with crypto markets too, things need to be able to adapt dynamically to the environment, in this case, market conditions. There is a big difference what a pump is between bitcoin, and doge coin. So the whole point was: plug in your raw market data, even when it comes to config, and wrap things into adaptive primitives so things keep dynamically derived. - -So the question becomes: - -{ - "channel": "ticker", - "type": "update", - "data": [ - { - "symbol": "ALGO/USD", - "bid": 0.10025, - "bid_qty": 740.0, - "ask": 0.10035, - "ask_qty": 740.0, - "last": 0.10035, - "volume": 997038.98383185, - "vwap": 0.10148, - "low": 0.09979, - "high": 0.10285, - "change": -0.00017, - "change_pct": -0.17, - "timestamp": "2023-09-25T09:04:31.742648Z" - } - ] -} - -If that is (one of a few) data structures we get in, how would we derive the shortWindow, longWindow, scale, and return lag from those data points. Or maybe, could also be, we need to actually wait until we also have a book frame: - -{ - "channel": "book", - "type": "update", - "data": [ - { - "symbol": "MATIC/USD", - "bids": [ - { - "price": 0.5657, - "qty": 1098.3947558 - } - ], - "asks": [], - "checksum": 2114181697, - "timestamp": "2023-10-06T17:35:55.440295Z" - } - ] -} - -A candle frame: - -{ - "channel": "ohlc", - "type": "update", - "timestamp": "2023-10-04T16:26:30.524394914Z", - "data": [ - { - "symbol": "MATIC/USD", - "open": 0.5624, - "high": 0.5628, - "low": 0.5622, - "close": 0.5627, - "trades": 12, - "volume": 30927.68066226, - "vwap": 0.5626, - "interval_begin": "2023-10-04T16:25:00.000000000Z", - "interval": 5, - "timestamp": "2023-10-04T16:30:00.000000Z" - } - ] -} - -A trade frame: - -{ - "channel": "trade", - "type": "update", - "data": [ - { - "symbol": "MATIC/USD", - "side": "sell", - "price": 0.5117, - "qty": 40.0, - "ord_type": "market", - "trade_id": 4665906, - "timestamp": "2023-09-25T07:49:37.708706Z" - } - ] -} - -Or even an L3 orders frame: - -{ - "channel": "level3", - "type": "update", - "data": [ - { - "checksum": 2841398499, - "symbol": "MATIC/USD", - "bids": [], - "asks": [ - { - "event": "delete", - "order_id": "OOIATY-6EIWY-ACVIUN", - "limit_price": 0.5636, - "order_qty": 302.89736033, - "timestamp": "2023-10-06T18:21:00.097010033Z" - }, - { - "event": "add", - "order_id": "O2BN53-5RSB2-V3J57T", - "limit_price": 0.564, - "order_qty": 3500.77668626, - "timestamp": "2023-10-06T18:20:27.383408052Z" - }, - { - "event": "add", - "order_id": "OWG5ZU-LHUHH-BICPEX", - "limit_price": 0.564, - "order_qty": 22149.62881248, - "timestamp": "2023-10-06T18:20:50.842854530Z" - }, - { - "event": "add", - "order_id": "ONVDB3-2DRUF-Y6MF7D", - "limit_price": 0.564, - "order_qty": 42196.34088652, - "timestamp": "2023-10-06T18:20:58.101850535Z" - } - ] - } - ] -} - -That might require a new config attribute: {"required": ["ticker", "book", "trade", ...]} - -We already set the channel value as the role, and the type as the scope I see in the websocket code. - -### Established Conventions - -```go -map[string]any{ - "root": "data", // "root" gives you the value ("data" in this case) that is the key you need to get the data you need from the incoming artifact payload. - "inputs": []string{ - "symbol", - "bid", - "bid_qty", - "ask", - "ask_qty", - "last", - "volume", - "vwap", - "low", - "high", - "change", - "change_pct", - "timestamp", - }, // "inputs" give you the keys you can call on the data you retrieved from the payload using the root key. - "transforms": map[string]string{ - "volume": "ema", - "vwap": "ema", - }, // "transforms" map data points retrieved via the input keys from the data in the payload retrieved via the root key, to be wrapped within another compute primitive. This is for certain use-cases only, and something different from simply pipelining compute primitives. -} -``` - -* Compute primitives write their output under an `output` key. If the output is a map of values, that means the state artifact must also define the `root` key value, and potentially `inputs` and `transforms` diff --git a/Makefile b/Makefile index 6cc0485a..dc39034c 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ -# qpool uses go:linkname runtime hooks; Go 1.26+ needs this when linking symm. +# DMT currently pulls qpool's go:linkname runtime hooks for cognitive code. +# Go 1.26+ needs this while that indirect dependency remains. # export GOFLAGS so make targets and nested go/cgo subprocesses inherit the flag. # Outside Make, run: export GOFLAGS=-ldflags=-checklinkname=0 # No inner quotes: a single shell layer passes the flag through unambiguously. @@ -13,17 +14,16 @@ SYMM_BIN := bin/symm CONFIG ?= CONFIG_FLAG = $(if $(CONFIG),--config $(CONFIG),) LOG_DIR ?= runs +OPTIMIZE_AUDIT ?= runs/audit.jsonl +OPTIMIZE_REPLAY ?= runs/replay.jsonl +OPTIMIZE_TREE ?= logic/rules/tree.yml +OPTIMIZE_LOOKBACK ?= 6h +OPTIMIZE_SYMBOLS ?= +OPTIMIZE_FLAGS ?= DUMP_OUTPUT ?= symm.txt -DATURA_DIR ?= $(abspath ../datura) -CAPNP_GO_STD ?= $(abspath $(DATURA_DIR)/../../capnproto/go-capnp/std) -CAPNP_TS_ROOT ?= $(abspath ../capnp-ts) -CAPNP_TS_PLUGIN ?= $(CAPNP_TS_ROOT)/node_modules/.bin/capnpc-ts -CAPNP_TS_OUT := frontend/src/lib/capnp -ARTIFACT_CAPNP := $(DATURA_DIR)/artifact.capnp - -.PHONY: build test test-go test-race test-cover test-e2e test-frontend bench run audit audit-report dump profile profile-stack profile-report strip-trailing-newlines gen-capnp-ts capnp-ts-toolchain +.PHONY: build test test-go test-race test-cover test-e2e test-frontend bench run optimize audit audit-report dump profile profile-stack profile-report strip-trailing-newlines debug debug-inspect test: test-go test-race test-frontend @@ -39,21 +39,32 @@ test-cover: go tool cover -func=runs/coverage.out | tail -1 test-frontend: - cd frontend && pnpm exec tsc --noEmit -p tsconfig.lib.json && pnpm test --run + cd frontend && pnpm build bench: go test $(LDFLAGS) -bench=. -benchmem ./... +kill: + -lsof -t -i:8765 | xargs kill -9 || true + run: @echo "symm running (Ctrl+C to stop)" @echo "UI ws://127.0.0.1:8765/ws — dashboard: cd frontend && pnpm dev" go run $(LDFLAGS) main.go +optimize: + go run $(LDFLAGS) main.go optimize --replay $(OPTIMIZE_REPLAY) --tree $(OPTIMIZE_TREE) --lookback $(OPTIMIZE_LOOKBACK) --symbols "$(OPTIMIZE_SYMBOLS)" --write-tree $(OPTIMIZE_FLAGS) + debug: @echo "symm debug running (Ctrl+C to stop)" @echo "UI ws://127.0.0.1:8765/ws — dashboard: cd frontend && pnpm dev" export DATURA_INSPECT=1 && go run $(LDFLAGS) main.go +debug-inspect: + @echo "symm debug (DATURA_INSPECT) running (Ctrl+C to stop)" + @echo "UI ws://127.0.0.1:8765/ws — dashboard: cd frontend && pnpm dev" + export DATURA_INSPECT=1 && go run $(LDFLAGS) main.go + run-profile: @echo "pprof http://127.0.0.1:6060/debug/pprof/" SYMM_PPROF=1 go run $(LDFLAGS) main.go @@ -70,16 +81,6 @@ dump: strip-trailing-newlines: git ls-files '*.go' | python3 scripts/strip-trailing-newlines.py -capnp-ts-toolchain: - @test -x $(CAPNP_TS_PLUGIN) || (cd $(CAPNP_TS_ROOT) && yarn install) - -gen-capnp-ts: capnp-ts-toolchain - @mkdir -p $(CAPNP_TS_OUT) - capnpc -I$(CAPNP_GO_STD) \ - -o $(CAPNP_TS_PLUGIN):$(CAPNP_TS_OUT) \ - --src-prefix=$(DATURA_DIR) \ - $(ARTIFACT_CAPNP) - -build: gen-capnp-ts +build: @mkdir -p bin - go build $(LDFLAGS) -o $(SYMM_BIN) . \ No newline at end of file + go build $(LDFLAGS) -o $(SYMM_BIN) . diff --git a/README.md b/README.md index 347834e2..52b6211e 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Migration tasks and acceptance: [`spec/SPEC.md`](spec/SPEC.md). │ ingest: role/scope/origin/… (e.g. book/BTC-USD) │ │ measure: measurement///… │ └──────────────┬───────────────────────────────────────────────────┘ - │ tree.Seek(prefix) → transport.NewFlipFlop → Number + │ tree.Seek(prefix) → signal Measure / explicit packed frames ▼ ┌──────────────────────────────────────────────────────────────────┐ │ signal/* — Measure only (reference: signal/toxicity/signal.go) │ @@ -177,7 +177,7 @@ Builtin deny categories (`ToxicBluff`, `LiquidityVacuum`, `Turbulent`, `Saturati Each signal package: - Composes **one** `nomagique.Number` in `NewSignal` (schema on a `datura.Artifact`, not hardcoded Go params) -- Implements **`Measure(query)`** — `tree.Seek(query.Prefix())`, `transport.NewFlipFlop`, pipeline evaluate +- Implements **`Measure(query)`** — `tree.Seek(query.Prefix())`, explicit artifact frame decode, pipeline evaluate where used - Does **not** ingest feeds, hold `Update`, or switch on category index inside `Measure` | Signal | Package | Categories (examples) | Ingest prefix | @@ -453,3 +453,15 @@ See `cmd/cfg/config.yml` for the full set. 5. Extend `logic/rules/tree.yml` if new categories should authorize or deny trades. See `signal/toxicity/signal.go` and `AGENTS.md` §8. + +![Image of S.Y.M.M. Terminal](terminal1.png) + +![Image of S.Y.M.M. Terminal](terminal2.png) + +![Image of S.Y.M.M. Terminal](terminal3.png) + +![Image of S.Y.M.M. Terminal](terminal4.png) + +![Image of S.Y.M.M. Terminal](terminal5.png) + +![Image of S.Y.M.M. Terminal](terminal6.png) diff --git a/REVIEW.md b/REVIEW.md new file mode 100644 index 00000000..1075ea0d --- /dev/null +++ b/REVIEW.md @@ -0,0 +1,183 @@ +# symm — Critical Code Review + +Scope: `symm`, plus the `nomagique` and `datura` sibling packages it depends on via the `replace` directives in `go.mod`. Four axes, per request: signal-math correctness against the per-signal `Signal`-type spec, code shape against the compositional pattern in `AGENTS.md`, re-implementation of things that already exist, and lock-free/performance. Findings are not ranked — everything below is treated as equally critical. + +Method: the tree was swept by five focused passes (two math passes across all thirteen signals, one shape pass, one duplication pass, one performance/lock-free pass), each reading the actual source and quoting it. Two of the highest-impact claims (the Hawkes shadowed named-returns and the manifold `medianAbsolute`) were re-read and confirmed line-for-line during write-up. All paths are relative to the three repo roots. + +--- + +## 1. Signal math vs the spec + +The governing rule (`AGENTS.md`): the comment block above each package's `Signal` type is the absolute spec; no magic numbers, no fixed windows/horizons, no fallbacks, no performative math, no assuming all symbols share one temporal scale, and dump/exhaustion detection must be direction-aware. + +### Cross-cutting math defects (recur across most signals) + +- **No signal derives any window or horizon from observed timestamps.** fluid/manifold run on a fixed `integrationInterval`/`DeltaT`; resonance, pumpdump, exhaust, toxicity, cvd, depthflow all window by *sample/frame count* (`len(history)`, frame counters, fixed caps of 32/64/128). `nomagique/timeline` is imported by none of the signal packages. Every spec that promises "tick cadence" / "observed update cadence" is contradicted by the code. +- **`nomagique/statistic.ResolveWindows` is misused as a no-op or a retention length.** In the count-only path (`nomagique/statistic/windows.go:109-121`) it forces `longWindow == sampleCount`, so the "adaptive" flow/RVOL windows collapse to the entire buffer. In resonance (`baselines.go:26`, `feed_ring.go:122`) its second return (`longWindow`, a computation length) is used as a ring-trim count — a category error — and it is fed epoch-nanosecond timestamps as the value series, so its CV is ≈0 and the window degenerates to `~sqrt(n)` regardless of true cadence. +- **A `1/N` uniform constant is used as a computed measurement.** `probabilities [0.25,0.25,0.25,0.25]` (4-way) or `[1/3,1/3,1/3]` (3-way) with a hard category label is stamped whenever a stage yields nothing — pumpdump (ticker/book/trade), exhaust, toxicity. This fabricates a fully-formed, often *directional* conclusion in place of an abstention. +- **Category scores are unbounded products/ratios fed to a softmax.** correlation, leadlag, depthflow, manifold, and the shared `nomagique/probability/classifier.go:241` softmax compare scores built on incommensurable scales, so the winner is whichever score is numerically largest, not a calibrated posterior. Bare `(1-x)`, `1/(1+x)`, and `*` multipliers with no statistic in the denominator are the norm (the `AGENTS.md` "bare multipliers" anti-pattern). +- **Direction-blind / positive-only detection recurs** where the spec demands two-sidedness: fluid (F8), manifold (M9), resonance (R10), pumpdump (PD3), exhaust (EX2). + +### hawkes + +- `nomagique/algorithm/excitation_symbol.go:444-502` `organicHeadroomScores` declares named returns `(frenzy, saturation, organic, exhaustion)`, then at `:466` `saturation, err :=` and `:484` `frenzy, err :=` use `:=`, creating locals that **shadow** the named returns. Those locals feed only the discarded `headroom`. The function therefore **always returns `frenzy=0`, `saturation=0`, and `exhaustion=0`** (exhaustion is never assigned anywhere); only `organic` survives. Two of the four Hawkes regime scores are dead. *(Re-read and confirmed.)* +- `nomagique/algorithm/excitation.go:115-116` wires **branching ratio and spectral radius to the same value** (`BranchingRatio` written to both keys); `excitation_symbol.go:154` sets `branchingRatio = fit.SpectralRadius`. The spec treats α (descendants/parent) and ρ (stability eigenvalue) as distinct; the true branching ratio is never emitted. +- Magic horizons/multipliers: `excitation.go:15` `hawkesFitCooldownMult = 50` applied bare (`windowSpan * 50`, `:305-311`); `excitation.go:240` `EventCount < 4`; `trade_excitation_sample.go:13-14` caps `128`/`64`; `:271-278` `if required < 8 { return 8 }`. +- `excitation_symbol.go:178,508-540` `confirmAsymmetryWithBook` folds L2 top-of-book imbalance into the Hawkes asymmetry — the signal's own spec (signal.go:42-45) explicitly declares book confirmation **out of scope** because there is no L3 ingest. +- `nomagique/hawkes/fit.go:266-269` `ClampSubcritical` returns unchanged for every subcritical fit, and `Valid()` already rejects supercritical fits, so the clamp body is unreachable. + +### cvd + +- `nomagique/algorithm/trade_flow_sample.go:163-169` sizes the "active flow window" via `ResolveWindows(notionals,0,0)` → window == whole buffer (capped at `flowSampleHistoryCap = 128`). Spec promises a window derived from observed notional history; in practice it is a fixed 128-tick cap that dispersion never shrinks. +- `nomagique/equation/flow.go:137-142,280` gate `flowPressure` and `impactEfficiency` (ratios) against the literal `1` with no distributional fence — magic thresholds. +- `trade_flow_sample.go:109-113` trusts the feed's `side` field as the aggressor tag with no tick-rule verification, while the spec markets "Tick Integrity." Unstated dependency. + +### correlation + +- `market/cross_section.go:142-149` builds per-symbol return series by *arrival index* and drops zero returns, then `market/peer_cache.go:60` aligns cross-symbol returns by tail position. Symbols update at different cadences (the code even tracks `updateGaps`), so index *i* is a different wall-clock instant per symbol — Pearson of index-aligned, differently-clocked series is not the "synchronized log-returns" the spec claims, and violates the shared-temporal-scale rule. +- `peer_cache.go:54-71` computes the measured symbol's correlation against a **leave-one-out** market median, but the `peerCorrelations` it is compared against (`:86-96`) use a **full-market (self-included)** median. `relativeCorrelation = alignment/median` (signal.go:223) divides quantities computed against different reference vectors. +- `signal/correlation/signal.go:265-279` `EnergyLift` is an unbounded ratio squashed only at the very end; the "Variance" axis is represented solely by this ratio into the softmax. + +### leadlag + +- `signal/leadlag/section_correlation.go:156-199` `alignedReturns` derives a single `interval` from the anchor's median spacing and shifts **both** anchor and follower by the same integer `shift = lag/interval`. The follower has its own spacing, so the realized wall-clock lag differs from the intended `lag` — the shared-temporal-scale anti-pattern, in the one signal whose entire purpose is temporal lead/lag. +- `section_correlation.go:201-220` index-pairs the two return vectors after independent zero-price filtering, so they can differ in length for reasons unrelated to lag, then tail-aligns by count. +- `signal/leadlag/ticker.go:157-160` category scores are un-normalized polynomial products; `sampleSupport = SampleCount/minCorrelationSamples` (`:115-121`) is unbounded and multiplies every score. `lagDampExponent = 1 + LagBars*LagCorr*(1+StallMargin)` (`:143-147`) uses the *signed* `LagCorr`, so a negative value drives `math.Pow(1-lagFraction, exponent)` toward divergence. +- `section.go:280-293` `moveThreshold` computes `mean, std := meanStdDev(...)`, discards `mean` (`_ = mean`), and returns `median + std` — mixing a median center with a std dispersion (MAD is used elsewhere), the discarded mean signaling an unfinished change. + +### causal + +- `nomagique/algorithm/pearl_sample.go:246` sets the "Macro Momentum" control node to the **same symbol's** ticker `change_pct`. The spec defines node 0 as the broad-market drift the backdoor adjustment must control *for*; controlling for the target's own return makes the "Local vs. Global / Systemic Beta" decomposition vacuous. No `crossSection` data enters `PearlSample` at all despite the spec requiring cross-asset contagion. +- `nomagique/causal/contagion.go:60-99` `peakFromTable` returns `max|sample|` over the latest single row of one symbol's table — single-symbol, unbounded, never normalized toward 1.0, and not a co-movement measure. The regime gate (`regime.go:70-153`) then outlier-detects this raw magnitude and calls it contagion. +- `signal/causal/signal.go:114-124` hardcodes `"minHistory": 5.0`, `"window": 1.0`, never sets `history`; `pearl_sample.go:303-307` falls back to `minHistory`, so every symbol's causal buffer is a fixed 5 rows — OLS over 4 nodes × 5 rows sits at the rank floor. A literal fixed horizon. +- `signal/causal/ticker.go:57-60` (and book/trade) set `counterfactualReady = true` whenever `root == "output"`, regardless of whether Rung-3 actually ran; the ladder only computes uplift when `intervention > 0`, so "counterfactual ready" can report an untouched zero. +- The estimator itself (Frisch–Waugh residualization, ridge normal equations, Nadaraya–Watson weighting, condition number) is correctly implemented in `nomagique/causal/linear_fit.go` and `table.go`. The defects are in the node semantics and horizons feeding it. + +### depthflow + +- `nomagique/equation/bookflow.go:251-315` measures "Book Thinning: Rapidly Falling" as a static ratio of medians (`flatMedian/weightedMedian`) with **no rate/derivative** — nothing computes depth change over time, so the temporal crumbling story is absent. +- `nomagique/algorithm/bookflow_sample.go:275-282` trade-pressure EMA uses `smoothing = 2/(tradeFrameCount+1)` with an ever-incrementing, never-reset counter, so its effective window expands to the whole session — a de facto unbounded fixed horizon. +- `bookflow.go:159-171` spoof/thin/neutral scores are raw imbalance differences on different scales fed to the shared softmax. +- Magic caps/floors: `bookflow_sample.go:13-15` cap `64`, `bookflow.go:11` `minBookGateHistory = 3`, `bookflow_sample.go:531-535` `flatDepth` floored to `2`. + +### fluid + +- `signal/fluid/grid.go:179-190`, `grid_solver.go:66-84`: explicit Rusanov/RK2 advection+diffusion driven by `dt = integrationInterval.Seconds()` (default one minute) with **no CFL bound anywhere** (`max|v|·dt/dx ≤ 1`, `D·dt/dx² ≤ 1/2`). At minute-scale dt / tick-scale dx the scheme is unconditionally unstable. +- `grid_solver.go:55-64` Neumann ghost-copy boundaries (`rho[0]=rho[1]`) inject/delete mass every step, breaking the finite-volume conservation the framing claims; RK2 combine only touches interior cells. +- `grid_velocity.go:32-64`: velocity is built from the same `observedRho − remappedRho` residual that the source terms use, so `v` in `∂ρ/∂t + ∇·(ρv) = sources` is defined from the source residual — circular. +- `grid_velocity.go:12` `midPriceVelocity` divides by fixed dt not observed Δt; in the catch-up loop later sub-steps force velocity to 0. +- `grid_velocity.go:70-91` `estimateDiffusionCoefficient` returns `mean(|Δv|)/2` (velocity units) where `D` needs length²/time — dimensionally wrong, no length scale, no stability bound. +- `grid.go:365-399,505-541` `measureReplenishment`/Reynolds `flow` store incommensurable quantities (ratio vs rate·dt vs density-change/time) under one field and one set of quantile thresholds; `Re` returns `Inf` when `ν ≤ 0`. +- `grid.go:481-499` `medianObservedRho` sums positive densities and divides by *total cell count* — a count-diluted mean mislabeled median, while `stats.go:9 sampleQuantile` exists unused. +- `symbol.go:538-580` `priceMemoryFromSamples` is a 1-step ratio over a fixed 32-sample count, not the fractional-diff the spec claims. `symbol.go:517-536` `fluidViscosity` uses a bare `(1 + replenishment)` with dimensionally different branches. +- `grid_remap.go:24-46` piles out-of-domain mass onto edge cells then rescales, manufacturing a spurious source at the boundary whenever mid drifts ≥1 tick. `dynamics.go:33-48,111-121` append stamps unconditionally but values conditionally, desyncing `len(series) != len(stamps)`. + +### manifold + +- `field_config.go:29-30,96-105`: one global `DeltaT` (viper constant, or `1/bookDepth` fallback) divides every symbol's variance; `lastEventAt` is written (`field_feed.go:43,102,151`) but never read. Per-symbol temporal scale is discarded. +- `field_math.go:10-52` `returnAnalyticPhase` is `atan2` over a linear index ramp — not a Hilbert/analytic phase, but it is fed as `Oscillator.Phase`. `field_math.go:105-136` `returnFrequency` returns `2π/dt` on cold start (identical fabricated ω for every new symbol) and otherwise `sqrt(variance)/dt`, conflating return volatility with oscillation frequency. +- `field_deposit.go:17-18` deposits truncate the book to the **top level only** (`truncateLevels(...,1)`) while the grid is sized `bookDepth*4`; the depth profile collapses to two spikes. `field_deposit.go:111-158` `filterManifoldDensity` is an invented `alpha=|∇²ρ|/(|∇²ρ|+localMass)` mean-reversion with hard-coded 3-point stencil and `/2` — not the CFL-bounded diffusion the config enforces. +- `field_carriers.go:76-103` `liquidityRho` divides physical mass by `carrierCapacity = max(activeCarriers, MaxModes)` where `MaxModes` is a 256-thread GPU bound — mass scaled by hardware; whale path and book path use inconsistent `rho` scales. +- `signal.go:304-313` classifier features are raw/`1+`/negative-capable products, argmaxed over incommensurable scales; `RollingZScore` unused. `universe.go:205-219` orders the Z-axis by `medianAbsolute(returns)` (volatility) rather than the market-cap/beta ordering the spec's torus demands. `universe.go:80,471-472` `defaultBookDepth = 10` used as a per-level reference divisor. `field_step.go:15-16` advances exactly one fixed `DeltaT` per call regardless of real inter-arrival gap, decoupling the CFL guarantee from the data. + +### resonance + +- `attention.go:49-76` `AttentionCategoryIndex` is not attention (no query/key/value, no softmax, no temperature): stress is hard-assigned to latent index 1 via `abs(z[1]) > abs(z[0])+abs(z[2])`, and the autoencoder is fixed-seed (`rand.NewSource(42)`), so the axis has no guaranteed meaning. `attention.go:78-132` confidence/strength are bare reciprocals (`1/(1+surprise)`) maxed against unbounded raw activation or `abs(spread)` in bps — incommensurable; `:98` rewards a *more negative* invalid spread. +- `baselines.go:26-33,41-77` misuses `ResolveWindows` (return-value and value-series both wrong, per cross-cutting) and cold-starts with synthetic "normal" readings (`return 1`) — biasing exactly the obscure movers it targets. +- `sensory_facts.go:109,120` channels 0 and 11 (`changePct` and `|changePct|`) share one baseline ring, contaminating its MAD; channel 11 double-counts channel 0. `sensory.go:186-217` `buyPressure` divides net notional by `abs(net)` → collapses to `sign(net)` (±1), destroying imbalance magnitude. `sensory.go:199-206` trade rate divides by the whole ring span, not a rolling window. `sensory_facts.go:55,97` `tickCadence` overwrites the ticker clock with the trade clock and floors at a magic `1e-3`. +- `batch_engine_cpu.go:52` + `learning/resonance.go:147` reset every symbol to identical fixed-seed weights, wiping per-symbol adaptation on churn. `batch_engine_cpu.go:86-90` advances temporal state twice per settle (`Settle(...,true)` then `Learn(nil)`), corrupting the temporal-coupling error. `signal.go:352-378` the confidence gate almost never fires, `strength = peakActivation` (raw), and baselines are the constant `1/latentWidth`. + +### pumpdump + +- `signal.go:19-22` spec ("derived from the pair's tick cadence") vs `ticker.go:52-53` + `nomagique/statistic/mean_median_ratio.go:237-290`: window hint 0 → window = frame count; `shortWindow==longWindow==len(history)` so RVOL short-mean and long-median are over the same slice, and `if longMedian <= 0 { longMedian = shortMean }` pins the ratio to 1. +- `ticker.go:59-70` `positiveOnly: 1.0` clamps the precursor z-score at 0 — all four states are pump-side, so despite the name the package cannot detect a dump. +- `ticker.go:135-175` the ticker path (unlike book/trade) swallows the RoundTrip error and stamps the `0.25`-uniform fallback with `category = trend`. `book.go`/`trade.go` (`:71-123`) carry the same uniform default. + +### exhaust + +- `signal.go:19-65` spec ("series lengths derived from observed cadence") vs `nomagique/algorithm/decay_sample.go:20,314`: `ResolveWindows` derives from `sqrt(sampleCount)` over fixed-cap-64 rings; `timeline` unimported. +- `nomagique/equation/decay.go:130-349`: `depthTrend`, `spreadWiden`, `pressureFade` are all one-sided/positive-only; only `imbalanceFlip` is sign-aware, and `lastPrice` (`:51`) is validated but never used — so the price-rejection half of the mandated "lift decline AND price rejection" is entirely missing. `signal.go:200-252` carries the `0.25`-uniform fallback. + +### toxicity + +- `signal.go:182-230` `completeMeasurement` synthesizes `probabilities [1/3,1/3,1/3]` with `category = HardSupport` when the BookQuality stage emits nothing, and is called unconditionally at the end of `level3.go:60`/`trade.go:55` — a no-evidence frame exits as the directional conclusion "the wall will hold," not an abstention. +- `nomagique/algorithm/book_quality_sample.go`: EMA `smoothing = 2/(frameCount+1)` (expanding window keyed to event count, not a half-life); `resolvedGatePercentile` uses hard floors/ceilings (`0.5`/`0.75`/`0.9`), a `< 3`-frame warm-up, and a `/17` ramp; touch-price detection uses exact float `==` (any representational drift silently reclassifies a touch), inconsistent with the MAD-tolerant fill matcher. +- Correct: `IngestRoles` is `["level3","trade"]` only, so L2 qty deltas are never used as a cancel/fill fallback, and fill labels come from matching L3 deletes against actual trade prices — this honors the spec. + +### liquidity + +- `signal.go:92-110` bypasses the spec-faithful `nomagique/equation/depth.go` (25/50/75 peer quantiles + baseline gate) entirely; `median` is the cross-sectional median of the raw 24h summary `volume` field — one instantaneous snapshot, no window. `scarcity = 1-relative`, `depth = relative-1` are bare deviations of a ratio from 1.0 with no dispersion in the denominator (a 2× and a 10× event are indistinguishable in σ). `balance = 1/(1+|relative-1|)` is strictly positive, so the signal fires for every row; `relative` collapses to 1 when peers < 2. + +### sentiment + +- `signal.go:91-114` is built directly from the raw 24h `change_pct` summary field — the "scoring ticker summary fields and calling it microstructure" anti-pattern — with no entropy/KL/z-score against a live baseline (`statistic/entropy.go`, `kl.go`, `rolling_zscore.go` unused). `surgeScore`/`divergentScore`/`slumpScore` are ad-hoc products with `(1-breadth)` and `1/(1+leaderEvidence)` forms; `relativeLead` is a hard 0/1 indicator so `divergentScore` is identically 0 for every non-leader, while `slumpScore` is non-zero for every non-leader (a systemic-slump default hidden by the confidence≤0 silent drop). `cross_section.go:197-238` assumes one temporal scale for all symbols. + +--- + +## 2. Code shape vs the compositional pattern + +Rules (`AGENTS.md`): methods over loose functions; compose types (don't just move methods to new files); file ≤400 (target 200); method ≤60 (target 30); type ≤10 methods; guard clauses + early return; no `else`; nesting ≤2; names one–two segments; no silent fallbacks. Naming discipline is otherwise well-observed — no single-character receivers or locals were found, and the `errnie` error style is applied consistently. + +**Files over the 400-line ceiling** (≈42 more sit in the 200–400 over-target band): `broker/desk.go` **1613**, `market/cognitive.go` 701, `signal/fluid/grid.go` 600, `signal/fluid/symbol.go` 580, `kraken/public/response/order.go` 541, `signal/manifold/universe.go` 486, `signal/resonance/signal.go` 463, `logic/operand.go` 434, `market/cross_section.go` 429, `trader/decide.go` 423. `broker/desk.go` at 4× the ceiling is its own subsystem — its doc comment says "Desk only owns the live stop map and forwards orders," but the file also does order construction, quantity/price resolution, balance caching, pending-order lifecycle, diagnostics publishing, and native-protective-stop submission: five-plus responsibilities that the pattern says to compose out. + +**Methods over 60 lines:** `Orders.Send` (`kraken/public/response/order.go` ~82-313, ~232 lines, `switch` with a ~150-line inline `add_order` payload, 3+ nesting levels); `ConditionOperand.Resolve` (`logic/operand.go:52-395`, ~343 lines, one `switch` over `SubjectType`, the `SubjectEigenmode` arm alone `:252-387` has nested loops and an inline closure); `hydrateFieldFromTree` (`signal/manifold/observe.go:11-96`, nested 4-5 levels); `ConditionType.Evaluate` (`logic/condition.go:26-172`, ~146 lines); `readingFromEngine` (`market/cognitive.go:385-498`); `crypto.Run` (`trader/crypto.go:164-316`, ~152 lines); `feedBookLocked` (`signal/fluid/symbol.go:239-317`); `websocket.Run` (`kraken/public/websocket.go:156-235`); `manifold.Measure` (`signal/manifold/signal.go:129-198`). + +**Types over 10 methods:** `CrossSection` (~28 methods, `market/cross_section.go`); `FluidGrid` (~22 methods + ~30 fields, `signal/fluid/grid.go:15-51`); `FluidSymbol` (~19); manifold `Signal` (~16 across `signal.go`+`observe.go` — split into a second *file*, which `AGENTS.md:148` explicitly calls out as *not* the intended fix); `Desk` (25 struct fields `:28-54` + dozens of associated functions — a god-type). + +**Over-guarding (guard outweighing logic):** `logic/condition.go` `ConditionType.Evaluate` — 11 near-identical `case` arms whose real work is one comparison but whose error plumbing is ~6 lines each, re-wrapping an already-`errnie`-wrapped error in a second `errnie.Err(errnie.Validation, err.Error(), err)`; that double-wrap idiom (message = `err.Error()` *and* cause = `err`) appears 16× in this file and 55× across 21 files. `trader/crypto.go` reconstructs-and-revalidates the balances artifact three times (`:141-149`, `:187-191`, `:257-265`) with the same `origin=="" || scope=="" || len(payload)==0` guard. `market/story.go:58-66` re-initializes `symbols`/`dirty` with nil-checks that `NewStory:34-49` already guarantees. Pervasive `if == nil` on types only ever built via their `New…` constructor (`Desk.storePending:458`, `releaseAckLock:482`, `pendingByClientOrExchangeID:572`, etc.). + +**Loose functions that should be methods on a composed type:** `broker/desk.go` — ~16 free functions operating on order/execution/action artifacts (`actionAllowedForDispatch:238`, `actionSetupKey:256`, `terminalExecutionStatus:420`, `executionOrderIDs:734`, `requiresTriggerPrice:982`, `executionQuantity:1389`, `baseAsset:1206`, `artifactOrderID:1546`, …) — the behavior of would-be `Order`/`Execution`/`PendingOrder` types. `market/positions.go` — the *entire* file is package functions taking `tree *dmt.Tree` as the first arg (`PositionReadings`, `latestBalances`, `openPositions`, `latestMark`, …) — textbook `Positions{tree}` type. `market/cognitive.go` — a `CognitiveEvaluator` type exists (`:60-63`) but the real work lives in free functions beside it (`cognitiveObservations:185`, `readingFromEngine:385`, `cognitiveBranches:560`, `bestBeamScore:685`). + +**`else` blocks and deep nesting:** `else` appears 16×, e.g. `signal/sentiment/signal.go:104`, `signal/resonance/attention.go:66`, `signal/correlation/signal.go:222`, `market/cognitive.go:450,674`, `market/positions.go:56-68` (a three-branch nested else-if chain), `broker/desk.go:369,1504,1576`. Nesting past two levels: `hydrateFieldFromTree`, `Orders.Send`, `ConditionOperand.Resolve`, `cognitiveBranches` (recursion). + +**Convoluted / pass-through indirection:** `market/story.go:125-128` `Actions` is a pass-through to `ActionsWithTrace` that silently discards the error/trace. `logic/condition.go:229-249` `Condition.Evaluate` passes through to `Type.Evaluate` adding only another redundant re-wrap. `signal/fluid/symbol.go:235-237` `FeedBook` → `feedBookLocked` (the `…Locked` suffix implies a mutex the struct no longer has). `signal/fluid/grid.go` one-line getters that just rename private fields (`midAddRateAtTouch:401`, `viscosity:443`, `reynolds:501`). `kraken/public/response/order.go:527-535` a bespoke `fillPriceError` string type where `fmt.Errorf` would do. + +**Names mutating something other than themselves:** `market/cognitive.go:314` `ApplyCognitiveReadings` (three-segment, and it mutates the `measurements` slice passed in, not a receiver — the exact `AGENTS.md:190-195` anti-pattern). `broker/desk.go` `submitNativeProtectiveStop:1230`, `markProtectiveWorking:631`, `publishCriticalStopDiagnostic:1407` — three-segment names, several mutating `Stoploss` state rather than Desk's own. + +**Silent fallbacks / swallowed errors:** `signal/resonance/signal.go:424-430` `observedAt` returns `time.Now()` when the timestamp is zero — a default substituting for missing data. `signal/manifold/observe.go` `instrumentTick` returns `0` on every failure path; `observeBook/Trade/Ticker` and `forEachKrakenElement` silently drop elements on `json.Unmarshal` failure (`if json.Unmarshal(...) == nil`) — inconsistent with `panic`-on-feed-error in the *same* file (`:179,246,289`). `signal/manifold/universe.go` `loadSymbol:159`/`registerSymbols:173`/`loadIdentity:136` return nil/continue on error; `configureTickFromBook` replaces the wrapped cause with a fixed `fmt.Errorf("manifold: tick size is zero")`. `broker/stoploss_snapshot.go:62-71` swallows unmarshal failures (`return nil`). `market/story.go:173-195` logs `Evaluate`/`Marshal` errors but proceeds with partial candidates. + +--- + +## 3. Re-implementation of existing primitives + +Confirmed available and bypassed: `nomagique/statistic` (Mean, Median/`MedianOf`, MedianAbsolute/`MedianAbsoluteOf`, StdDev, Quantile, RollingZScore, Entropy, KL, ResolveWindows, ObservationRing, PriceRing), `nomagique/probability` (Softmax, Classifier, CUSUM), `nomagique/correlation` (Pearson→gonum, Covariance, HayashiYoshida), `datura/structure` (SPSCRing, MPMCRing, UltraRingBuffer, ListRing, ClockRing). symm imports only `ClockRing`/`ListRing`; `SPSCRing`/`MPMCRing`/`UltraRingBuffer` have **zero references** in symm. + +**Statistics rolled by hand instead of `nomagique/statistic`:** `market/peer_cache.go:148,169,177,180,191` (median/median-abs via direct `gonum stat.Quantile`, skipping the nomagique NaN/Inf guards); `signal/manifold/universe.go:324` `median`, `:307` `medianAbsolute`; `signal/leadlag/section_correlation.go:245` `meanStdDev`; `signal/manifold/field_math.go:112-131` mean+variance; `signal/fluid/grid.go:574-591` mean+variance; `signal/fluid/stats.go:9` `sampleQuantile`; `market/cross_section.go:219-221,419` direct `stat.Quantile(0.5,...)`. + +- **`signal/manifold/universe.go:307` `medianAbsolute` is a genuine bug, not just duplication.** It sorts the *raw* values and returns `|sorted[mid]|` — i.e. the absolute value of the median — whereas `nomagique/statistic.MedianAbsoluteOf` sorts the *absolute* values first. These differ whenever the input has negatives; the local version is not a median-of-absolutes at all. *(Re-read and confirmed.)* + +**Correlation rolled by hand instead of `nomagique/correlation`:** `signal/leadlag/section_correlation.go:222` `pearson` (full hand-rolled mean/stddev/covariance/ratio) duplicates both `correlation/Pearson` and the `gonum stat.Correlation` it wraps; `market/peer_cache.go:61,91` call `gonum stat.Correlation` directly, bypassing the project's `Pearson` wrapper. + +**Ring buffers rolled instead of `datura/structure`:** `signal/resonance/feed_ring.go:20` `symbolRing` (hand-rolled fixed-capacity ring with parallel typed columns — the role of `SPSCRing`/`ListRing`); `signal/resonance/baselines.go:10` `scalarRing` (overlaps `statistic.ObservationRing`/`PriceRing`). + +**Near-duplicate files:** `kraken/public/websocket.go` (385) vs `replayer.go` (351) are near-verbatim twins (`onMessage`, `Run`, `Error`, `Close`, `Connect`, `disconnect`, `setConnection`, `writeMessage`, …) — and they have already diverged into a bug: `WebSocket.setConnection:331-334` does **not** lock `connMu` while `Replayer.setConnection:292-298` does. `signal/manifold/ticksize.go` vs `signal/fluid/ticksize.go` are byte-identical except package name and one helper. The per-role `trade.go`/`book.go`/`ticker.go` files across signal packages repeat the identical `Measure → parse timestamp → SetTimestamp → RoundTripArtifact → SetOrigin → completeMeasurement` skeleton with only a per-package origin constant differing. + +--- + +## 4. Lock-free & performance + +The tick loop (`trader/crypto.go:167`, 100ms) calls `signals.Measure()` → each signal's `Measure` (run **sequentially** in one goroutine, `trader/signal.go:261-273` — the "concurrent signal reads" comment at `:239-241` is aspirational, nothing fans out) → `cross_section` / `peer_cache` / `story`. + +**Locks on/near the hot path that should be lock-free:** + +- `trader/signal.go:53,55` `pendingMu`/`regimeMu`. `pendingMu` guards a `[]*datura.Artifact` produced in `onMessage` and swapped out in `Measure` — a textbook SPSC hand-off that `datura/structure/spsc.go` (`SPSCRing`) or `mpmc.go` exist to replace. `regimeMu` guards a single `*datura.Artifact` pointer with a cross-goroutine reader (`Regime()` from `crypto.Run`) — replaceable by `atomic.Pointer`. +- `trader/crypto.go:43` `balancesMu sync.RWMutex` guards five scalar fields, read on **every tick** (`:238-244`) plus a defensive per-tick `append([]byte(nil),...)` copy under lock. A snapshot behind `atomic.Pointer[balancesSnapshot]` makes the tick read a single atomic load. +- `market/story.go:23,24` `symbols`/`dirty` are `sync.Map` but `Update` and `ActionsWithTrace` both run single-goroutine (`crypto.go:273-274`), so `sync.Map` only adds boxing + `LoadOrStore` allocation per tick over a plain map. +- Per-symbol `sync.Map` state read/written inside every signal's single-goroutine `Measure`: `resonance/signal.go:97,98`, `feed_ring.go:34`, `baselines.go:99`; `manifold/field_types.go:22` (which even documents "single-owner signal job"), `universe.go:49`; `fluid/registry.go:11`; `leadlag/section.go:32`. Each pays `sync.Map` overhead for concurrency that is never exercised; `leadlag/section.go:110` `ensure` also allocates a throwaway `&symbolState{}` on every `LoadOrStore`. +- `signal/resonance/batch_engine.go:39` `slotRegistry.mutex` on the per-tick settle path (single-writer in practice; the one lock where a lock-free replacement is genuinely non-trivial). + +**Concurrency correctness hazards:** `structure.ListRing` is **not thread-safe** (`structure/list.go:69`, plain non-atomic `Push`), yet it is stored in `story.go`'s `sync.Map` that advertises concurrency — safe only because access is currently single-goroutine. `trader/crypto.go` `crypto.state` (`:30`, plain `uint8`) is read/written across goroutines (`:170`, `:209`) **without atomics** — a data race, with a `tick *atomic.Int64` sitting right beside it showing the available pattern. The whole shared-mutable-stage design (one `market.Signal` per source reused across all symbols and ticks, holding plain unsynchronized fields like `leadlag/section.go:33-34 anchorSymbol`/`moveHistory`) is one fan-out away from immediate races — exactly the fan-out the `:239-241` comment says is intended. + +**Hot-path allocations (every tick):** `trader/signal.go:135-139` builds a formatted string per elapsed second, then `:161` does `[]byte(role+"/update/"+prefix)` (string concat + fresh `[]byte`) per (prefix × role). `:141,182,183` new maps per tick. `:159-179` `datura.Acquire` per walked frame — and `datura.Acquire` (`datura/artifact.go:18`) is **not pooled**: it allocates a capnp segment, `NewRootArtifact`, a `uuid.NewString()` (`:34`) and three `Set*` calls, while `Release()` (`:160`) is a no-op. This is the single largest per-tick allocation source; `sync.Pool` precedent exists (`datura/transport/copier.go:12`). `:213-218` and `:257-259` run **two `sort.Slice` per tick** (reflection-based, closure alloc) over data that `WalkPrefix` already returns in timestamp order — a k-way merge of the already-sorted role buckets would avoid both. `datura.Peek` (`datura/attributes.go:13`) does a full `sonic` JSON AST parse **per field access** and is called pervasively (`:152,186,188,201,203,262` plus inside every signal), re-parsing the same symbol 2-3× per artifact with no caching. + +**Repeated / O(n²) recomputation per tick:** `market/cross_section.go:165` `refreshAggregates` runs on *every* ticker row, looping all symbols and rebuilding `volumes`/`absChanges` from scratch — O(symbols × rows) per tick for incrementally-updatable aggregates; `:143` `refreshConfig` re-runs `ResolveWindows` and allocates a config artifact per row. `MajorityThreshold:218`, `Leader:284`, `leadershipThreshold:420` each `append`-copy and `sort.Float64s` the full buffer per call. `market/peer_cache.go` is O(symbols² × window): `build:74` correlates each peer against a `marketReturns:140-153` that `sort.Float64s` a column *per time index*, and `marketReturnsExcluding:155` re-runs the whole leave-one-out median build per symbol, bypassing the cache — whose `crossSection.version` key is invalidated on every observed row anyway (`cross_section.go:164`). `trader/signal.go:161` issues a separate `WalkPrefix` per role per second-prefix per tick (5×k scans for a k-second tick), when `dmt.Tree.WalkLowerBound` (`tree.go:193`) exists precisely to scan `[role/timestamp, next-role)` without manufacturing every intermediate second prefix. + +**Tree access is genuinely lock-free** — `WalkPrefix`/`Seek`/`Get` do a single `atomic.Pointer.Load` over an immutable radix snapshot (`datura/dmt/tree.go:37-49,127,169,323`); `Insert`/`Delete` use a CAS retry loop. The only tree lock is `persistMu` (`tree.go:30`), held across WAL append + root store in the persistent-write branch (`tree_persistence.go:43,89`), which serializes ingest writers when persistence is enabled but does not touch the read-only Measure path. `broker/desk.go:48 treeMu` wraps already-CAS-safe tree ops — redundant serialization unless it is guarding a multi-call read-modify-write (worth confirming at `desk.go:1500,1572`). + +**Busy-wait:** `trader/crypto.go:170-211` readiness polls with `time.Sleep(1s)`, re-`RLock`-ing, copying the payload, and rebuilding+JSON-peeking a balances artifact every second until ready — a `close(ready chan struct{})` from `onMessage` removes the spin. If a tick's work exceeds 100ms (plausible given the O(n²) peer work), ticks silently coalesce on `ticker.C`. + +--- + +## Notes on verification + +Per `AGENTS.md`, findings that touch code paths need tests/benchmarks run to close them out; this review is static and does not execute the suite. **VERIFICATION LIMITATION: tests and benchmarks were not run as part of this review.** To confirm the correctness findings before acting, the relevant commands would be `go test ./...` in each of the three repos and `go test -bench . -benchmem ./signal/...` and `./trader/...` in symm. Two representative claims (hawkes `organicHeadroomScores` shadowing at `nomagique/algorithm/excitation_symbol.go:466,484`, and manifold `medianAbsolute` at `signal/manifold/universe.go:307`) were re-read directly and confirmed; the remainder are traced from source with quoted lines but not independently executed. diff --git a/audit/writer.go b/audit/writer.go index 0b634fe0..f13773f5 100644 --- a/audit/writer.go +++ b/audit/writer.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "path/filepath" + "sync" "github.com/bytedance/sonic" "github.com/theapemachine/errnie" @@ -12,10 +13,9 @@ import ( /* Recorder is a generic jsonl data recorder that can be used anywhere we need to record data to a file. -Producers marshal locally and append with O_APPEND so concurrent Write calls -need no mutex or channel. */ type Recorder struct { + mu sync.Mutex filename string fh *os.File } @@ -46,7 +46,18 @@ func NewRecorder(filename string) (*Recorder, error) { } func (recorder *Recorder) Write(event any) error { - if recorder == nil || recorder.fh == nil { + if recorder == nil { + return errnie.Error(errnie.Err( + errnie.IO, + "audit: recorder is closed", + nil, + )) + } + + recorder.mu.Lock() + defer recorder.mu.Unlock() + + if recorder.fh == nil { return errnie.Error(errnie.Err( errnie.IO, "audit: recorder is closed", @@ -80,7 +91,18 @@ func (recorder *Recorder) Write(event any) error { } func (recorder *Recorder) Close() error { - if recorder == nil || recorder.fh == nil { + if recorder == nil { + return errnie.Error(errnie.Err( + errnie.IO, + "audit: recorder is closed", + nil, + )) + } + + recorder.mu.Lock() + defer recorder.mu.Unlock() + + if recorder.fh == nil { return errnie.Error(errnie.Err( errnie.IO, "audit: recorder is closed", diff --git a/broker/desk.go b/broker/desk.go index b114c707..484b84cf 100644 --- a/broker/desk.go +++ b/broker/desk.go @@ -2,47 +2,219 @@ package broker import ( "context" + "errors" + "strings" + "sync" "github.com/theapemachine/datura" - "github.com/theapemachine/datura/dmt" - "github.com/theapemachine/qpool" + "github.com/theapemachine/errnie" + "github.com/theapemachine/symm/kraken" + "github.com/theapemachine/symm/kraken/websocket" +) + +const ( + channelTicker = "ticker" + channelBalances = "balances" + channelExecutions = "executions" + channelOrders = "orders" ) -/* -Desk is the link between the trader and the Kraken exchange. It is responsible -for managing orders and executions, as well as keeping track of stoplosses, -managing risk, etc. -*/ type Desk struct { - ctx context.Context - cancel context.CancelFunc - pool *qpool.Q[any] - tree *dmt.Tree + ctx context.Context + cancel context.CancelFunc + channels map[string]chan []byte + public websocket.Socket + private websocket.Private + balance *kraken.BalanceDataSlice + executions []*kraken.ExecutionDataSlice + orders *kraken.PaperOrderSlice + positions *sync.Map + UIForward chan []byte } func NewDesk( - ctx context.Context, pool *qpool.Q[any], tree *dmt.Tree, -) *Desk { + ctx context.Context, + public websocket.Socket, + private websocket.Private, +) (*Desk, error) { ctx, cancel := context.WithCancel(ctx) - return &Desk{ - ctx: ctx, - cancel: cancel, - pool: pool, - tree: tree, + if public == nil { + cancel() + return nil, errnie.Error(errnie.Err( + errnie.Validation, + "broker: public stream required", + nil, + )) + } + + if private == nil { + cancel() + return nil, errnie.Error(errnie.Err( + errnie.Validation, + "broker: private stream required", + nil, + )) } + + return &Desk{ + ctx: ctx, + cancel: cancel, + public: public, + private: private, + positions: &sync.Map{}, + channels: map[string]chan []byte{ + channelTicker: public.Observe(channelTicker), + channelBalances: private.Observe(channelBalances), + channelExecutions: private.Observe(channelExecutions), + channelOrders: private.Observe(channelOrders), + }, + }, nil +} + +func (desk *Desk) Ready() bool { + return errnie.Require(map[string]any{ + "balance": desk.balance, + }) == nil +} + +func (desk *Desk) OpenPositions() int { + open := 0 + + desk.positions.Range(func(_ any, value any) bool { + open += len(value.([]*Position)) + return true + }) + + return open } /* -Update the desk about any new price movements, balance changes, or other events -that are relevant for the desk to do its job. +Run processes websocket and private frame streams until ctx closes. */ -func (desk *Desk) Update(artifact *datura.Artifact) error { +func (desk *Desk) Run() (err error) { + for { + select { + case <-desk.ctx.Done(): + return nil + case msg := <-desk.channels[channelBalances]: + desk.balance = kraken.NewBalanceDataSlice(msg) + case msg := <-desk.channels[channelExecutions]: + slice := kraken.NewExecutionDataSlice(msg) + desk.executions = append(desk.executions, slice) + case msg := <-desk.channels[channelOrders]: + desk.orders = kraken.NewPaperOrderSlice(msg) + case msg := <-desk.channels[channelTicker]: + for _, ticker := range kraken.NewTickerDataSlice(msg) { + position, ok := desk.positions.Load(ticker.Symbol) + + if ok { + for _, position := range position.([]*Position) { + position.Update(ticker) + } + } + } + } + + positions := make([]PositionData, 0) + + desk.positions.Range(func(_ any, value any) bool { + for _, position := range value.([]*Position) { + positions = append(positions, position.Data()) + } + + return true + }) + + out := datura.Map[any]{} + + if desk.balance != nil { + out["balance"] = desk.balance + } + + if len(desk.executions) > 0 { + out["executions"] = desk.executions + } + + if desk.orders != nil { + out["orders"] = desk.orders + } + + if len(positions) > 0 { + out["positions"] = positions + } + + desk.UIForward <- out.Marshal() + } +} + +func (desk *Desk) Buy(symbol string, fraction float64, price float64) error { + position, err := NewPosition( + desk.private, + desk.balance, + symbol, + fraction, + price, + ) + + if err != nil { + return errnie.Error(errnie.Err( + errnie.UnprocessableContent, + err.Error(), + err, + )) + } + + if err := position.Enter(); err != nil { + return errnie.Error(errnie.Err( + errnie.UnprocessableContent, + err.Error(), + err, + )) + } + + positionData := position.Data() + positions, ok := desk.positions.LoadOrStore(positionData.Symbol, []*Position{position}) + + if ok { + desk.positions.Store( + positionData.Symbol, + append(positions.([]*Position), position), + ) + } + + return nil +} + +func (desk *Desk) Sell(symbol string) (err error) { + symbol = strings.TrimSpace(symbol) + positions, ok := desk.positions.Load(symbol) + + if !ok { + return errnie.Error(errnie.Err( + errnie.NotFound, + "position not found", + nil, + )) + } + + for _, position := range positions.([]*Position) { + err = errors.Join(err, position.Exit()) + } + + if err != nil { + return errnie.Error(errnie.Err( + errnie.UnprocessableContent, + err.Error(), + err, + )) + } + + desk.positions.Delete(symbol) return nil } func (desk *Desk) Close() error { desk.cancel() - return nil } diff --git a/broker/desk_test.go b/broker/desk_test.go new file mode 100644 index 00000000..4583a1f6 --- /dev/null +++ b/broker/desk_test.go @@ -0,0 +1,229 @@ +package broker + +import ( + "context" + "encoding/json" + "sync" + "testing" + "time" + + "github.com/bytedance/sonic" + "github.com/theapemachine/symm/kraken" + + . "github.com/smartystreets/goconvey/convey" +) + +type recordingSocket struct { + channels map[string]chan []byte +} + +func (socket *recordingSocket) Observe(channel string) chan []byte { + if socket.channels == nil { + socket.channels = map[string]chan []byte{} + } + + if socket.channels[channel] == nil { + socket.channels[channel] = make(chan []byte, 4) + } + + return socket.channels[channel] +} + +type recordingPrivate struct { + recordingSocket + orders []*kraken.Order +} + +func (private *recordingPrivate) Submit(order *kraken.Order) error { + private.orders = append(private.orders, order) + return nil +} + +func (private *recordingPrivate) Close() { +} + +func TestDeskRun(testingTB *testing.T) { + Convey("Given a desk with public and private byte streams", testingTB, func() { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + public := &recordingSocket{} + private := &recordingPrivate{} + desk, err := NewDesk(ctx, public, private) + + So(err, ShouldBeNil) + desk.UIForward = make(chan []byte, 4) + + Convey("When balance, execution, and order payloads arrive", func() { + done := make(chan error, 1) + go func() { + done <- desk.Run() + }() + + private.channels[channelBalances] <- []byte(`[{ + "asset": "USD", + "asset_class": "currency", + "balance": 200.18 + }]`) + private.channels[channelExecutions] <- []byte(`[{ + "exec_id": "PAPER-00002", + "order_id": "PAPER-00002", + "symbol": "NEAR/USD", + "side": "sell", + "order_status": "filled", + "order_qty": 20, + "fee": 0.104 + }]`) + private.channels[channelOrders] <- []byte(`[{ + "id": "PAPER-00003", + "pair": "NEARUSD", + "price": 1.8, + "reserved_amount": 18, + "reserved_asset": "USD", + "side": "buy", + "type": "limit", + "volume": 10, + "created_at": "2026-07-06T10:00:00Z" + }]`) + + time.Sleep(10 * time.Millisecond) + cancel() + + Convey("Then the desk should retain the decoded state", func() { + So(<-done, ShouldBeNil) + So(desk.balance, ShouldNotBeNil) + So(*desk.balance, ShouldHaveLength, 1) + So((*desk.balance)[0].Asset, ShouldEqual, "USD") + So(desk.executions, ShouldHaveLength, 1) + So((*desk.executions[0])[0].ExecID, ShouldEqual, "PAPER-00002") + So(desk.orders, ShouldNotBeNil) + So(*desk.orders, ShouldHaveLength, 1) + So((*desk.orders)[0].ID, ShouldEqual, "PAPER-00003") + }) + + Convey("Then the desk should forward named UI batches", func() { + frames := map[string]json.RawMessage{} + deadline := time.After(time.Second) + + for len(frames) < 3 { + select { + case wire := <-desk.UIForward: + frame := map[string]json.RawMessage{} + So(sonic.Unmarshal(wire, &frame), ShouldBeNil) + + for key, rows := range frame { + frames[key] = rows + } + case <-deadline: + testingTB.Fatal("desk did not forward named UI batches") + } + } + + balances := []map[string]any{} + executions := [][]map[string]any{} + orders := []map[string]any{} + + So(sonic.Unmarshal(frames["balance"], &balances), ShouldBeNil) + So(sonic.Unmarshal(frames[channelExecutions], &executions), ShouldBeNil) + So(sonic.Unmarshal(frames[channelOrders], &orders), ShouldBeNil) + So(balances, ShouldHaveLength, 1) + So(balances[0]["asset"], ShouldEqual, "USD") + So(executions, ShouldHaveLength, 1) + So(executions[0][0]["exec_id"], ShouldEqual, "PAPER-00002") + So(orders, ShouldHaveLength, 1) + So(orders[0]["id"], ShouldEqual, "PAPER-00003") + }) + }) + }) +} + +func TestDeskOpenPositions(testingTB *testing.T) { + Convey("Given a desk that opens positions through buy orders", testingTB, func() { + public := &recordingSocket{} + private := &recordingPrivate{} + desk, err := NewDesk(context.Background(), public, private) + + So(err, ShouldBeNil) + balance := kraken.BalanceDataSlice{{ + Asset: "USD", + Available: 200, + Balance: 200, + }, { + Asset: "EUR", + Available: 500, + Balance: 500, + }} + desk.balance = &balance + + So(desk.OpenPositions(), ShouldEqual, 0) + + Convey("When buys are submitted", func() { + firstErr := desk.Buy("BTC/USD", 0.05, 100000) + secondErr := desk.Buy("SOL/USD", 0.10, 20) + + Convey("Then only tracked positions count as open", func() { + So(firstErr, ShouldBeNil) + So(secondErr, ShouldBeNil) + So(desk.OpenPositions(), ShouldEqual, 2) + So(private.orders, ShouldHaveLength, 2) + }) + }) + + Convey("When a tracked symbol is sold", func() { + So(desk.Buy("BTC/USD", 0.05, 100000), ShouldBeNil) + So(desk.Buy("SOL/USD", 0.10, 20), ShouldBeNil) + sellErr := desk.Sell("BTC/USD") + + Convey("Then the matching position is removed", func() { + So(sellErr, ShouldBeNil) + So(desk.OpenPositions(), ShouldEqual, 1) + _, btcOpen := desk.positions.Load("BTC/USD") + solPositions, solOpen := desk.positions.Load("SOL/USD") + So(btcOpen, ShouldBeFalse) + So(solOpen, ShouldBeTrue) + So(solPositions.([]*Position), ShouldHaveLength, 1) + }) + }) + }) +} + +func TestDeskBuy(testingTB *testing.T) { + Convey("Given a desk with a private submitter", testingTB, func() { + public := &recordingSocket{} + private := &recordingPrivate{} + desk, err := NewDesk(context.Background(), public, private) + + So(err, ShouldBeNil) + balance := kraken.BalanceDataSlice{{ + Asset: "USD", + Available: 200, + Balance: 200, + }} + desk.balance = &balance + + Convey("When Buy submits a market order", func() { + err := desk.Buy("BTC/USD", 0.05, 100000) + + Convey("Then it should submit a Kraken order", func() { + So(err, ShouldBeNil) + So(private.orders, ShouldHaveLength, 1) + So(private.orders[0].Method, ShouldEqual, "add_order") + params := private.orders[0].Params.(kraken.LimitOrderParams) + So(params.OrderQty, ShouldAlmostEqual, 0.0001) + }) + }) + }) +} + +func BenchmarkDeskOpenPositions(benchmarkTB *testing.B) { + desk := &Desk{ + positions: &sync.Map{}, + } + desk.positions.Store("BTC/USD", []*Position{{Symbol: "BTC/USD", Qty: 0.01}}) + desk.positions.Store("SOL/USD", []*Position{{Symbol: "SOL/USD", Qty: 3.5}}) + + benchmarkTB.ReportAllocs() + for benchmarkTB.Loop() { + _ = desk.OpenPositions() + } +} diff --git a/broker/position.go b/broker/position.go new file mode 100644 index 00000000..ba676f31 --- /dev/null +++ b/broker/position.go @@ -0,0 +1,166 @@ +package broker + +import ( + "strings" + "sync" + "time" + + "github.com/theapemachine/errnie" + "github.com/theapemachine/symm/kraken" + "github.com/theapemachine/symm/kraken/websocket" +) + +type PositionData struct { + Symbol string `json:"symbol"` + Qty float64 `json:"qty"` + EntryPrice float64 `json:"entry_price"` + Mark float64 `json:"mark"` + PnL float64 `json:"pnl"` + ReturnPct float64 `json:"return_pct"` +} + +type Position struct { + private websocket.Private + mu sync.RWMutex + data PositionData + Symbol string + Qty float64 +} + +func NewPosition( + private websocket.Private, + balance *kraken.BalanceDataSlice, + symbol string, + fraction float64, + price float64, +) (*Position, error) { + symbol = strings.TrimSpace(symbol) + _, quote, ok := strings.Cut(symbol, "/") + + if !ok || strings.TrimSpace(quote) == "" { + return nil, errnie.Error(errnie.Err( + errnie.Validation, + "broker: buy symbol must include base and quote", + nil, + )) + } + + if fraction <= 0 || fraction > 1 { + return nil, errnie.Error(errnie.Err( + errnie.Validation, + "broker: buy fraction must be within the quote balance", + nil, + )) + } + + if price <= 0 { + return nil, errnie.Error(errnie.Err( + errnie.Validation, + "broker: buy price must be positive", + nil, + )) + } + + if balance == nil { + return nil, errnie.Error(errnie.Err( + errnie.Validation, + "broker: balance required", + nil, + )) + } + + notional := 0.0 + for _, row := range *balance { + if strings.EqualFold(row.Asset, quote) { + notional = row.Available * fraction + break + } + } + + if notional <= 0 { + return nil, errnie.Error(errnie.Err( + errnie.Validation, + "broker: buy quote balance must be positive", + nil, + )) + } + + return &Position{ + private: private, + data: PositionData{ + Symbol: symbol, + Qty: notional / price, + EntryPrice: price, + Mark: price, + }, + }, nil +} + +func (position *Position) Data() PositionData { + position.mu.RLock() + defer position.mu.RUnlock() + + if position.data.Symbol == "" { + return PositionData{ + Symbol: position.Symbol, + Qty: position.Qty, + } + } + + return position.data +} + +func (position *Position) Update(ticker kraken.TickerData) { + if strings.TrimSpace(ticker.Symbol) != position.Data().Symbol { + return + } + + mark := ticker.Last + if mark <= 0 && ticker.Bid > 0 && ticker.Ask > 0 { + mark = (ticker.Bid + ticker.Ask) / 2 + } + + if mark <= 0 { + return + } + + position.mu.Lock() + defer position.mu.Unlock() + + position.data.Mark = mark + position.data.PnL = (mark - position.data.EntryPrice) * position.data.Qty + + if position.data.EntryPrice > 0 { + position.data.ReturnPct = mark/position.data.EntryPrice - 1 + } +} + +func (position *Position) Enter() error { + data := position.Data() + + return position.private.Submit(&kraken.Order{ + Method: "add_order", + Params: kraken.LimitOrderParams{ + OrderType: "market", + Side: "buy", + OrderQty: data.Qty, + Symbol: data.Symbol, + }, + ReqID: int(time.Now().UnixNano()), + }) +} + +func (position *Position) Exit() error { + data := position.Data() + + return position.private.Submit(&kraken.Order{ + Method: "add_order", + Params: kraken.LimitOrderParams{ + OrderType: "market", + Side: "sell", + OrderQty: data.Qty, + Symbol: data.Symbol, + }, + ReqID: int(time.Now().UnixNano()), + }) +} diff --git a/broker/stoploss.go b/broker/stoploss.go deleted file mode 100644 index e83c74a2..00000000 --- a/broker/stoploss.go +++ /dev/null @@ -1,43 +0,0 @@ -package broker - -import ( - "context" - - "github.com/theapemachine/datura" - "github.com/theapemachine/datura/dmt" - "github.com/theapemachine/qpool" -) - -type StopLoss struct { - ctx context.Context - cancel context.CancelFunc - err error - pool *qpool.Q[any] - tree *dmt.Tree -} - -func NewStopLoss( - ctx context.Context, pool *qpool.Q[any], tree *dmt.Tree, -) *StopLoss { - ctx, cancel := context.WithCancel(ctx) - - return &StopLoss{ - ctx: ctx, - cancel: cancel, - pool: pool, - tree: tree, - } -} - -func (sl *StopLoss) Update(artifact *datura.Artifact) error { - return nil -} - -func (sl *StopLoss) Close() error { - sl.cancel() - return nil -} - -func (sl *StopLoss) Error() error { - return sl.err -} diff --git a/cmd/cfg/config.yml b/cmd/cfg/config.yml index 43ed84a9..2dc85bce 100644 --- a/cmd/cfg/config.yml +++ b/cmd/cfg/config.yml @@ -7,27 +7,12 @@ system: audit: enabled: true file: runs/audit.jsonl + websocket: + channel: + buffer: 64 queue: ttl: 1024 buffer: 65536 - qpool: - scheduling_timeout: 1s - regulators: - circuit_breaker: - max_failures: 10 - reset_timeout: 10s - max_half_open: 10 - rate_limiter: - max_requests: 100 - interval: 1s - back_pressure: - max_queue_size: 1000 - interval: 1s - timeout: 1s - resource_governor: - max_cpu_percent: 90 - max_memory_percent: 90 - interval: 1s network: connection: max_delay: 89 @@ -41,26 +26,28 @@ story: measurements: buffer: 1024 +optimizer: + replay: + capture: true + file: runs/replay.jsonl + cognitive: persist_dir: "" beam_width: 4 beam_hops: 3 + tick_budget: 10ms rem_interval: 1h market: quote_currency: USD - anchor_symbol: BTC/USD - default_symbols: - - BTC/USD - max_scan_symbols: 1024 - book_depth_levels: 10 + book_depth_levels: 25 futures_enabled: false futures_ws_ping_interval: 30s - l3_enabled: false + l3_enabled: true l3_depth: 10 - # Fluid book resync still batches unsub/subscribe to avoid close 1008. - subscribe_pace: 50ms - subscribe_batch: 100 + # High-liquidity run: deeper L2 book and faster subscription pacing. + subscribe_pace: 20ms + subscribe_batch: 50 ws_reconnect_initial: 1s ws_reconnect_max: 2m ws_reconnect_multiplier: 2 @@ -68,11 +55,11 @@ market: story: measurement_max_age: 30s ui_interval: 1s - forward_return_min_samples: 30 + forward_return_min_samples: 0 forward_return_significance_z: 1.96 forward_return_slope_alpha: 0.05 book: - depth: 10 + depth: 25 checksum: levels: 10 @@ -81,9 +68,17 @@ ui: heartbeat_interval: 1s outbound_buffer: 512 +emulator: + addr: 127.0.0.1:8766 + trading: order_ack_timeout: 500ms - max_quote_age: 15s + max_quote_age: 3s + max_spread_bps: 5.0 + max_slippage_bps: 3.0 + edge_min_bps: 10 + edge: + forward_return_horizon: 5m model: paper margin_enabled: false replay: @@ -98,18 +93,33 @@ trading: choppy_size_scale: 0.5 bearish_size_scale: 0.35 max_concurrent_positions: 4 + slots: + normal: 4 + reserved: 0 + sizing: + base_fraction: 0.05 + stop: + trailing_offset_bps: 100 + min_offset_bps: 20 + max_offset_bps: 500 entry: - batch_window: 50ms + batch_window: 20ms + min_active_origins: 3 preemption_enabled: true - transit_ttl: 5s + transit_ttl: 3s opportunity_slot_count: 2 paper: deterministic: true wallet: # No, these are not a mistake, or practice amount, but the exact amount I found in my Kraken account. usd: 200 # As such, it will be the only amount I am willing to trade with. eur: 200 # It is also the reason why this system has to be somewhat more advanced than a simple trading bot. - slippage_bps: 5 + slippage_bps: 2.0 + taker_fee_bps: 40 + maker_fee_bps: 25 latency_profile: runs/network_latency.json + rate_limits: + enabled: true + tier: starter failure_injection: enabled: false seed: 1 @@ -130,6 +140,7 @@ live: clock_synchronized: false exchange_connectivity_confirmed: false paper_live_parity_passed: false + native_protective_stops_supported: false max_order_notional: 0 max_daily_loss: 0 @@ -137,7 +148,7 @@ regime: {} signals: raw_dump: true - feed_ring_capacity: 64 + feed_ring_capacity: 128 causal: publish_interval: 1s pumpdump: @@ -149,7 +160,9 @@ signals: depthflow: raw_dump: true hawkes: {} - fluid: {} + fluid: + idle_threshold: 5s + max_integration_steps: 50 leadlag: raw_dump: true publish_interval: 200ms @@ -163,6 +176,10 @@ signals: toxicity: {} resonance: batch: 128 - arch: [12, 24, 3] + arch: [12, 24, 12, 3] alpha: 0.01 attention_warmup: 10 + +logic: + resonance: + learn: false diff --git a/cmd/root.go b/cmd/root.go index 8d3572a6..2f2fe89b 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,8 +1,10 @@ package cmd import ( + "context" "embed" "fmt" + "net/http" "os" "path/filepath" "runtime" @@ -12,9 +14,7 @@ import ( "github.com/spf13/viper" "github.com/theapemachine/datura/dmt" "github.com/theapemachine/errnie" - "github.com/theapemachine/qpool" - "github.com/theapemachine/symm/kraken/paper" - "github.com/theapemachine/symm/kraken/public" + "github.com/theapemachine/symm/kraken/websocket" "github.com/theapemachine/symm/trader" "github.com/theapemachine/symm/ui" ) @@ -35,61 +35,84 @@ var ( Short: "S.Y.M.M. is not financial advice.", Long: rootLong, RunE: func(cmd *cobra.Command, args []string) error { + ctx, cancel := context.WithCancel(cmd.Context()) + errnie.Apply(&errnie.Config{ Level: viper.GetViper().GetString("system.log.level"), }) errnie.Info(fmt.Sprintf("symm started with %d CPUs", runtime.NumCPU())) - - pool := qpool.NewQ[any](cmd.Context(), 1, runtime.NumCPU(), &qpool.Config{ - SchedulingTimeout: viper.GetDuration("system.qpool.scheduling_timeout"), - Regulators: []qpool.Regulator{ - qpool.NewRegulator(qpool.NewCircuitBreaker( - viper.GetInt("system.qpool.regulators.circuit_breaker.max_failures"), - viper.GetDuration("system.qpool.regulators.circuit_breaker.reset_timeout"), - viper.GetInt("system.qpool.regulators.circuit_breaker.max_half_open"), - )), - qpool.NewRegulator(qpool.NewRateLimiter( - viper.GetInt("system.qpool.regulators.rate_limiter.max_requests"), - viper.GetDuration("system.qpool.regulators.rate_limiter.interval"), - )), - qpool.NewRegulator(qpool.NewBackPressureRegulator( - viper.GetInt("system.qpool.regulators.back_pressure.max_queue_size"), - viper.GetDuration("system.qpool.regulators.back_pressure.interval"), - viper.GetDuration("system.qpool.regulators.back_pressure.timeout"), - )), - qpool.NewRegulator(qpool.NewResourceGovernorRegulator( - viper.GetFloat64("system.qpool.regulators.resource_governor.max_cpu_percent"), - viper.GetFloat64("system.qpool.regulators.resource_governor.max_memory_percent"), - viper.GetDuration("system.qpool.regulators.resource_governor.interval"), - )), - }, - }) + startPprof() tree := dmt.NewTree(viper.GetString("cognitive.persist_dir")) - publicRest := public.NewRest(cmd.Context(), tree) - defer publicRest.Close() - - publicSocket := public.NewWebSocket(cmd.Context(), pool, tree) + publicSocket := websocket.NewPublic(ctx, nil) defer publicSocket.Close() + symbolUpdates := publicSocket.Symbols() + + tradingModel := viper.GetViper().GetString("trading.model") + privateStream := websocket.NewPrivate(ctx) + defer privateStream.Close() + + level3Sockets := []websocket.Socket{} + if tradingModel == "live" && viper.GetBool("market.l3_enabled") { + level3Socket := websocket.NewL3(ctx, nil) + defer level3Socket.Close() + level3Sockets = append(level3Sockets, level3Socket) + + go func() { + for { + select { + case <-ctx.Done(): + return + case symbols := <-symbolUpdates: + level3Socket.Subscribe(symbols) + } + } + }() + } - go publicSocket.Run(public.WebSocketURL) + uiHub, err := ui.NewHub(ctx) - paperSocket := paper.NewWebSocket(cmd.Context(), pool, tree) - defer paperSocket.Close() + if err != nil { + cancel() + return errnie.Error(errnie.Err( + errnie.IO, + "ui: failed to create hub", + err, + )) + } - go paperSocket.Run() + defer uiHub.Close() - cryptoTrader := trader.NewCrypto(cmd.Context(), pool, tree) - defer cryptoTrader.Close() + cryptoTrader, err := trader.NewCrypto( + ctx, + tree, + privateStream, + publicSocket, + uiHub, + level3Sockets..., + ) + + if err != nil { + cancel() + return errnie.Error(errnie.Err( + errnie.IO, + "trader: failed to create crypto", + err, + )) + } - uiHub := ui.NewHub(cmd.Context(), pool) - defer uiHub.Close() + defer cryptoTrader.Close() - go cryptoTrader.Run() + go func() { + if err := cryptoTrader.Run(); err != nil { + errnie.Error(err) + cancel() + } + }() - return errnie.Error(uiHub.Run()) + return uiHub.Serve() }, } ) @@ -102,6 +125,22 @@ func Execute() { } } +func startPprof() { + if !viper.GetBool("system.pprof.enabled") && os.Getenv("SYMM_PPROF") == "" { + return + } + + addr := viper.GetString("system.pprof.addr") + + if addr == "" { + addr = "127.0.0.1:6060" + } + + go func() { + errnie.Error(http.ListenAndServe(addr, nil)) + }() +} + func init() { cobra.OnInitialize(initConfig) diff --git a/frontend/README.md b/frontend/README.md index 0b3237dd..3eb11dcf 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -2,32 +2,21 @@ The dashboard connects to `ws://127.0.0.1:8765/ws` by default. Wallet snapshots drive the header cash balance; `equity` frames add the realistic all-cash balance after market-selling every open lot through the L2 book with taker fees (shown beside cash when positions are open). Wallet snapshots also hydrate `gauge_confidence` so gauges recover immediately after reconnect. The trades panel intentionally renders open positions only, with live `mark` events updating each card's P/L. The right rail splits trades and audit 50/50. The audit half receives realtime entry/exit action events only (`trade_*_fill`, `trade_*_error`); skips, high-volume measurement lines, and perspective lines remain in the JSONL sidecar but do not stream to the dashboard. Trade charts consume candle rows only; raw mark ticks do not become synthetic candles. -The **Signal Insight** page (`/diagnostics`) lists `runs/_raw.jsonl` dumps through `/api/dumps`, runs a full-file analysis on selection through `/api/analyze`, and then streams debounced tail analyses over the websocket as `chart: "diagnostic"` frames whenever a dump grows. Dump inventory refreshes on `event: "dumps"`. Refresh still forces a full-file re-read. +The **Signal Insight** page (`/signals`) renders typed backend signal frames directly from the websocket-backed stores. It is the current replacement for the old diagnostics chart surface. The prediction chart consumes `chart: "prediction"` frames with optional `horizon` (seconds). Dashed orange `prediction` is the cross-symbol mean forecast at `now + story.prediction.horizon`; green `actual` and red `error` are cross-symbol means at the same target timestamp when price catches up. The visible x-range keeps the latest forecast on the right edge and spans `2 × horizon` into the past so ground truth and error lines visibly catch up. -The top strip and side rails render thirteen signal gauges, each on its own SciChart surface (`create()` shares one WebGL context across all of them). The top-left **Confidence** tab scrolls per-source band clarity (what the gauges show, over time). The main **Surprise** tab scrolls per-source SNR — how far each signal's category standout sits above its own recent baseline. That pair separates "how clear is the reading right now" from "how unusual is this versus recent history." - ## Source layout ``` src/ components/ - dashboard/ # layout shell (DashboardLayout, PanelTabs, placeholders) - charts/ - shared/ # SciChart theme + financial chart helpers - confidence/ # gauges, heatmaps, confidence wire adapter - fluid/ # 3D surface chart + field_row wire adapter - prediction/ # forward forecast/actual/error wire adapter - trade/ # OHLC chart + trade-chart-wire adapter - panels/ - data/ # audit, decisions, wallet, trades panel stores - audit.tsx, trades.tsx # panel UI (consume lib/symm hooks) - lib/symm/ # wire protocol, layout schema, WS routing, stores + terminal/ # current terminal dashboard rows and lightweight charts + collections/ # websocket-backed TanStack stores + providers/ # websocket connection and frame routing + routes/ # dashboard, signals, decisions, xray, cortex, allocation ``` -Chart adapters under `components/charts/*/` route websocket frames and call the mounted chart's update function. Each adapter is a thin `ingest*Wire` entry point plus a type guard; charts own SciChart state and do not mirror history in parallel stores. Trade candles additionally rely on the backend emitting numeric `sec` from `interval_begin`. Open-position trade charts render a read-only SciChart `StopLossTakeProfitAnnotation` when the desk publishes `stop_price` on the positions frame; the zone tracks ratcheting stops from backend `positions` updates and extends across the loaded candle range as new bars arrive. - # Getting Started To run this application: @@ -63,26 +52,6 @@ npm run bench This project uses [Tailwind CSS](https://tailwindcss.com/) for styling. -### Removing Tailwind CSS - -If you prefer not to use Tailwind CSS: - -1. Remove the demo pages in `src/routes/demo/` -2. Replace the Tailwind import in `src/styles.css` with your own styles -3. Remove `tailwindcss()` from the plugins array in `vite.config.ts` -4. Uninstall the packages: `npm install @tailwindcss/vite tailwindcss -D` - - -## Shadcn - -Add components using the latest version of [Shadcn](https://ui.shadcn.com/). - -```bash -pnpm dlx shadcn@latest add button -``` - - - ## Routing This project uses [TanStack Router](https://tanstack.com/router) with file-based routing. Routes are managed as files in `src/routes`. diff --git a/frontend/biome.json b/frontend/biome.json index 253a68b5..823b3e64 100644 --- a/frontend/biome.json +++ b/frontend/biome.json @@ -13,8 +13,7 @@ "**/.vscode/**/*", "**/index.html", "vite.config.ts", - "!**/src/routeTree.gen.ts", - "**/src/styles.css" + "!src/routeTree.gen.ts" ] }, "formatter": { @@ -47,4 +46,4 @@ "indentStyle": "tab" } } -} \ No newline at end of file +} diff --git a/frontend/components.json b/frontend/components.json deleted file mode 100644 index 11f0447f..00000000 --- a/frontend/components.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "$schema": "https://ui.shadcn.com/schema.json", - "style": "base-nova", - "rsc": false, - "tsx": true, - "tailwind": { - "config": "tailwind.config.js", - "css": "src/styles.css", - "baseColor": "neutral", - "cssVariables": true, - "prefix": "" - }, - "aliases": { - "components": "@/components", - "utils": "@/lib/utils", - "ui": "@/components/ui", - "lib": "@/lib", - "hooks": "@/hooks" - }, - "iconLibrary": "lucide", - "rtl": false, - "menuColor": "default", - "menuAccent": "subtle", - "registries": { - "@coss": "https://coss.com/ui/r/{name}.json" - } -} diff --git a/frontend/package.json b/frontend/package.json index aa2dd0e8..33fa15ec 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -2,64 +2,42 @@ "name": "my-tanstack-app", "private": true, "type": "module", + "packageManager": "pnpm@10.28.1", "imports": { "#/*": "./src/*" }, "scripts": { - "dev": "pnpm sync:scichart-wasm && vite dev --port 3000", - "build": "pnpm sync:scichart-wasm && vite build", + "dev": "vite dev --port 3000", + "build": "vite build", "preview": "vite preview", "test": "vitest run", - "bench": "vitest bench --run", - "sync:scichart-wasm": "mkdir -p public/scichart && cp node_modules/scichart/_wasm/scichart2d.wasm node_modules/scichart/_wasm/scichart2d-nosimd.wasm node_modules/scichart/_wasm/scichart3d.wasm node_modules/scichart/_wasm/scichart3d-nosimd.wasm node_modules/scichart/_wasm/scichart2d.js node_modules/scichart/_wasm/scichart3d.js public/scichart/", - "postinstall": "pnpm sync:scichart-wasm" + "typecheck": "tsc -p tsconfig.typecheck.json --noEmit", + "lint": "git ls-files --cached --others --exclude-standard 'src/**/*.ts' 'src/**/*.tsx' 'vite.config.ts' | grep -Ev '(^src/routeTree\\.gen\\.ts$)' | while IFS= read -r file; do [ -e \"$file\" ] && printf '%s\\n' \"$file\"; done | xargs biome lint", + "bench": "vitest bench --run" }, "dependencies": { - "@base-ui/react": "^1.4.1", - "@faker-js/faker": "^10.3.0", - "@fontsource-variable/geist": "^5.2.8", - "@fontsource-variable/inter": "^5.2.8", "@tailwindcss/vite": "^4.1.18", - "@tanstack/match-sorter-utils": "latest", - "@tanstack/react-devtools": "latest", - "@tanstack/react-form": "latest", "@tanstack/react-router": "latest", - "@tanstack/react-router-devtools": "latest", "@tanstack/react-start": "latest", "@tanstack/react-store": "^0.11.0", - "@tanstack/react-table": "latest", "@tanstack/router-plugin": "^1.132.0", "@tanstack/store": "^0.11.0", - "capnp-ts": "link:../../capnp-ts/packages/capnp-ts", - "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", - "lucide-react": "^0.577.0", - "motion": "^12.40.0", - "radix-ui": "^1.4.3", "react": "^19.2.0", - "react-day-picker": "^10.0.1", "react-dom": "^19.2.0", - "react-use-websocket": "^4.13.0", - "scichart": "^5.2.28", - "scichart-financial-tools": "^5.2.28", - "scichart-react": "^1.0.0", - "shadcn": "^4.7.0", "tailwind-merge": "^3.0.2", "tailwindcss": "^4.1.18", - "tw-animate-css": "^1.3.6", - "zod": "^4.3.6" + "tw-animate-css": "^1.3.6" }, "devDependencies": { "@tailwindcss/typography": "^0.5.16", "@tanstack/devtools-vite": "latest", - "@testing-library/dom": "^10.4.1", - "@testing-library/react": "^16.3.0", "@types/node": "^22.10.2", "@types/react": "^19.2.0", "@types/react-dom": "^19.2.0", "@vitejs/plugin-react": "^6.0.1", + "@biomejs/biome": "2.4.5", "esbuild": "^0.28.1", - "jsdom": "^28.1.0", "typescript": "^6.0.2", "vite": "^8.0.0", "vitest": "^4.1.5" diff --git a/frontend/pnpm-lock.yaml b/frontend/pnpm-lock.yaml index c721fd53..bf23406b 100644 --- a/frontend/pnpm-lock.yaml +++ b/frontend/pnpm-lock.yaml @@ -8,93 +8,33 @@ importers: .: dependencies: - '@base-ui/react': - specifier: ^1.4.1 - version: 1.5.0(@date-fns/tz@1.5.0)(@types/react@19.2.15)(date-fns@4.4.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@faker-js/faker': - specifier: ^10.3.0 - version: 10.4.0 - '@fontsource-variable/geist': - specifier: ^5.2.8 - version: 5.2.9 - '@fontsource-variable/inter': - specifier: ^5.2.8 - version: 5.2.8 '@tailwindcss/vite': specifier: ^4.1.18 version: 4.3.0(vite@8.0.14(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0)) - '@tanstack/match-sorter-utils': - specifier: latest - version: 8.19.4 - '@tanstack/react-devtools': - specifier: latest - version: 0.10.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(csstype@3.2.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(solid-js@1.9.13) - '@tanstack/react-form': - specifier: latest - version: 1.32.0(@tanstack/react-start@1.168.9(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite@8.0.14(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0)))(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@tanstack/react-router': specifier: latest version: 1.170.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@tanstack/react-router-devtools': - specifier: latest - version: 1.167.0(@tanstack/react-router@1.170.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@tanstack/router-core@1.171.4)(csstype@3.2.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@tanstack/react-start': specifier: latest version: 1.168.9(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite@8.0.14(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0)) '@tanstack/react-store': specifier: ^0.11.0 version: 0.11.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@tanstack/react-table': - specifier: latest - version: 8.21.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@tanstack/router-plugin': specifier: ^1.132.0 version: 1.168.9(@tanstack/react-router@1.170.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(vite@8.0.14(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0)) '@tanstack/store': specifier: ^0.11.0 version: 0.11.0 - capnp-ts: - specifier: link:../../capnp-ts/packages/capnp-ts - version: link:../../capnp-ts/packages/capnp-ts - class-variance-authority: - specifier: ^0.7.1 - version: 0.7.1 clsx: specifier: ^2.1.1 version: 2.1.1 - lucide-react: - specifier: ^0.577.0 - version: 0.577.0(react@19.2.6) - motion: - specifier: ^12.40.0 - version: 12.40.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - radix-ui: - specifier: ^1.4.3 - version: 1.4.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react: specifier: ^19.2.0 version: 19.2.6 - react-day-picker: - specifier: ^10.0.1 - version: 10.0.1(@types/react@19.2.15)(react@19.2.6) react-dom: specifier: ^19.2.0 version: 19.2.6(react@19.2.6) - react-use-websocket: - specifier: ^4.13.0 - version: 4.13.0 - scichart: - specifier: ^5.2.28 - version: 5.2.28 - scichart-financial-tools: - specifier: ^5.2.28 - version: 5.2.28(scichart@5.2.28) - scichart-react: - specifier: ^1.0.0 - version: 1.0.0(react@19.2.6)(scichart@5.2.28) - shadcn: - specifier: ^4.7.0 - version: 4.10.0(@types/node@22.19.19)(typescript@6.0.3) tailwind-merge: specifier: ^3.0.2 version: 3.6.0 @@ -104,22 +44,16 @@ importers: tw-animate-css: specifier: ^1.3.6 version: 1.4.0 - zod: - specifier: ^4.3.6 - version: 4.4.3 devDependencies: + '@biomejs/biome': + specifier: 2.4.5 + version: 2.4.5 '@tailwindcss/typography': specifier: ^0.5.16 version: 0.5.19(tailwindcss@4.3.0) '@tanstack/devtools-vite': specifier: latest version: 0.7.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(vite@8.0.14(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0)) - '@testing-library/dom': - specifier: ^10.4.1 - version: 10.4.1 - '@testing-library/react': - specifier: ^16.3.0 - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@types/node': specifier: ^22.10.2 version: 22.19.19 @@ -135,9 +69,6 @@ importers: esbuild: specifier: ^0.28.1 version: 0.28.1 - jsdom: - specifier: ^28.1.0 - version: 28.1.0(@noble/hashes@1.8.0) typescript: specifier: ^6.0.2 version: 6.0.3 @@ -175,10 +106,6 @@ packages: resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} engines: {node: '>=6.9.0'} - '@babel/code-frame@7.29.7': - resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} - engines: {node: '>=6.9.0'} - '@babel/compat-data@7.29.3': resolution: {integrity: sha512-LIVqM46zQWZhj17qA8wb4nW/ixr2y1Nw+r1etiAWgRM6U1IqP+LNhL1yg440jYZR72jCWcWbLWzIosH+uP1fqg==} engines: {node: '>=6.9.0'} @@ -191,102 +118,40 @@ packages: resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} engines: {node: '>=6.9.0'} - '@babel/generator@7.29.7': - resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} - engines: {node: '>=6.9.0'} - - '@babel/helper-annotate-as-pure@7.29.7': - resolution: {integrity: sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==} - engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.28.6': resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.29.7': - resolution: {integrity: sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - '@babel/helper-globals@7.28.0': resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} - '@babel/helper-globals@7.29.7': - resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-member-expression-to-functions@7.29.7': - resolution: {integrity: sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==} - engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.28.6': resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.29.7': - resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} - engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.28.6': resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-module-transforms@7.29.7': - resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-optimise-call-expression@7.29.7': - resolution: {integrity: sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==} - engines: {node: '>=6.9.0'} - '@babel/helper-plugin-utils@7.28.6': resolution: {integrity: sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==} engines: {node: '>=6.9.0'} - '@babel/helper-plugin-utils@7.29.7': - resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-replace-supers@7.29.7': - resolution: {integrity: sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-skip-transparent-expression-wrappers@7.29.7': - resolution: {integrity: sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==} - engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.29.7': - resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} - engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.28.5': resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.29.7': - resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} - engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.29.7': - resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} - engines: {node: '>=6.9.0'} - '@babel/helpers@7.29.2': resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} engines: {node: '>=6.9.0'} @@ -296,107 +161,82 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/parser@7.29.7': - resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} - engines: {node: '>=6.0.0'} - hasBin: true - '@babel/plugin-syntax-jsx@7.28.6': resolution: {integrity: sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.29.7': - resolution: {integrity: sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-typescript@7.28.6': resolution: {integrity: sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-typescript@7.29.7': - resolution: {integrity: sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-modules-commonjs@7.29.7': - resolution: {integrity: sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-typescript@7.29.7': - resolution: {integrity: sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/preset-typescript@7.29.7': - resolution: {integrity: sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/runtime@7.29.2': - resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} - engines: {node: '>=6.9.0'} - '@babel/template@7.28.6': resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} engines: {node: '>=6.9.0'} - '@babel/template@7.29.7': - resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} - engines: {node: '>=6.9.0'} - '@babel/traverse@7.29.0': resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.29.7': - resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} - engines: {node: '>=6.9.0'} - '@babel/types@7.29.0': resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} - '@babel/types@7.29.7': - resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} - engines: {node: '>=6.9.0'} + '@biomejs/biome@2.4.5': + resolution: {integrity: sha512-OWNCyMS0Q011R6YifXNOg6qsOg64IVc7XX6SqGsrGszPbkVCoaO7Sr/lISFnXZ9hjQhDewwZ40789QmrG0GYgQ==} + engines: {node: '>=14.21.3'} + hasBin: true - '@base-ui/react@1.5.0': - resolution: {integrity: sha512-z1gSAlced1yY+iM+mHDEtIkD8UI3Ebs52MuBPxvV6f5hRutk+xvCH/wuB7hDqDzK9JG5FoMz5nhrqtSs1wjt1A==} - engines: {node: '>=14.0.0'} - peerDependencies: - '@date-fns/tz': ^1.2.0 - '@types/react': ^17 || ^18 || ^19 - date-fns: ^4.0.0 - react: ^17 || ^18 || ^19 - react-dom: ^17 || ^18 || ^19 - peerDependenciesMeta: - '@date-fns/tz': - optional: true - '@types/react': - optional: true - date-fns: - optional: true + '@biomejs/cli-darwin-arm64@2.4.5': + resolution: {integrity: sha512-lGS4Nd5O3KQJ6TeWv10mElnx1phERhBxqGP/IKq0SvZl78kcWDFMaTtVK+w3v3lusRFxJY78n07PbKplirsU5g==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [darwin] - '@base-ui/utils@0.2.9': - resolution: {integrity: sha512-x/PDDCYzoqPpjrdyb3VcyylTI2IjUXEtYDGi5foh7KsnmNJIIaVwA2GLgDH1dps1GgXiJbA60hM+AyuTfQzIvw==} - peerDependencies: - '@types/react': ^17 || ^18 || ^19 - react: ^17 || ^18 || ^19 - react-dom: ^17 || ^18 || ^19 - peerDependenciesMeta: - '@types/react': - optional: true + '@biomejs/cli-darwin-x64@2.4.5': + resolution: {integrity: sha512-6MoH4tyISIBNkZ2Q5T1R7dLd5BsITb2yhhhrU9jHZxnNSNMWl+s2Mxu7NBF8Y3a7JJcqq9nsk8i637z4gqkJxQ==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [darwin] + + '@biomejs/cli-linux-arm64-musl@2.4.5': + resolution: {integrity: sha512-iqLDgpzobG7gpBF0fwEVS/LT8kmN7+S0E2YKFDtqliJfzNLnAiV2Nnyb+ehCDCJgAZBASkYHR2o60VQWikpqIg==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-arm64@2.4.5': + resolution: {integrity: sha512-U1GAG6FTjhAO04MyH4xn23wRNBkT6H7NentHh+8UxD6ShXKBm5SY4RedKJzkUThANxb9rUKIPc7B8ew9Xo/cWg==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [linux] + + '@biomejs/cli-linux-x64-musl@2.4.5': + resolution: {integrity: sha512-NlKa7GpbQmNhZf9kakQeddqZyT7itN7jjWdakELeXyTU3pg/83fTysRRDPJD0akTfKDl6vZYNT9Zqn4MYZVBOA==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-linux-x64@2.4.5': + resolution: {integrity: sha512-NdODlSugMzTlENPTa4z0xB82dTUlCpsrOxc43///aNkTLblIYH4XpYflBbf5ySlQuP8AA4AZd1qXhV07IdrHdQ==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [linux] + + '@biomejs/cli-win32-arm64@2.4.5': + resolution: {integrity: sha512-EBfrTqRIWOFSd7CQb/0ttjHMR88zm3hGravnDwUA9wHAaCAYsULKDebWcN5RmrEo1KBtl/gDVJMrFjNR0pdGUw==} + engines: {node: '>=14.21.3'} + cpu: [arm64] + os: [win32] + + '@biomejs/cli-win32-x64@2.4.5': + resolution: {integrity: sha512-Pmhv9zT95YzECfjEHNl3mN9Vhusw9VA5KHY0ZvlGsxsjwS5cb7vpRnHzJIv0vG7jB0JI7xEaMH9ddfZm/RozBw==} + engines: {node: '>=14.21.3'} + cpu: [x64] + os: [win32] '@bramus/specificity@2.4.2': resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} @@ -438,19 +278,6 @@ packages: resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} engines: {node: '>=20.19.0'} - '@date-fns/tz@1.5.0': - resolution: {integrity: sha512-lwYN/vDPeNRULcepoE/LO2Pgx+7/RV+S9ARfbc9lr2DtGkOD7pAiruHvbR1RX3Qyf6ja47EWJDMsNK5vK08DJg==} - - '@dotenvx/dotenvx@1.71.0': - resolution: {integrity: sha512-KEUw/mGu+EDRhYWRTNGHIimVCs9NvMFaIXOGrHSXoCteKLE5EsJnmPjOPpYorjXVg/0xG0fbdVw720azw1z4ag==} - hasBin: true - - '@ecies/ciphers@0.2.6': - resolution: {integrity: sha512-patgsRPKGkhhoBjETV4XxD0En4ui5fbX0hzayqI3M8tvNMGUoUvmyYAIWwlxBc1KX5cturfqByYdj5bYGRpN9g==} - engines: {bun: '>=1', deno: '>=2.7.10', node: '>=16'} - peerDependencies: - '@noble/ciphers': ^1.0.0 - '@emnapi/core@1.10.0': resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} @@ -625,37 +452,6 @@ packages: '@noble/hashes': optional: true - '@faker-js/faker@10.4.0': - resolution: {integrity: sha512-sDBWI3yLy8EcDzgobvJTWq1MJYzAkQdpjXuPukga9wXonhpMRvd1Izuo2Qgwey2OiEoRIBr35RMU9HJRoOHzpw==} - engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0, npm: '>=10'} - - '@floating-ui/core@1.7.5': - resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} - - '@floating-ui/dom@1.7.6': - resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} - - '@floating-ui/react-dom@2.1.8': - resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@floating-ui/utils@0.2.11': - resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} - - '@fontsource-variable/geist@5.2.9': - resolution: {integrity: sha512-TP+QSBG3wxKGPE33CbMy/L0Nu3qvJ6Fy81Yc4LnQ95xH+i+cfEp8fyU8/kfV14YwszxIFPhnoMTbjL71waVpyQ==} - - '@fontsource-variable/inter@5.2.8': - resolution: {integrity: sha512-kOfP2D+ykbcX/P3IFnokOhVRNoTozo5/JxhAIVYLpea/UBmCQ/YWPBfWIDuBImXX/15KH+eKh4xpEUyS2sQQGQ==} - - '@hono/node-server@1.19.14': - resolution: {integrity: sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==} - engines: {node: '>=18.14.1'} - peerDependencies: - hono: ^4 - '@inquirer/ansi@2.0.7': resolution: {integrity: sha512-3eTuUO1vH2cZm2ZKHeQxnOqlTi9EfZDGgIe3BL3I4u+rJHocr9Fz86M4fjYABPvFnQG/gGK551HqDiIcETwU6Q==} engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} @@ -707,16 +503,6 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@modelcontextprotocol/sdk@1.29.0': - resolution: {integrity: sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==} - engines: {node: '>=18'} - peerDependencies: - '@cfworker/json-schema': ^4.1.1 - zod: ^3.25 || ^4.0 - peerDependenciesMeta: - '@cfworker/json-schema': - optional: true - '@mswjs/interceptors@0.41.9': resolution: {integrity: sha512-VVPPgHyQ6ShqnrmDWuxjmUIsO9gWyOZFmuOfLd9LfBGQJwZfy0gvv9pbHSJuoFNIYC7ZDX9aoFwowjcdSC4E8w==} engines: {node: '>=18'} @@ -727,30 +513,10 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 - '@noble/ciphers@1.3.0': - resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} - engines: {node: ^14.21.3 || >=16} - - '@noble/curves@1.9.7': - resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} - engines: {node: ^14.21.3 || >=16} - '@noble/hashes@1.8.0': resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - '@oozcitak/dom@2.0.2': resolution: {integrity: sha512-GjpKhkSYC3Mj4+lfwEyI1dqnsKTgwGy48ytZEhm4A/xnH/8z9M3ZVXKr/YGQi3uCLs1AEBS+x5T2JPiueEDW8w==} engines: {node: '>=20.0'} @@ -904,4569 +670,1771 @@ packages: '@oxc-project/types@0.132.0': resolution: {integrity: sha512-FESMOxil5Se014ui/Eq8fT5uHJo6nIRwH0PfJrZJXs6Gek3ZVFOrpUv3YIZT20m+extU98Hg1Ym72U58rlsxUQ==} - '@radix-ui/number@1.1.1': - resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} + '@rolldown/binding-android-arm64@1.0.2': + resolution: {integrity: sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] - '@radix-ui/primitive@1.1.3': - resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} + '@rolldown/binding-darwin-arm64@1.0.2': + resolution: {integrity: sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] - '@radix-ui/react-accessible-icon@1.1.7': - resolution: {integrity: sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@rolldown/binding-darwin-x64@1.0.2': + resolution: {integrity: sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] - '@radix-ui/react-accordion@1.2.12': - resolution: {integrity: sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@rolldown/binding-freebsd-x64@1.0.2': + resolution: {integrity: sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] - '@radix-ui/react-alert-dialog@1.1.15': - resolution: {integrity: sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@rolldown/binding-linux-arm-gnueabihf@1.0.2': + resolution: {integrity: sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] - '@radix-ui/react-arrow@1.1.7': - resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@rolldown/binding-linux-arm64-gnu@1.0.2': + resolution: {integrity: sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] - '@radix-ui/react-aspect-ratio@1.1.7': - resolution: {integrity: sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@rolldown/binding-linux-arm64-musl@1.0.2': + resolution: {integrity: sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] - '@radix-ui/react-avatar@1.1.10': - resolution: {integrity: sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@rolldown/binding-linux-ppc64-gnu@1.0.2': + resolution: {integrity: sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] - '@radix-ui/react-checkbox@1.3.3': - resolution: {integrity: sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@rolldown/binding-linux-s390x-gnu@1.0.2': + resolution: {integrity: sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] - '@radix-ui/react-collapsible@1.1.12': - resolution: {integrity: sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@rolldown/binding-linux-x64-gnu@1.0.2': + resolution: {integrity: sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] - '@radix-ui/react-collection@1.1.7': - resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@rolldown/binding-linux-x64-musl@1.0.2': + resolution: {integrity: sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] - '@radix-ui/react-compose-refs@1.1.2': - resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + '@rolldown/binding-openharmony-arm64@1.0.2': + resolution: {integrity: sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] - '@radix-ui/react-context-menu@2.2.16': - resolution: {integrity: sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@rolldown/binding-wasm32-wasi@1.0.2': + resolution: {integrity: sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] - '@radix-ui/react-context@1.1.2': - resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + '@rolldown/binding-win32-arm64-msvc@1.0.2': + resolution: {integrity: sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.2': + resolution: {integrity: sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@standard-schema/spec@1.1.0': + resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + + '@tailwindcss/node@4.3.0': + resolution: {integrity: sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==} + + '@tailwindcss/oxide-android-arm64@4.3.0': + resolution: {integrity: sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.0': + resolution: {integrity: sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.0': + resolution: {integrity: sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.0': + resolution: {integrity: sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': + resolution: {integrity: sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': + resolution: {integrity: sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.0': + resolution: {integrity: sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.0': + resolution: {integrity: sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.3.0': + resolution: {integrity: sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.3.0': + resolution: {integrity: sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': + resolution: {integrity: sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.0': + resolution: {integrity: sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.0': + resolution: {integrity: sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==} + engines: {node: '>= 20'} - '@radix-ui/react-dialog@1.1.15': - resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} + '@tailwindcss/typography@0.5.19': + resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==} peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' - '@radix-ui/react-direction@1.1.1': - resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} + '@tailwindcss/vite@4.3.0': + resolution: {integrity: sha512-t6J3OrB5Fc0ExuhohouH0fWUGMYL6PTLhW+E7zIk/pdbnJARZDCwjBznFnkh5ynRnIRSI4YjtTH0t6USjJISrw==} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + vite: ^5.2.0 || ^6 || ^7 || ^8 + + '@tanstack/devtools-client@0.0.6': + resolution: {integrity: sha512-f85ZJXJnDIFOoykG/BFIixuAevJovCvJF391LPs6YjBAPhGYC50NWlx1y4iF/UmK5/cCMx+/JqI5SBOz7FanQQ==} + engines: {node: '>=18'} + + '@tanstack/devtools-event-bus@0.4.1': + resolution: {integrity: sha512-cNnJ89Q021Zf883rlbBTfsaxTfi2r73/qejGtyTa7ksErF3hyDyAq1aTbo5crK9dAL7zSHh9viKY1BtMls1QOA==} + engines: {node: '>=18'} + + '@tanstack/devtools-event-client@0.4.3': + resolution: {integrity: sha512-OZI6QyULw0FI0wjgmeYzCIfbgPsOEzwJtCpa69XrfLMtNXLGnz3d/dIabk7frg0TmHo+Ah49w5I4KC7Tufwsvw==} + engines: {node: '>=18'} + hasBin: true - '@radix-ui/react-dismissable-layer@1.1.11': - resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} + '@tanstack/devtools-vite@0.7.0': + resolution: {integrity: sha512-VXki7K+Xwnpo3IKdNSWGe7YOvtZv33YlulGqaQ+YCpeQhYg8JFuxP50BXibDoRLj5EOX4r21Hs7COdxbRHXkTw==} + engines: {node: '>=18'} + hasBin: true peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + + '@tanstack/history@1.162.0': + resolution: {integrity: sha512-79pf/RkhteYZTRgcR4F9kbk84P2N8rugQJswxfIqovlbRiT3yI7eBE+5QorIrZaOKktsgzRlXh1l/du/xpl4iA==} + engines: {node: '>=20.19'} - '@radix-ui/react-dropdown-menu@2.1.16': - resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==} + '@tanstack/react-router@1.170.6': + resolution: {integrity: sha512-tGQkOjcMESBbfw+iz9zE/ivcuw4D2zdhW8PA4wMmpOyA2bLiqpc6bg5MnJPxamdXoO3GZBiHYOOoEwi5qxpPgA==} + engines: {node: '>=20.19'} peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' - '@radix-ui/react-focus-guards@1.1.3': - resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} + '@tanstack/react-start-client@1.168.1': + resolution: {integrity: sha512-jPqn2jcC+GgUcrEB9Jk1rtS2YToi8Ag336o7WisUSshpd6XggLAnSzNlbADrvmmjtgyIVZWOo1iHOs3wUWKAsw==} + engines: {node: '>=22.12.0'} peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' - '@radix-ui/react-focus-scope@1.1.7': - resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} + '@tanstack/react-start-rsc@0.1.9': + resolution: {integrity: sha512-Qf10ButiDQwTCRjGNvTR6M596P8/Yt6/vUmYgu2NhUptjwhv47iMgDfCaQfSsx5UzKpdCNydL+EABUYy+45QdQ==} + engines: {node: '>=22.12.0'} peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + '@rspack/core': '>=2.0.0-0' + '@vitejs/plugin-rsc': '>=0.5.20' + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + react-server-dom-rspack: '>=0.0.2' peerDependenciesMeta: - '@types/react': + '@rspack/core': optional: true - '@types/react-dom': + '@vitejs/plugin-rsc': + optional: true + react-server-dom-rspack: optional: true - '@radix-ui/react-form@0.1.8': - resolution: {integrity: sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ==} + '@tanstack/react-start-server@1.167.6': + resolution: {integrity: sha512-D0QxMj8YPcRcKcn9TLBBvQvenC7ViVzOmV7C9InyMW65052jAvLkBGDzsqh+RZTmMsSHI0AK+tuLUtViUddxag==} + engines: {node: '>=22.12.0'} peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' - '@radix-ui/react-hover-card@1.1.15': - resolution: {integrity: sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==} + '@tanstack/react-start@1.168.9': + resolution: {integrity: sha512-8sJqG4qADM3OndF2K+ExG55kPY1IIEm9sluthl7NqsrqopJpkkuwaBg9ztczdFfko6JkmBoerwEuVGDD08rcyQ==} + engines: {node: '>=22.12.0'} peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + '@rsbuild/core': ^2.0.0 + '@vitejs/plugin-rsc': '*' + react: '>=18.0.0 || >=19.0.0' + react-dom: '>=18.0.0 || >=19.0.0' + vite: '>=7.0.0' peerDependenciesMeta: - '@types/react': + '@rsbuild/core': optional: true - '@types/react-dom': + '@vitejs/plugin-rsc': optional: true - - '@radix-ui/react-id@1.1.1': - resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': + vite: optional: true - '@radix-ui/react-label@2.1.7': - resolution: {integrity: sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==} + '@tanstack/react-store@0.11.0': + resolution: {integrity: sha512-tX4YXh3PDkmpvGQWkWqKpzs/MSqbtuwY9dWdWhtV9Q50PmO+jOkUKIWIX4G85dwt7lxdHLXsiaEKPdKmC8F41w==} peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@radix-ui/react-menu@2.1.16': - resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==} + '@tanstack/react-store@0.9.3': + resolution: {integrity: sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg==} peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@tanstack/router-core@1.171.4': + resolution: {integrity: sha512-LU9YuVdgaP+h4MEXRvokyjIEelulylgsromHMfYwVfgo1PF9oJP3NHyy7qtjxGLJq6zoZMCfoa1frDJlPo7I8g==} + engines: {node: '>=20.19'} + + '@tanstack/router-generator@1.167.8': + resolution: {integrity: sha512-Z4GT+p0jVaamW5eIbCAODLySmDSGnESwsUG+vS83M/F/4/erQgJKvFGtbosUp0vxeMe+kx3zE3s6d/hOle73aA==} + engines: {node: '>=20.19'} - '@radix-ui/react-menubar@1.1.16': - resolution: {integrity: sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==} + '@tanstack/router-plugin@1.168.9': + resolution: {integrity: sha512-n5gM7FKkveUW9yVs9UC8kaHvSxU60mDFP3llVpu9hzEEWUo8KBl11NWiUPIKeeRN5Wk2f4k6pysN+iTHbezT9Q==} + engines: {node: '>=20.19'} peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + '@rsbuild/core': '>=1.0.2 || ^2.0.0' + '@tanstack/react-router': ^1.170.6 + vite: '>=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0' + vite-plugin-solid: ^2.11.10 || ^3.0.0-0 + webpack: '>=5.92.0' peerDependenciesMeta: - '@types/react': + '@rsbuild/core': optional: true - '@types/react-dom': + '@tanstack/react-router': optional: true - - '@radix-ui/react-navigation-menu@1.2.14': - resolution: {integrity: sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': + vite: optional: true - '@types/react-dom': + vite-plugin-solid: optional: true - - '@radix-ui/react-one-time-password-field@0.1.8': - resolution: {integrity: sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': + webpack: optional: true - '@radix-ui/react-password-toggle-field@0.1.3': - resolution: {integrity: sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@tanstack/router-utils@1.162.1': + resolution: {integrity: sha512-62layyTGmclHDQS/eidwKRfN1hhCKwViG7iEBcVmL0MXgcAB3OOucWCEcDDGd9Cu11H6b4QQ5oOo47MWIqwz0A==} + engines: {node: '>=20.19'} - '@radix-ui/react-popover@1.1.15': - resolution: {integrity: sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@tanstack/start-client-core@1.170.1': + resolution: {integrity: sha512-KvUDEtQX7rURFtOsfh2OhOQ8YC46b+d0+T6gXi9Wpe9IRm1QzWUY38LH0SWlto4Dcs2VnN689Y7VgvkdnFHrzQ==} + engines: {node: '>=22.12.0'} - '@radix-ui/react-popper@1.2.8': - resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@tanstack/start-fn-stubs@1.162.0': + resolution: {integrity: sha512-QWfUZ3Yo923tdQn38LyKMU8rcTw69zc+T4dAvgTWV4O56SqFRsGfS0lSWIMhJRwXIx/bvdi7nTUBDdZtTHtpTQ==} + engines: {node: '>=22.12.0'} - '@radix-ui/react-portal@1.1.9': - resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} + '@tanstack/start-plugin-core@1.171.2': + resolution: {integrity: sha512-WYH0+CDvl1VHXJlhS0Z+65zq99fyE9JL9NoNVGjWT42IYhnaNcaI7LH9psvL16MMVoez+6W3j3b//+aB9RIG0A==} + engines: {node: '>=22.12.0'} peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + '@rsbuild/core': ^2.0.0 + vite: '>=7.0.0' peerDependenciesMeta: - '@types/react': + '@rsbuild/core': optional: true - '@types/react-dom': + vite: optional: true - '@radix-ui/react-presence@1.1.5': - resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@tanstack/start-server-core@1.169.1': + resolution: {integrity: sha512-DYXzU8ZUcNhVi63gB1t7JSgV7HmypgRfv6mhQpc3HmgeBppa7SIjtocFQKgtfUnSMZ+FWWE7wUn05viEGpZaMQ==} + engines: {node: '>=22.12.0'} - '@radix-ui/react-primitive@2.1.3': - resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@tanstack/start-storage-context@1.167.6': + resolution: {integrity: sha512-+bfS+L/r7QUHtuxSV3QtpcU5kn1V0j2fKlOY/XH3zLZqpTocKZdV8Q97grmqY3OcNJkRFPZEXSYNQg0Fn4Ilaw==} + engines: {node: '>=22.12.0'} - '@radix-ui/react-progress@1.1.7': - resolution: {integrity: sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@tanstack/store@0.11.0': + resolution: {integrity: sha512-WlzzCt3xi0G6pCAJu1U+2jiECwabETDpQDi3hfkFZvJii9AuZqEKbOiVarX1/bWhTNjU486yQtJCCasi/0q+Cw==} - '@radix-ui/react-radio-group@1.3.8': - resolution: {integrity: sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@tanstack/store@0.9.3': + resolution: {integrity: sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==} - '@radix-ui/react-roving-focus@1.1.11': - resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@tanstack/virtual-file-routes@1.162.0': + resolution: {integrity: sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA==} + engines: {node: '>=20.19'} - '@radix-ui/react-scroll-area@1.2.10': - resolution: {integrity: sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} - '@radix-ui/react-select@2.2.6': - resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - '@radix-ui/react-separator@1.1.7': - resolution: {integrity: sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - '@radix-ui/react-slider@1.3.6': - resolution: {integrity: sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} - '@radix-ui/react-slot@1.2.3': - resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + '@types/node@22.19.19': + resolution: {integrity: sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==} - '@radix-ui/react-switch@1.2.6': - resolution: {integrity: sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==} + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@types/react': ^19.2.0 - '@radix-ui/react-tabs@1.1.13': - resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@types/react@19.2.15': + resolution: {integrity: sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==} - '@radix-ui/react-toast@1.2.15': - resolution: {integrity: sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@types/set-cookie-parser@2.4.10': + resolution: {integrity: sha512-GGmQVGpQWUe5qglJozEjZV/5dyxbOOZ0LHe/lqyWssB88Y4svNfst0uqBVscdDeIKl5Jy5+aPSvy7mI9tYRguw==} - '@radix-ui/react-toggle-group@1.1.11': - resolution: {integrity: sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@types/statuses@2.0.6': + resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} - '@radix-ui/react-toggle@1.1.10': - resolution: {integrity: sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==} + '@vitejs/plugin-react@6.0.2': + resolution: {integrity: sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==} + engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 + babel-plugin-react-compiler: ^1.0.0 + vite: ^8.0.0 peerDependenciesMeta: - '@types/react': + '@rolldown/plugin-babel': optional: true - '@types/react-dom': + babel-plugin-react-compiler: optional: true - '@radix-ui/react-toolbar@1.1.11': - resolution: {integrity: sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@vitest/expect@4.1.7': + resolution: {integrity: sha512-1R+tw0ortHEbZDGMymm+pN7/AFQ/RkFFdtd7EN+VBpynKmLbP8A3rpEXdshBJ7+8hQ9zBJh/i1s0yKNtxAnU7w==} - '@radix-ui/react-tooltip@1.2.8': - resolution: {integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==} + '@vitest/mocker@4.1.7': + resolution: {integrity: sha512-vY7nuamKgfvpA1Koa3oYIw/k7D6kZnpGyNMZW8loow2bsBYla1TFdqTaXncWdRn4pgwNs+90RhnXhJScDwQeJA==} peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: - '@types/react': + msw: optional: true - '@types/react-dom': + vite: optional: true - '@radix-ui/react-use-callback-ref@1.1.1': - resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + '@vitest/pretty-format@4.1.7': + resolution: {integrity: sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==} - '@radix-ui/react-use-controllable-state@1.2.2': - resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + '@vitest/runner@4.1.7': + resolution: {integrity: sha512-BapjmAQ2aI78WdMEfeUWivnfVzB+VPGwWRQcJE0OUq7qEeEcBsCSf+0T5iREBNE5nBb4wA5Ya0W6IA+sghdEFw==} - '@radix-ui/react-use-effect-event@0.0.2': - resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + '@vitest/snapshot@4.1.7': + resolution: {integrity: sha512-ZacLzja+TmJeZ1h14xW2FB/WpeimUD3haBXQPyJqxvo8jQTmfeA8zv58mtjN2C7EHXZDYVcVYdYmAxjkWVvKCw==} - '@radix-ui/react-use-escape-keydown@1.1.1': - resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + '@vitest/spy@4.1.7': + resolution: {integrity: sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q==} - '@radix-ui/react-use-is-hydrated@0.1.0': - resolution: {integrity: sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + '@vitest/utils@4.1.7': + resolution: {integrity: sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==} - '@radix-ui/react-use-layout-effect@1.1.1': - resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} - '@radix-ui/react-use-previous@1.1.1': - resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} - '@radix-ui/react-use-rect@1.1.1': - resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} - '@radix-ui/react-use-size@1.1.1': - resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + ansis@4.3.0: + resolution: {integrity: sha512-44mvgtPvohuU/70DdY5Oz2AIrLJ9k6/5x4KmoSvPwO+5Moijo0+N9D0fKbbYZQWP1hNm5CpOf+E01jhxG/r8xg==} + engines: {node: '>=14'} - '@radix-ui/react-visually-hidden@1.2.3': - resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - '@radix-ui/rect@1.1.1': - resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} - '@rolldown/binding-android-arm64@1.0.2': - resolution: {integrity: sha512-ZS4D1JPGn/MYQN/SYDWftIE/nVsM8j/AFOYEzAoOE2O3NktQOZru+/vYXGbR/qtdLdIfGCP0lcoJiYVzsEz+iQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] + babel-dead-code-elimination@1.0.12: + resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} - '@rolldown/binding-darwin-arm64@1.0.2': - resolution: {integrity: sha512-vdFA9+C/rekyGce7WqHs/xoT0ioZEWaOFyZLIV1mEeNFaFDUQrPIo8Vs2GvJ6eetb3rzDUtUBgzto3ExpXJB3w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] + baseline-browser-mapping@2.10.31: + resolution: {integrity: sha512-MujYO3eP72uvmSE0i4wltsodRfIpZATP3jvzRNRGGxgzId7aVocVJJV3nf01qnzzKFGxQVC9bpWxl5cjxTr/7Q==} + engines: {node: '>=6.0.0'} + hasBin: true - '@rolldown/binding-darwin-x64@1.0.2': - resolution: {integrity: sha512-BewSOwTHazv77DTYiAZXSqqKZ4KP/KonFisDMVU7PImxoWfB2aepnPhd2E4SWz3zDzYgDNbs6jBmTdgNnF02GA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] + bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} - '@rolldown/binding-freebsd-x64@1.0.2': - resolution: {integrity: sha512-m41o7M0YWtUdqk61Tb+jnKb2rN++iRdIASlExkUoKfIAH30DOHCB8fVLzSUpbWHHU8esmEioY62PxzexE8MBuA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] + boolbase@1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - '@rolldown/binding-linux-arm-gnueabihf@1.0.2': - resolution: {integrity: sha512-jcojB9H7W/jS29pMKWAK1N+fU99vXodHDTatS3b3y/XSOCiHo0kkA74pL3jJmkoQtYpOCxDvaKs1fo2Ij/1X5w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true - '@rolldown/binding-linux-arm64-gnu@1.0.2': - resolution: {integrity: sha512-1jn6qDU5iiOgFgygDzKUuKP0maTi0/f1+sBLgvij/76C77Nm3ts6ufz9Bjg5q5dduxiUIxtq86JIoBvo1xQ4Ig==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] + caniuse-lite@1.0.30001793: + resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==} - '@rolldown/binding-linux-arm64-musl@1.0.2': - resolution: {integrity: sha512-QVLO/czFMdoMFSqlX3bcswcJNm/23r+qoa/jgtmFc/qEp6/jXmIkDjF/XIo8dPfGaiwy1xfQn8o77L79GeXFgw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} + engines: {node: '>=18'} - '@rolldown/binding-linux-ppc64-gnu@1.0.2': - resolution: {integrity: sha512-hgO5Abm0w5UL6FEa2iFnZqo2KlK7TQ5QhV5x09hujBf7t5KzHQ1VmfPuTpqRy/rNlSxua3eWH374xxiVrP+lcA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - '@rolldown/binding-linux-s390x-gnu@1.0.2': - resolution: {integrity: sha512-fy8rXxuYEu602abC8MUNaPjYLIFzReOaEIEMKMUa0rFEUxNpVXhs15KSSQ4qlqSaM7B6rcj9rDZgADh/IGDzLQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] + cheerio-select@2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} - '@rolldown/binding-linux-x64-gnu@1.0.2': - resolution: {integrity: sha512-0+bOkiQ779+r1WpoHOWHqncvyySci0vKph+myNDYb+im6meJAzHQXay6oEgnkHuUGouM1LKTZwqKpBow6Kj7CQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] + cheerio@1.2.0: + resolution: {integrity: sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==} + engines: {node: '>=20.18.1'} - '@rolldown/binding-linux-x64-musl@1.0.2': - resolution: {integrity: sha512-mjSkrzZK5Qsl0a9d1JgILOiuZOSDTVdKENcSXBoqbzSrspLR/4/IRVDo5wd2GgZjNss/viBFJdeq+j7qH2nypw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} - '@rolldown/binding-openharmony-arm64@1.0.2': - resolution: {integrity: sha512-1v5vHasdfQAZoEHakBV72LIFAC9JjnymsiKxp+GEr/ma3+NJCPSaYK+qavInOovJkgwFrs7GccX2d6IgDA3Z5w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] + cli-width@4.1.0: + resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} + engines: {node: '>= 12'} - '@rolldown/binding-wasm32-wasi@1.0.2': - resolution: {integrity: sha512-mb1VobWn6NheziTk5/WEaR6AKVbrwT5sOi6C7zk3gy/pD1qtJfU1j4PgTo2NJnOtbL9Dl3Aeei8w9jJ7qC2jZQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [wasm32] + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} - '@rolldown/binding-win32-arm64-msvc@1.0.2': - resolution: {integrity: sha512-SqKonF56vA/L2yHwHYcEp2P34URpOZ7d1fS635cTkpDnUtEGdUbhI6NzsPdqeSWvAAeGDrxjWjNmibDIdFf9/A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} - '@rolldown/binding-win32-x64-msvc@1.0.2': - resolution: {integrity: sha512-v7qRI7gXLRINcOGXt+7YmAZ6iFuyZVMIoXAxhd8oP+DR9dLfL9GfNIx7PLMxmhZdvq8waUJBQiWN9EKNy+TRBQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} - '@rolldown/pluginutils@1.0.1': - resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - '@sec-ant/readable-stream@0.4.1': - resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==} + cookie-es@3.1.1: + resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==} - '@sindresorhus/merge-streams@4.0.0': - resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} - '@solid-primitives/event-listener@2.4.5': - resolution: {integrity: sha512-nwRV558mIabl4yVAhZKY8cb6G+O1F0M6Z75ttTu5hk+SxdOnKSGj+eetDIu7Oax1P138ZdUU01qnBPR8rnxaEA==} - peerDependencies: - solid-js: ^1.6.12 + css-select@5.2.2: + resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} - '@solid-primitives/keyboard@1.3.5': - resolution: {integrity: sha512-sav+l+PL+74z3yaftVs7qd8c2SXkqzuxPOVibUe5wYMt+U5Hxp3V3XCPgBPN2I6cANjvoFtz0NiU8uHVLdi9FQ==} - peerDependencies: - solid-js: ^1.6.12 + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - '@solid-primitives/resize-observer@2.1.5': - resolution: {integrity: sha512-AiyTknKcNBaKHbcSMuxtSNM8FjIuiSuFyFghdD0TcCMU9hKi9EmsC5pjfjDwxE+5EueB1a+T/34PLRI5vbBbKw==} - peerDependencies: - solid-js: ^1.6.12 + css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} + engines: {node: '>= 6'} - '@solid-primitives/rootless@1.5.3': - resolution: {integrity: sha512-N8cIDAHbWcLahNRLr0knAAQvXyEdEMoAZvIMZKmhNb1mlx9e2UOv9BRD5YNwQUJwbNoYVhhLwFOEOcVXFx0HqA==} - peerDependencies: - solid-js: ^1.6.12 + cssesc@3.0.0: + resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} + engines: {node: '>=4'} + hasBin: true - '@solid-primitives/static-store@0.1.3': - resolution: {integrity: sha512-uxez7SXnr5GiRnzqO2IEDjOJRIXaG+0LZLBizmUA1FwSi+hrpuMzVBwyk70m4prcl8X6FDDXUl9O8hSq8wHbBQ==} - peerDependencies: - solid-js: ^1.6.12 + cssstyle@6.2.0: + resolution: {integrity: sha512-Fm5NvhYathRnXNVndkUsCCuR63DCLVVwGOOwQw782coXFi5HhkXdu289l59HlXZBawsyNccXfWRYvLzcDCdDig==} + engines: {node: '>=20'} - '@solid-primitives/utils@6.4.0': - resolution: {integrity: sha512-AeGTBg8Wtkh/0s+evyLtP8piQoS4wyqqQaAFs2HJcFMMjYAtUgo+ZPduRXLjPlqKVc2ejeR544oeqpbn8Egn8A==} - peerDependencies: - solid-js: ^1.6.12 + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - '@standard-schema/spec@1.1.0': - resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + data-urls@7.0.0: + resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - '@tailwindcss/node@4.3.0': - resolution: {integrity: sha512-aFb4gUhFOgdh9AXo4IzBEOzBkkAxm9VigwDJnMIYv3lcfXCJVesNfbEaBl4BNgVRyid92AmdviqwBUBRKSeY3g==} + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true - '@tailwindcss/oxide-android-arm64@4.3.0': - resolution: {integrity: sha512-TJPiq67tKlLuObP6RkwvVGDoxCMBVtDgKkLfa/uyj7/FyxvQwHS+UOnVrXXgbEsfUaMgiVvC4KbJnRr26ho4Ng==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [android] + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - '@tailwindcss/oxide-darwin-arm64@4.3.0': - resolution: {integrity: sha512-oMN/WZRb+SO37BmUElEgeEWuU8E/HXRkiODxJxLe1UTHVXLrdVSgfaJV7pSlhRGMSOiXLuxTIjfsF3wYvz8cgQ==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [darwin] + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} - '@tailwindcss/oxide-darwin-x64@4.3.0': - resolution: {integrity: sha512-N6CUmu4a6bKVADfw77p+iw6Yd9Q3OBhe0veaDX+QazfuVYlQsHfDgxBrsjQ/IW+zywL8mTrNd0SdJT/zgtvMdA==} - engines: {node: '>= 20'} - cpu: [x64] - os: [darwin] + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} + engines: {node: '>=0.3.1'} - '@tailwindcss/oxide-freebsd-x64@4.3.0': - resolution: {integrity: sha512-zDL5hBkQdH5C6MpqbK3gQAgP80tsMwSI26vjOzjJtNCMUo0lFgOItzHKBIupOZNQxt3ouPH7RPhvNhiTfCe5CQ==} - engines: {node: '>= 20'} - cpu: [x64] - os: [freebsd] + dom-serializer@2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} - '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.0': - resolution: {integrity: sha512-R06HdNi7A7OEoMsf6d4tjZ71RCWnZQPHj2mnotSFURjNLdBC+cIgXQ7l81CqeoiQftjf6OOblxXMInMgN2VzMA==} - engines: {node: '>= 20'} - cpu: [arm] - os: [linux] + domelementtype@2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} - '@tailwindcss/oxide-linux-arm64-gnu@4.3.0': - resolution: {integrity: sha512-qTJHELX8jetjhRQHCLilkVLmybpzNQAtaI/gaoVoidn/ufbNDbAo8KlK2J+yPoc8wQxvDxCmh/5lr8nC1+lTbg==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [linux] + domhandler@5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} - '@tailwindcss/oxide-linux-arm64-musl@4.3.0': - resolution: {integrity: sha512-Z6sukiQsngnWO+l39X4pPbiWT81IC+PLKF+PHxIlyZbGNb9MODfYlXEVlFvej5BOZInWX01kVyzeLvHsXhfczQ==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [linux] + domutils@3.2.2: + resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} - '@tailwindcss/oxide-linux-x64-gnu@4.3.0': - resolution: {integrity: sha512-DRNdQRpSGzRGfARVuVkxvM8Q12nh19l4BF/G7zGA1oe+9wcC6saFBHTISrpIcKzhiXtSrlSrluCfvMuledoCTQ==} - engines: {node: '>= 20'} - cpu: [x64] - os: [linux] + electron-to-chromium@1.5.360: + resolution: {integrity: sha512-GkcBt6YYAw9SxFWn+xVar4cLVGlXVuswwtRLBozi2zp0GjXs4ZnOrqV4zbXzg35n7w81hCkyJNYicgXlVHAmBA==} - '@tailwindcss/oxide-linux-x64-musl@4.3.0': - resolution: {integrity: sha512-Z0IADbDo8bh6I7h2IQMx601AdXBLfFpEdUotft86evd/8ZPflZe9COPO8Q1vw+pfLWIUo9zN/JGZvwuAJqduqg==} - engines: {node: '>= 20'} - cpu: [x64] - os: [linux] + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - '@tailwindcss/oxide-wasm32-wasi@4.3.0': - resolution: {integrity: sha512-HNZGOUxEmElksYR7S6sC5jTeNGpobAsy9u7Gu0AskJ8/20FR9GqebUyB+HBcU/ax6BHuiuJi+Oda4B+YX6H1yA==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - bundledDependencies: - - '@napi-rs/wasm-runtime' - - '@emnapi/core' - - '@emnapi/runtime' - - '@tybys/wasm-util' - - '@emnapi/wasi-threads' - - tslib + encoding-sniffer@0.2.1: + resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} - '@tailwindcss/oxide-win32-arm64-msvc@4.3.0': - resolution: {integrity: sha512-Pe+RPVTi1T+qymuuRpcdvwSVZjnll/f7n8gBxMMh3xLTctMDKqpdfGimbMyioqtLhUYZxdJ9wGNhV7MKHvgZsQ==} - engines: {node: '>= 20'} - cpu: [arm64] - os: [win32] + enhanced-resolve@5.21.6: + resolution: {integrity: sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==} + engines: {node: '>=10.13.0'} - '@tailwindcss/oxide-win32-x64-msvc@4.3.0': - resolution: {integrity: sha512-Mvrf2kXW/yeW/OTezZlCGOirXRcUuLIBx/5Y12BaPM7wJoryG6dfS/NJL8aBPqtTEx/Vm4T4vKzFUcKDT+TKUA==} - engines: {node: '>= 20'} - cpu: [x64] - os: [win32] + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} - '@tailwindcss/oxide@4.3.0': - resolution: {integrity: sha512-F7HZGBeN9I0/AuuJS5PwcD8xayx5ri5GhjYUDBEVYUkexyA/giwbDNjRVrxSezE3T250OU2K/wp/ltWx3UOefg==} - engines: {node: '>= 20'} - - '@tailwindcss/typography@0.5.19': - resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==} - peerDependencies: - tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} - '@tailwindcss/vite@4.3.0': - resolution: {integrity: sha512-t6J3OrB5Fc0ExuhohouH0fWUGMYL6PTLhW+E7zIk/pdbnJARZDCwjBznFnkh5ynRnIRSI4YjtTH0t6USjJISrw==} - peerDependencies: - vite: ^5.2.0 || ^6 || ^7 || ^8 + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} + engines: {node: '>=0.12'} - '@tanstack/devtools-client@0.0.6': - resolution: {integrity: sha512-f85ZJXJnDIFOoykG/BFIixuAevJovCvJF391LPs6YjBAPhGYC50NWlx1y4iF/UmK5/cCMx+/JqI5SBOz7FanQQ==} - engines: {node: '>=18'} + entities@8.0.0: + resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} + engines: {node: '>=20.19.0'} - '@tanstack/devtools-event-bus@0.4.1': - resolution: {integrity: sha512-cNnJ89Q021Zf883rlbBTfsaxTfi2r73/qejGtyTa7ksErF3hyDyAq1aTbo5crK9dAL7zSHh9viKY1BtMls1QOA==} - engines: {node: '>=18'} + es-module-lexer@2.1.0: + resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} - '@tanstack/devtools-event-client@0.4.3': - resolution: {integrity: sha512-OZI6QyULw0FI0wjgmeYzCIfbgPsOEzwJtCpa69XrfLMtNXLGnz3d/dIabk7frg0TmHo+Ah49w5I4KC7Tufwsvw==} + esbuild@0.28.1: + resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} engines: {node: '>=18'} hasBin: true - '@tanstack/devtools-ui@0.5.2': - resolution: {integrity: sha512-GtaMk8kaGZ9ZdR8Pu5RAfcse/ZrxzH/xsAIFtHMapLs2VMqSPFfb1NvIDO1MAAfUcub8Ix8XKQEP0uYSPzoFKw==} - engines: {node: '>=18'} - peerDependencies: - solid-js: '>=1.9.7' - - '@tanstack/devtools-vite@0.7.0': - resolution: {integrity: sha512-VXki7K+Xwnpo3IKdNSWGe7YOvtZv33YlulGqaQ+YCpeQhYg8JFuxP50BXibDoRLj5EOX4r21Hs7COdxbRHXkTw==} - engines: {node: '>=18'} - hasBin: true - peerDependencies: - vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} - '@tanstack/devtools@0.12.2': - resolution: {integrity: sha512-Xdl8pLzoDUvXaclQ0poY36WAPx0jEHk8vqUFd8FYFUm1BMshtB7RnTgD1HE9jCAXODxqw9I0gXBiUZLK3o3+Bw==} - engines: {node: '>=18'} - hasBin: true - peerDependencies: - solid-js: '>=1.9.7' + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - '@tanstack/form-core@1.32.0': - resolution: {integrity: sha512-Tn5VRDSjyqjmaet2tJMuEWDRFyrCaon03vxXPlSSaiSs6C/N7lCIwGCXJbZXEUq1kTj8jYN9qyXHbsz4LQHcow==} + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} - '@tanstack/history@1.162.0': - resolution: {integrity: sha512-79pf/RkhteYZTRgcR4F9kbk84P2N8rugQJswxfIqovlbRiT3yI7eBE+5QorIrZaOKktsgzRlXh1l/du/xpl4iA==} - engines: {node: '>=20.19'} + exsolve@1.0.8: + resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} - '@tanstack/match-sorter-utils@8.19.4': - resolution: {integrity: sha512-Wo1iKt2b9OT7d+YGhvEPD3DXvPv2etTusIMhMUoG7fbhmxcXCtIjJDEygy91Y2JFlwGyjqiBPRozme7UD8hoqg==} - engines: {node: '>=12'} + fast-string-truncated-width@3.0.3: + resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} - '@tanstack/pacer-lite@0.1.1': - resolution: {integrity: sha512-y/xtNPNt/YeyoVxE/JCx+T7yjEzpezmbb+toK8DDD1P4m7Kzs5YR956+7OKexG3f8aXgC3rLZl7b1V+yNUSy5w==} - engines: {node: '>=18'} + fast-string-width@3.0.2: + resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} - '@tanstack/react-devtools@0.10.5': - resolution: {integrity: sha512-orVsRJ7oAXFb7oyafQCgx9YuK44jpILh5T/ddYuxAsolNfN5DZBr5/NLrWErD7HCGIzvYzg1TZI4sPxmiKvtvA==} - engines: {node: '>=18'} - peerDependencies: - '@types/react': '>=16.8' - '@types/react-dom': '>=16.8' - react: '>=16.8' - react-dom: '>=16.8' + fast-wrap-ansi@0.2.2: + resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} - '@tanstack/react-form@1.32.0': - resolution: {integrity: sha512-6WP5SQTA6/H9crCpvpq3ZppYWqtrdE5NjOy6ebABi6uAQPqhfTzrdjS9t40mCZCFtGI5585OhJV6zBP/KN2zcw==} + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} peerDependencies: - '@tanstack/react-start': '*' - react: ^17.0.0 || ^18.0.0 || ^19.0.0 + picomatch: ^3 || ^4 peerDependenciesMeta: - '@tanstack/react-start': + picomatch: optional: true - '@tanstack/react-router-devtools@1.167.0': - resolution: {integrity: sha512-nGw095EG7IHx0h5NtlEmzf6vcCTaFNPWdTSuDKazajhN0ct/v/TkekJ9J6KYUCeV1a8/2ZmToc58M+0rrOyn7w==} - engines: {node: '>=20.19'} - peerDependencies: - '@tanstack/react-router': ^1.170.0 - '@tanstack/router-core': ^1.170.0 - react: '>=18.0.0 || >=19.0.0' - react-dom: '>=18.0.0 || >=19.0.0' - peerDependenciesMeta: - '@tanstack/router-core': - optional: true + fetchdts@0.1.7: + resolution: {integrity: sha512-YoZjBdafyLIop9lSxXVI33oLD5kN31q4Td+CasofLLYeLXRFeOsuOw0Uo+XNRi9PZlbfdlN2GmRtm4tCEQ9/KA==} - '@tanstack/react-router@1.170.6': - resolution: {integrity: sha512-tGQkOjcMESBbfw+iz9zE/ivcuw4D2zdhW8PA4wMmpOyA2bLiqpc6bg5MnJPxamdXoO3GZBiHYOOoEwi5qxpPgA==} - engines: {node: '>=20.19'} - peerDependencies: - react: '>=18.0.0 || >=19.0.0' - react-dom: '>=18.0.0 || >=19.0.0' + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] - '@tanstack/react-start-client@1.168.1': - resolution: {integrity: sha512-jPqn2jcC+GgUcrEB9Jk1rtS2YToi8Ag336o7WisUSshpd6XggLAnSzNlbADrvmmjtgyIVZWOo1iHOs3wUWKAsw==} - engines: {node: '>=22.12.0'} - peerDependencies: - react: '>=18.0.0 || >=19.0.0' - react-dom: '>=18.0.0 || >=19.0.0' + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} - '@tanstack/react-start-rsc@0.1.9': - resolution: {integrity: sha512-Qf10ButiDQwTCRjGNvTR6M596P8/Yt6/vUmYgu2NhUptjwhv47iMgDfCaQfSsx5UzKpdCNydL+EABUYy+45QdQ==} - engines: {node: '>=22.12.0'} - peerDependencies: - '@rspack/core': '>=2.0.0-0' - '@vitejs/plugin-rsc': '>=0.5.20' - react: '>=18.0.0 || >=19.0.0' - react-dom: '>=18.0.0 || >=19.0.0' - react-server-dom-rspack: '>=0.0.2' - peerDependenciesMeta: - '@rspack/core': - optional: true - '@vitejs/plugin-rsc': - optional: true - react-server-dom-rspack: - optional: true + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} - '@tanstack/react-start-server@1.167.6': - resolution: {integrity: sha512-D0QxMj8YPcRcKcn9TLBBvQvenC7ViVzOmV7C9InyMW65052jAvLkBGDzsqh+RZTmMsSHI0AK+tuLUtViUddxag==} - engines: {node: '>=22.12.0'} - peerDependencies: - react: '>=18.0.0 || >=19.0.0' - react-dom: '>=18.0.0 || >=19.0.0' + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - '@tanstack/react-start@1.168.9': - resolution: {integrity: sha512-8sJqG4qADM3OndF2K+ExG55kPY1IIEm9sluthl7NqsrqopJpkkuwaBg9ztczdFfko6JkmBoerwEuVGDD08rcyQ==} - engines: {node: '>=22.12.0'} + graphql@16.14.1: + resolution: {integrity: sha512-cQOsSMS/IrDz82PVyRDvf/Q1F/bRbBVjJlh+xYOkI1qw2bWRvWGiWc+m2O0d6l4Bt1fyY+8kzJ8JFWGJqNeDBg==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + + h3@2.0.1-rc.20: + resolution: {integrity: sha512-28ljodXuUp0fZovdiSRq4G9OgrxCztrJe5VdYzXAB7ueRvI7pIUqLU14Xi3XqdYJ/khXjfpUOOD2EQa6CmBgsg==} + engines: {node: '>=20.11.1'} + hasBin: true peerDependencies: - '@rsbuild/core': ^2.0.0 - '@vitejs/plugin-rsc': '*' - react: '>=18.0.0 || >=19.0.0' - react-dom: '>=18.0.0 || >=19.0.0' - vite: '>=7.0.0' + crossws: ^0.4.1 peerDependenciesMeta: - '@rsbuild/core': - optional: true - '@vitejs/plugin-rsc': - optional: true - vite: + crossws: optional: true - '@tanstack/react-store@0.11.0': - resolution: {integrity: sha512-tX4YXh3PDkmpvGQWkWqKpzs/MSqbtuwY9dWdWhtV9Q50PmO+jOkUKIWIX4G85dwt7lxdHLXsiaEKPdKmC8F41w==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + headers-polyfill@5.0.1: + resolution: {integrity: sha512-1TJ6Fih/b8h5TIcv+1+Hw0PDQWJTKDKzFZzcKOiW1wJza3XoAQlkCuXLbymPYB8+ZQyw8mHvdw560e8zVFIWyA==} - '@tanstack/react-store@0.9.3': - resolution: {integrity: sha512-y2iHd/N9OkoQbFJLUX1T9vbc2O9tjH0pQRgTcx1/Nz4IlwLvkgpuglXUx+mXt0g5ZDFrEeDnONPqkbfxXJKwRg==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + html-encoding-sniffer@6.0.0: + resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - '@tanstack/react-table@8.21.3': - resolution: {integrity: sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==} - engines: {node: '>=12'} - peerDependencies: - react: '>=16.8' - react-dom: '>=16.8' + htmlparser2@10.1.0: + resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} - '@tanstack/router-core@1.171.4': - resolution: {integrity: sha512-LU9YuVdgaP+h4MEXRvokyjIEelulylgsromHMfYwVfgo1PF9oJP3NHyy7qtjxGLJq6zoZMCfoa1frDJlPo7I8g==} - engines: {node: '>=20.19'} + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} - '@tanstack/router-devtools-core@1.168.0': - resolution: {integrity: sha512-wQoQhlBK7nlZgqzaqdYXKWNTpdHdsaREdaPhFZVH0/Ador+F+eM3/NF2i3f2LPeS0GgKraZUQXe1Q/1+KHyEYg==} - engines: {node: '>=20.19'} - peerDependencies: - '@tanstack/router-core': ^1.170.0 - csstype: ^3.0.10 - peerDependenciesMeta: - csstype: - optional: true + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} - '@tanstack/router-generator@1.167.8': - resolution: {integrity: sha512-Z4GT+p0jVaamW5eIbCAODLySmDSGnESwsUG+vS83M/F/4/erQgJKvFGtbosUp0vxeMe+kx3zE3s6d/hOle73aA==} - engines: {node: '>=20.19'} + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} - '@tanstack/router-plugin@1.168.9': - resolution: {integrity: sha512-n5gM7FKkveUW9yVs9UC8kaHvSxU60mDFP3llVpu9hzEEWUo8KBl11NWiUPIKeeRN5Wk2f4k6pysN+iTHbezT9Q==} - engines: {node: '>=20.19'} - peerDependencies: - '@rsbuild/core': '>=1.0.2 || ^2.0.0' - '@tanstack/react-router': ^1.170.6 - vite: '>=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0' - vite-plugin-solid: ^2.11.10 || ^3.0.0-0 - webpack: '>=5.92.0' - peerDependenciesMeta: - '@rsbuild/core': - optional: true - '@tanstack/react-router': - optional: true - vite: - optional: true - vite-plugin-solid: - optional: true - webpack: - optional: true + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} - '@tanstack/router-utils@1.162.1': - resolution: {integrity: sha512-62layyTGmclHDQS/eidwKRfN1hhCKwViG7iEBcVmL0MXgcAB3OOucWCEcDDGd9Cu11H6b4QQ5oOo47MWIqwz0A==} - engines: {node: '>=20.19'} + is-node-process@1.2.0: + resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} - '@tanstack/start-client-core@1.170.1': - resolution: {integrity: sha512-KvUDEtQX7rURFtOsfh2OhOQ8YC46b+d0+T6gXi9Wpe9IRm1QzWUY38LH0SWlto4Dcs2VnN689Y7VgvkdnFHrzQ==} - engines: {node: '>=22.12.0'} + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - '@tanstack/start-fn-stubs@1.162.0': - resolution: {integrity: sha512-QWfUZ3Yo923tdQn38LyKMU8rcTw69zc+T4dAvgTWV4O56SqFRsGfS0lSWIMhJRwXIx/bvdi7nTUBDdZtTHtpTQ==} - engines: {node: '>=22.12.0'} + isbot@5.1.40: + resolution: {integrity: sha512-yNeeynhhtIVRBk12tBV4eHNxwB42HzR4Q3Ea7vCOiJhImGaAIdIMrbJtacQlBizGLjUPw+akkFI5Dn9T70XoVQ==} + engines: {node: '>=18'} - '@tanstack/start-plugin-core@1.171.2': - resolution: {integrity: sha512-WYH0+CDvl1VHXJlhS0Z+65zq99fyE9JL9NoNVGjWT42IYhnaNcaI7LH9psvL16MMVoez+6W3j3b//+aB9RIG0A==} - engines: {node: '>=22.12.0'} + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + hasBin: true + + jsdom@28.1.0: + resolution: {integrity: sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - '@rsbuild/core': ^2.0.0 - vite: '>=7.0.0' + canvas: ^3.0.0 peerDependenciesMeta: - '@rsbuild/core': - optional: true - vite: + canvas: optional: true - '@tanstack/start-server-core@1.169.1': - resolution: {integrity: sha512-DYXzU8ZUcNhVi63gB1t7JSgV7HmypgRfv6mhQpc3HmgeBppa7SIjtocFQKgtfUnSMZ+FWWE7wUn05viEGpZaMQ==} - engines: {node: '>=22.12.0'} - - '@tanstack/start-storage-context@1.167.6': - resolution: {integrity: sha512-+bfS+L/r7QUHtuxSV3QtpcU5kn1V0j2fKlOY/XH3zLZqpTocKZdV8Q97grmqY3OcNJkRFPZEXSYNQg0Fn4Ilaw==} - engines: {node: '>=22.12.0'} + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true - '@tanstack/store@0.11.0': - resolution: {integrity: sha512-WlzzCt3xi0G6pCAJu1U+2jiECwabETDpQDi3hfkFZvJii9AuZqEKbOiVarX1/bWhTNjU486yQtJCCasi/0q+Cw==} + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true - '@tanstack/store@0.9.3': - resolution: {integrity: sha512-8reSzl/qGWGGVKhBoxXPMWzATSbZLZFWhwBAFO9NAyp0TxzfBP0mIrGb8CP8KrQTmvzXlR/vFPPUrHTLBGyFyw==} + launch-editor@2.13.2: + resolution: {integrity: sha512-4VVDnbOpLXy/s8rdRCSXb+zfMeFR0WlJWpET1iA9CQdlZDfwyLjUuGQzXU4VeOoey6AicSAluWan7Etga6Kcmg==} - '@tanstack/table-core@8.21.3': - resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} - engines: {node: '>=12'} + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] - '@tanstack/virtual-file-routes@1.162.0': - resolution: {integrity: sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA==} - engines: {node: '>=20.19'} + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] - '@testing-library/dom@10.4.1': - resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} - engines: {node: '>=18'} + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] - '@testing-library/react@16.3.2': - resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==} - engines: {node: '>=18'} - peerDependencies: - '@testing-library/dom': ^10.0.0 - '@types/react': ^18.0.0 || ^19.0.0 - '@types/react-dom': ^18.0.0 || ^19.0.0 - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] - '@ts-morph/common@0.27.0': - resolution: {integrity: sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==} + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] - '@tybys/wasm-util@0.10.2': - resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] - '@types/aria-query@5.0.4': - resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] - '@types/chai@5.2.3': - resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] - '@types/deep-eql@4.0.2': - resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] - '@types/estree@1.0.9': - resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] - '@types/node@22.19.19': - resolution: {integrity: sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==} + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} - '@types/react-dom@19.2.3': - resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} - peerDependencies: - '@types/react': ^19.2.0 + lru-cache@11.5.0: + resolution: {integrity: sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA==} + engines: {node: 20 || >=22} - '@types/react@19.2.15': - resolution: {integrity: sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==} + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - '@types/set-cookie-parser@2.4.10': - resolution: {integrity: sha512-GGmQVGpQWUe5qglJozEjZV/5dyxbOOZ0LHe/lqyWssB88Y4svNfst0uqBVscdDeIKl5Jy5+aPSvy7mI9tYRguw==} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - '@types/statuses@2.0.6': - resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} - '@types/validate-npm-package-name@4.0.2': - resolution: {integrity: sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==} + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - '@vitejs/plugin-react@6.0.2': - resolution: {integrity: sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==} - engines: {node: ^20.19.0 || >=22.12.0} + msw@2.14.6: + resolution: {integrity: sha512-ALe+N10S72cyx94cMcy3Zs4HhXCj35sgeAL4c+WTvKi0zWnbd8/h0lcFqv0mb2P+aSgAdD7p9HzvA0DiUPxsyg==} + engines: {node: '>=18'} + hasBin: true peerDependencies: - '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 - babel-plugin-react-compiler: ^1.0.0 - vite: ^8.0.0 + typescript: '>= 4.8.x' peerDependenciesMeta: - '@rolldown/plugin-babel': - optional: true - babel-plugin-react-compiler: + typescript: optional: true - '@vitest/expect@4.1.7': - resolution: {integrity: sha512-1R+tw0ortHEbZDGMymm+pN7/AFQ/RkFFdtd7EN+VBpynKmLbP8A3rpEXdshBJ7+8hQ9zBJh/i1s0yKNtxAnU7w==} + mute-stream@3.0.0: + resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==} + engines: {node: ^20.17.0 || >=22.9.0} - '@vitest/mocker@4.1.7': - resolution: {integrity: sha512-vY7nuamKgfvpA1Koa3oYIw/k7D6kZnpGyNMZW8loow2bsBYla1TFdqTaXncWdRn4pgwNs+90RhnXhJScDwQeJA==} - peerDependencies: - msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true - '@vitest/pretty-format@4.1.7': - resolution: {integrity: sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==} + node-releases@2.0.45: + resolution: {integrity: sha512-iIbHXV9eBB2nB0wa7oTsrrXq+qQt+9SIlx9AX3T96YgobtEQfis5n6TJ6vV+3QP8DwdriEAcGhARaFCu37peBg==} + engines: {node: '>=18'} - '@vitest/runner@4.1.7': - resolution: {integrity: sha512-BapjmAQ2aI78WdMEfeUWivnfVzB+VPGwWRQcJE0OUq7qEeEcBsCSf+0T5iREBNE5nBb4wA5Ya0W6IA+sghdEFw==} + nth-check@2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - '@vitest/snapshot@4.1.7': - resolution: {integrity: sha512-ZacLzja+TmJeZ1h14xW2FB/WpeimUD3haBXQPyJqxvo8jQTmfeA8zv58mtjN2C7EHXZDYVcVYdYmAxjkWVvKCw==} + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} - '@vitest/spy@4.1.7': - resolution: {integrity: sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q==} + outvariant@1.4.3: + resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} - '@vitest/utils@4.1.7': - resolution: {integrity: sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==} + oxc-parser@0.120.0: + resolution: {integrity: sha512-WyPWZlcIm+Fkte63FGfgFB8mAAk33aH9h5N9lphXVOHSXEBFFsmYdOBedVKly363aWABjZdaj/m9lBfEY4wt+w==} + engines: {node: ^20.19.0 || >=22.12.0} - accepts@2.0.0: - resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} - engines: {node: '>= 0.6'} + parse5-htmlparser2-tree-adapter@7.1.0: + resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} - agent-base@7.1.4: - resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} - engines: {node: '>= 14'} + parse5-parser-stream@7.1.2: + resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} - ajv-formats@3.0.1: - resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} - ajv@8.20.0: - resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + parse5@8.0.1: + resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} - ansi-colors@4.1.3: - resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} - engines: {node: '>=6'} + path-to-regexp@6.3.0: + resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - ansi-regex@6.2.2: - resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} + postcss-selector-parser@6.0.10: + resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} + engines: {node: '>=4'} - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} - ansis@4.3.0: - resolution: {integrity: sha512-44mvgtPvohuU/70DdY5Oz2AIrLJ9k6/5x4KmoSvPwO+5Moijo0+N9D0fKbbYZQWP1hNm5CpOf+E01jhxG/r8xg==} + prettier@3.8.3: + resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} engines: {node: '>=14'} + hasBin: true - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} - aria-hidden@1.2.6: - resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} - engines: {node: '>=10'} + react-dom@19.2.6: + resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==} + peerDependencies: + react: ^19.2.6 - aria-query@5.3.0: - resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + react@19.2.6: + resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} + engines: {node: '>=0.10.0'} - assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} + readdirp@5.0.0: + resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} + engines: {node: '>= 20.19.0'} - ast-types@0.16.1: - resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} - engines: {node: '>=4'} + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} - babel-dead-code-elimination@1.0.12: - resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} - balanced-match@4.0.4: - resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} - engines: {node: 18 || 20 || >=22} + rettime@0.11.11: + resolution: {integrity: sha512-ILJRqVWBCTlg9r42fFgwVZx1gnFAcQF8mRoMkbgQfIrjEDf9nbBFDFx00oloOa+Q869FUtaYDXZvEfnecQSCoQ==} - baseline-browser-mapping@2.10.31: - resolution: {integrity: sha512-MujYO3eP72uvmSE0i4wltsodRfIpZATP3jvzRNRGGxgzId7aVocVJJV3nf01qnzzKFGxQVC9bpWxl5cjxTr/7Q==} - engines: {node: '>=6.0.0'} + rolldown@1.0.2: + resolution: {integrity: sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - bidi-js@1.0.3: - resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + rou3@0.8.1: + resolution: {integrity: sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA==} - body-parser@2.2.2: - resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} - engines: {node: '>=18'} - - boolbase@1.0.0: - resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - brace-expansion@5.0.6: - resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} - engines: {node: 18 || 20 || >=22} + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - browserslist@4.28.2: - resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - bundle-name@4.1.0: - resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} - engines: {node: '>=18'} + seroval-plugins@1.5.4: + resolution: {integrity: sha512-S0xQPhUTefAhNvNWFg0c1J8qJArHt5KdtJ/cFAofo06KD1MVSeFWyl4iiu+ApDIuw0WhjpOfCdgConOfAnLgkw==} + engines: {node: '>=10'} + peerDependencies: + seroval: ^1.0 - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} + seroval@1.5.4: + resolution: {integrity: sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw==} + engines: {node: '>=10'} - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} + set-cookie-parser@3.1.0: + resolution: {integrity: sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==} - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + shell-quote@1.8.3: + resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} engines: {node: '>= 0.4'} - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - - caniuse-lite@1.0.30001793: - resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==} - - chai@6.2.2: - resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} - engines: {node: '>=18'} - - chalk@5.6.2: - resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - cheerio-select@2.1.0: - resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} - cheerio@1.2.0: - resolution: {integrity: sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==} - engines: {node: '>=20.18.1'} + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} - chokidar@5.0.0: - resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} - engines: {node: '>= 20.19.0'} + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} - class-variance-authority@0.7.1: - resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + srvx@0.11.15: + resolution: {integrity: sha512-iXsux0UcOjdvs0LCMa2Ws3WwcDUozA3JN3BquNXkaFPP7TpRqgunKdEgoZ/uwb1J6xaYHfxtz9Twlh6yzwM6Tg==} + engines: {node: '>=20.16.0'} + hasBin: true - cli-cursor@5.0.0: - resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} - engines: {node: '>=18'} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - cli-spinners@2.9.2: - resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} - engines: {node: '>=6'} + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} - cli-width@4.1.0: - resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} - engines: {node: '>= 12'} + std-env@4.1.0: + resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} + strict-event-emitter@0.5.1: + resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} - clsx@2.1.1: - resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} - engines: {node: '>=6'} + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} - code-block-writer@13.0.3: - resolution: {integrity: sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==} + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + tagged-tag@1.0.0: + resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} + engines: {node: '>=20'} - commander@11.1.0: - resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} - engines: {node: '>=16'} + tailwind-merge@3.6.0: + resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==} - commander@14.0.3: - resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} - engines: {node: '>=20'} + tailwindcss@4.3.0: + resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==} - content-disposition@1.1.0: - resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} - engines: {node: '>=18'} + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - content-type@2.0.0: - resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} + tinyexec@1.1.2: + resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} engines: {node: '>=18'} - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + engines: {node: '>=12.0.0'} - cookie-es@3.1.1: - resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==} + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} + engines: {node: '>=14.0.0'} - cookie-signature@1.2.2: - resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} - engines: {node: '>=6.6.0'} + tldts-core@7.0.30: + resolution: {integrity: sha512-uiHN8PIB1VmWyS98eZYja4xzlYqeFZVjb4OuYlJQnZAuJhMw4PbKQOKgHKhBdJR3FE/t5mUQ1Kd80++B+qhD1Q==} - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} - engines: {node: '>= 0.6'} + tldts@7.0.30: + resolution: {integrity: sha512-ELrFxuqsDdHUwoh0XxDbxuLD3Wnz49Z57IFvTtvWy1hJdcMZjXLIuonjilCiWHlT2GbE4Wlv1wKVTzDFnXH1aw==} + hasBin: true - cookie@1.1.1: - resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} - engines: {node: '>=18'} + tough-cookie@6.0.1: + resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} + engines: {node: '>=16'} - cors@2.8.6: - resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} - engines: {node: '>= 0.10'} + tr46@6.0.0: + resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} + engines: {node: '>=20'} - cosmiconfig@9.0.1: - resolution: {integrity: sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==} - engines: {node: '>=14'} - peerDependencies: - typescript: '>=4.9.5' - peerDependenciesMeta: - typescript: - optional: true + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} + tw-animate-css@1.4.0: + resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} - css-select@5.2.2: - resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + type-fest@5.7.0: + resolution: {integrity: sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg==} + engines: {node: '>=20'} - css-tree@3.2.1: - resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} - engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} + engines: {node: '>=14.17'} + hasBin: true - css-what@6.2.2: - resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} - engines: {node: '>= 6'} + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} - cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - cssstyle@6.2.0: - resolution: {integrity: sha512-Fm5NvhYathRnXNVndkUsCCuR63DCLVVwGOOwQw782coXFi5HhkXdu289l59HlXZBawsyNccXfWRYvLzcDCdDig==} - engines: {node: '>=20'} + undici@7.25.0: + resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==} + engines: {node: '>=20.18.1'} - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + unplugin@3.0.0: + resolution: {integrity: sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==} + engines: {node: ^20.19.0 || >=22.12.0} - data-uri-to-buffer@4.0.1: - resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} - engines: {node: '>= 12'} + until-async@3.0.2: + resolution: {integrity: sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==} - data-urls@7.0.0: - resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' - date-fns@4.4.0: - resolution: {integrity: sha512-+1UMbeh68lH1SegH83CGWwpb6OHHbpSgr3+s5Eww5M4CAgswBpoWS0AjTOfEJ33HiYKz1hdj/KTFprzXHmq/6w==} + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - dayjs@1.11.20: - resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} + vite@8.0.14: + resolution: {integrity: sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true peerDependencies: - supports-color: '*' + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.18 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 peerDependenciesMeta: - supports-color: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: optional: true - decimal.js@10.6.0: - resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - - dedent@1.7.2: - resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} + vitefu@1.1.3: + resolution: {integrity: sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==} peerDependencies: - babel-plugin-macros: ^3.1.0 + vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: - babel-plugin-macros: + vite: optional: true - deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - - default-browser-id@5.0.1: - resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} - engines: {node: '>=18'} - - default-browser@5.5.0: - resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} + vitest@4.1.7: + resolution: {integrity: sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@opentelemetry/api': ^1.9.0 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.1.7 + '@vitest/browser-preview': 4.1.7 + '@vitest/browser-webdriverio': 4.1.7 + '@vitest/coverage-istanbul': 4.1.7 + '@vitest/coverage-v8': 4.1.7 + '@vitest/ui': 4.1.7 + happy-dom: '*' + jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@opentelemetry/api': + optional: true + '@types/node': + optional: true + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': + optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} - define-lazy-prop@3.0.0: - resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} - engines: {node: '>=12'} + webidl-conversions@8.0.1: + resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} + engines: {node: '>=20'} - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} + deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} - engines: {node: '>=8'} + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} - detect-node-es@1.1.0: - resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + whatwg-mimetype@5.0.0: + resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} + engines: {node: '>=20'} - diff@8.0.4: - resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} - engines: {node: '>=0.3.1'} + whatwg-url@16.0.1: + resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - dom-accessibility-api@0.5.16: - resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true - dom-serializer@2.0.0: - resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} - domelementtype@2.3.0: - resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + ws@8.20.1: + resolution: {integrity: sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true - domhandler@5.0.3: - resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} - engines: {node: '>= 4'} + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} - domutils@3.2.2: - resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + xmlbuilder2@4.0.3: + resolution: {integrity: sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA==} + engines: {node: '>=20.0'} - dotenv@17.4.2: - resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} - engines: {node: '>=12'} + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} - eciesjs@0.4.18: - resolution: {integrity: sha512-wG99Zcfcys9fZux7Cft8BAX/YrOJLJSZ3jyYPfhZHqN2E+Ffx+QXBDsv3gubEgPtV6dTzJMSQUwk1H98/t/0wQ==} - engines: {bun: '>=1', deno: '>=2', node: '>=16'} + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} - electron-to-chromium@1.5.360: - resolution: {integrity: sha512-GkcBt6YYAw9SxFWn+xVar4cLVGlXVuswwtRLBozi2zp0GjXs4ZnOrqV4zbXzg35n7w81hCkyJNYicgXlVHAmBA==} + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} - emoji-regex@10.6.0: - resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} +snapshots: - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} + '@acemir/cssom@0.9.31': + optional: true - encoding-sniffer@0.2.1: - resolution: {integrity: sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==} + '@asamuzakjp/css-color@5.1.11': + dependencies: + '@asamuzakjp/generational-cache': 1.0.1 + '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-color-parser': 4.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + optional: true - enhanced-resolve@5.21.6: - resolution: {integrity: sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==} - engines: {node: '>=10.13.0'} + '@asamuzakjp/dom-selector@6.8.1': + dependencies: + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.2.1 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.5.0 + optional: true - enquirer@2.4.1: - resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} - engines: {node: '>=8.6'} + '@asamuzakjp/generational-cache@1.0.1': + optional: true - entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} + '@asamuzakjp/nwsapi@2.3.9': + optional: true - entities@6.0.1: - resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} - engines: {node: '>=0.12'} + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 - entities@7.0.1: - resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} - engines: {node: '>=0.12'} + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 - entities@8.0.0: - resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} - engines: {node: '>=20.19.0'} + '@babel/compat-data@7.29.3': {} - env-paths@2.2.1: - resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} - engines: {node: '>=6'} + '@babel/core@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-compilation-targets': 7.28.6 + '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) + '@babel/helpers': 7.29.2 + '@babel/parser': 7.29.3 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color - error-ex@1.3.4: - resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} + '@babel/helper-compilation-targets@7.28.6': + dependencies: + '@babel/compat-data': 7.29.3 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.2 + lru-cache: 5.1.1 + semver: 6.3.1 - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} + '@babel/helper-globals@7.28.0': {} - es-module-lexer@2.1.0: - resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} + '@babel/helper-module-imports@7.28.6': + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + transitivePeerDependencies: + - supports-color - es-object-atoms@1.1.2: - resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} - engines: {node: '>= 0.4'} + '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-module-imports': 7.28.6 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.29.0 + transitivePeerDependencies: + - supports-color - esbuild@0.28.1: - resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} - engines: {node: '>=18'} - hasBin: true + '@babel/helper-plugin-utils@7.28.6': {} - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} + '@babel/helper-string-parser@7.27.1': {} - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + '@babel/helper-validator-identifier@7.28.5': {} - esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true + '@babel/helper-validator-option@7.27.1': {} - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + '@babel/helpers@7.29.2': + dependencies: + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} + '@babel/parser@7.29.3': + dependencies: + '@babel/types': 7.29.0 - eventsource-parser@3.1.0: - resolution: {integrity: sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==} - engines: {node: '>=18.0.0'} + '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - eventsource@3.0.7: - resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} - engines: {node: '>=18.0.0'} - - execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} + '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': + dependencies: + '@babel/core': 7.29.0 + '@babel/helper-plugin-utils': 7.28.6 - execa@9.6.1: - resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} - engines: {node: ^18.19.0 || >=20.5.0} + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.3 + '@babel/types': 7.29.0 - expect-type@1.3.0: - resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} - engines: {node: '>=12.0.0'} + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.3 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color - express-rate-limit@8.5.2: - resolution: {integrity: sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==} - engines: {node: '>= 16'} - peerDependencies: - express: '>= 4.11' + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 - express@5.2.1: - resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} - engines: {node: '>= 18'} + '@biomejs/biome@2.4.5': + optionalDependencies: + '@biomejs/cli-darwin-arm64': 2.4.5 + '@biomejs/cli-darwin-x64': 2.4.5 + '@biomejs/cli-linux-arm64': 2.4.5 + '@biomejs/cli-linux-arm64-musl': 2.4.5 + '@biomejs/cli-linux-x64': 2.4.5 + '@biomejs/cli-linux-x64-musl': 2.4.5 + '@biomejs/cli-win32-arm64': 2.4.5 + '@biomejs/cli-win32-x64': 2.4.5 - exsolve@1.0.8: - resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} + '@biomejs/cli-darwin-arm64@2.4.5': + optional: true - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + '@biomejs/cli-darwin-x64@2.4.5': + optional: true - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} + '@biomejs/cli-linux-arm64-musl@2.4.5': + optional: true - fast-string-truncated-width@3.0.3: - resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} + '@biomejs/cli-linux-arm64@2.4.5': + optional: true - fast-string-width@3.0.2: - resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} + '@biomejs/cli-linux-x64-musl@2.4.5': + optional: true - fast-uri@3.1.2: - resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} + '@biomejs/cli-linux-x64@2.4.5': + optional: true - fast-wrap-ansi@0.2.2: - resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} + '@biomejs/cli-win32-arm64@2.4.5': + optional: true - fastq@1.20.1: - resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + '@biomejs/cli-win32-x64@2.4.5': + optional: true - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true + '@bramus/specificity@2.4.2': + dependencies: + css-tree: 3.2.1 + optional: true - fetch-blob@3.2.0: - resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} - engines: {node: ^12.20 || >= 14.13} + '@csstools/color-helpers@6.0.2': + optional: true - fetchdts@0.1.7: - resolution: {integrity: sha512-YoZjBdafyLIop9lSxXVI33oLD5kN31q4Td+CasofLLYeLXRFeOsuOw0Uo+XNRi9PZlbfdlN2GmRtm4tCEQ9/KA==} + '@csstools/css-calc@3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + optional: true - figures@6.1.0: - resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} - engines: {node: '>=18'} + '@csstools/css-color-parser@4.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/color-helpers': 6.0.2 + '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + optional: true - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} + '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-tokenizer': 4.0.0 + optional: true - finalhandler@2.1.1: - resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} - engines: {node: '>= 18.0.0'} + '@csstools/css-syntax-patches-for-csstree@1.1.4(css-tree@3.2.1)': + optionalDependencies: + css-tree: 3.2.1 + optional: true - formdata-polyfill@4.0.10: - resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} - engines: {node: '>=12.20.0'} + '@csstools/css-tokenizer@4.0.0': + optional: true - forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true - framer-motion@12.40.0: - resolution: {integrity: sha512-uaBd3qC1v3KQqBEjwTUd183K6PbS+j0yR9w9VmEOLWA/tnUcSn8Xa3uck7t4dgpDoUss8xQTcj8W2L07lrnLFg==} - peerDependencies: - '@emotion/is-prop-valid': '*' - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@emotion/is-prop-valid': - optional: true - react: - optional: true - react-dom: - optional: true + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true - fresh@2.0.0: - resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} - engines: {node: '>= 0.8'} + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true - fs-extra@11.3.5: - resolution: {integrity: sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==} - engines: {node: '>=14.14'} + '@esbuild/aix-ppc64@0.28.1': + optional: true - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] + '@esbuild/android-arm64@0.28.1': + optional: true - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + '@esbuild/android-arm@0.28.1': + optional: true - fuzzysort@3.1.0: - resolution: {integrity: sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==} + '@esbuild/android-x64@0.28.1': + optional: true - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} + '@esbuild/darwin-arm64@0.28.1': + optional: true - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} + '@esbuild/darwin-x64@0.28.1': + optional: true - get-east-asian-width@1.6.0: - resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} - engines: {node: '>=18'} + '@esbuild/freebsd-arm64@0.28.1': + optional: true - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} + '@esbuild/freebsd-x64@0.28.1': + optional: true - get-nonce@1.0.1: - resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} - engines: {node: '>=6'} + '@esbuild/linux-arm64@0.28.1': + optional: true - get-own-enumerable-keys@1.0.0: - resolution: {integrity: sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==} - engines: {node: '>=14.16'} + '@esbuild/linux-arm@0.28.1': + optional: true - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} + '@esbuild/linux-ia32@0.28.1': + optional: true - get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} + '@esbuild/linux-loong64@0.28.1': + optional: true - get-stream@9.0.1: - resolution: {integrity: sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==} - engines: {node: '>=18'} + '@esbuild/linux-mips64el@0.28.1': + optional: true - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} + '@esbuild/linux-ppc64@0.28.1': + optional: true - goober@2.1.19: - resolution: {integrity: sha512-U7veizMqxyKlM58+Z5j2ngJBH/r9siDmxpvNxSw0PylF6WQvrASJEZrxh1hidRBJc2jqoBVSyOban5u8m+6Rxg==} - peerDependencies: - csstype: ^3.0.10 + '@esbuild/linux-riscv64@0.28.1': + optional: true - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} + '@esbuild/linux-s390x@0.28.1': + optional: true - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + '@esbuild/linux-x64@0.28.1': + optional: true - graphql@16.14.1: - resolution: {integrity: sha512-cQOsSMS/IrDz82PVyRDvf/Q1F/bRbBVjJlh+xYOkI1qw2bWRvWGiWc+m2O0d6l4Bt1fyY+8kzJ8JFWGJqNeDBg==} - engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + '@esbuild/netbsd-arm64@0.28.1': + optional: true - h3@2.0.1-rc.20: - resolution: {integrity: sha512-28ljodXuUp0fZovdiSRq4G9OgrxCztrJe5VdYzXAB7ueRvI7pIUqLU14Xi3XqdYJ/khXjfpUOOD2EQa6CmBgsg==} - engines: {node: '>=20.11.1'} - hasBin: true - peerDependencies: - crossws: ^0.4.1 - peerDependenciesMeta: - crossws: - optional: true + '@esbuild/netbsd-x64@0.28.1': + optional: true - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} + '@esbuild/openbsd-arm64@0.28.1': + optional: true - hasown@2.0.4: - resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} - engines: {node: '>= 0.4'} + '@esbuild/openbsd-x64@0.28.1': + optional: true - headers-polyfill@5.0.1: - resolution: {integrity: sha512-1TJ6Fih/b8h5TIcv+1+Hw0PDQWJTKDKzFZzcKOiW1wJza3XoAQlkCuXLbymPYB8+ZQyw8mHvdw560e8zVFIWyA==} + '@esbuild/openharmony-arm64@0.28.1': + optional: true - hono@4.12.23: - resolution: {integrity: sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==} - engines: {node: '>=16.9.0'} + '@esbuild/sunos-x64@0.28.1': + optional: true - html-encoding-sniffer@6.0.0: - resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + '@esbuild/win32-arm64@0.28.1': + optional: true - htmlparser2@10.1.0: - resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} + '@esbuild/win32-ia32@0.28.1': + optional: true - http-errors@2.0.1: - resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} - engines: {node: '>= 0.8'} + '@esbuild/win32-x64@0.28.1': + optional: true - http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} + '@exodus/bytes@1.15.1(@noble/hashes@1.8.0)': + optionalDependencies: + '@noble/hashes': 1.8.0 + optional: true - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} + '@inquirer/ansi@2.0.7': + optional: true - human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} + '@inquirer/confirm@6.1.1(@types/node@22.19.19)': + dependencies: + '@inquirer/core': 11.2.1(@types/node@22.19.19) + '@inquirer/type': 4.0.7(@types/node@22.19.19) + optionalDependencies: + '@types/node': 22.19.19 + optional: true - human-signals@8.0.1: - resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} - engines: {node: '>=18.18.0'} + '@inquirer/core@11.2.1(@types/node@22.19.19)': + dependencies: + '@inquirer/ansi': 2.0.7 + '@inquirer/figures': 2.0.7 + '@inquirer/type': 4.0.7(@types/node@22.19.19) + cli-width: 4.1.0 + fast-wrap-ansi: 0.2.2 + mute-stream: 3.0.0 + signal-exit: 4.1.0 + optionalDependencies: + '@types/node': 22.19.19 + optional: true - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} + '@inquirer/figures@2.0.7': + optional: true - iconv-lite@0.7.2: - resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} - engines: {node: '>=0.10.0'} + '@inquirer/type@4.0.7(@types/node@22.19.19)': + optionalDependencies: + '@types/node': 22.19.19 + optional: true - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + '@jridgewell/resolve-uri@3.1.2': {} - ip-address@10.2.0: - resolution: {integrity: sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==} - engines: {node: '>= 12'} - - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - - is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - - is-docker@3.0.0: - resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - hasBin: true - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-in-ssh@1.0.0: - resolution: {integrity: sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==} - engines: {node: '>=20'} - - is-inside-container@1.0.0: - resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} - engines: {node: '>=14.16'} - hasBin: true - - is-interactive@2.0.0: - resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} - engines: {node: '>=12'} - - is-node-process@1.2.0: - resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-obj@3.0.0: - resolution: {integrity: sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==} - engines: {node: '>=12'} - - is-plain-obj@4.1.0: - resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} - engines: {node: '>=12'} - - is-potential-custom-element-name@1.0.1: - resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - - is-promise@4.0.0: - resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} - - is-regexp@3.1.0: - resolution: {integrity: sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==} - engines: {node: '>=12'} - - is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - - is-stream@4.0.1: - resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} - engines: {node: '>=18'} - - is-unicode-supported@1.3.0: - resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} - engines: {node: '>=12'} - - is-unicode-supported@2.1.0: - resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} - engines: {node: '>=18'} - - is-wsl@3.1.1: - resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} - engines: {node: '>=16'} - - isbot@5.1.40: - resolution: {integrity: sha512-yNeeynhhtIVRBk12tBV4eHNxwB42HzR4Q3Ea7vCOiJhImGaAIdIMrbJtacQlBizGLjUPw+akkFI5Dn9T70XoVQ==} - engines: {node: '>=18'} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - isexe@3.1.5: - resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} - engines: {node: '>=18'} - - jiti@2.7.0: - resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} - hasBin: true - - jose@6.2.3: - resolution: {integrity: sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==} - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} - hasBin: true - - jsdom@28.1.0: - resolution: {integrity: sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - peerDependencies: - canvas: ^3.0.0 - peerDependenciesMeta: - canvas: - optional: true - - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - - json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - - json-schema-typed@8.0.2: - resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} - - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - - jsonfile@6.2.1: - resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} - - kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} - - kleur@4.1.5: - resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} - engines: {node: '>=6'} - - launch-editor@2.13.2: - resolution: {integrity: sha512-4VVDnbOpLXy/s8rdRCSXb+zfMeFR0WlJWpET1iA9CQdlZDfwyLjUuGQzXU4VeOoey6AicSAluWan7Etga6Kcmg==} - - lightningcss-android-arm64@1.32.0: - resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [android] - - lightningcss-darwin-arm64@1.32.0: - resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] - - lightningcss-darwin-x64@1.32.0: - resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] - - lightningcss-freebsd-x64@1.32.0: - resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] - - lightningcss-linux-arm-gnueabihf@1.32.0: - resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] - - lightningcss-linux-arm64-gnu@1.32.0: - resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - - lightningcss-linux-arm64-musl@1.32.0: - resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - - lightningcss-linux-x64-gnu@1.32.0: - resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - - lightningcss-linux-x64-musl@1.32.0: - resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - - lightningcss-win32-arm64-msvc@1.32.0: - resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [win32] - - lightningcss-win32-x64-msvc@1.32.0: - resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - - lightningcss@1.32.0: - resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} - engines: {node: '>= 12.0.0'} - - lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - - log-symbols@6.0.0: - resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} - engines: {node: '>=18'} - - lru-cache@11.5.0: - resolution: {integrity: sha512-5YgH9UJd7wVb9hIouI2adWpgqrrICkt070Dnj8EUY1+B4B2P9eRLPAkAAo6NICA7CEhOIeBHl46u9zSNpNu7zA==} - engines: {node: 20 || >=22} - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - - lucide-react@0.577.0: - resolution: {integrity: sha512-4LjoFv2eEPwYDPg/CUdBJQSDfPyzXCRrVW1X7jrx/trgxnxkHFjnVZINbzvzxjN70dxychOfg+FTYwBiS3pQ5A==} - peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - lz-string@1.5.0: - resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} - hasBin: true - - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - mdn-data@2.27.1: - resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} - - media-typer@1.1.0: - resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} - engines: {node: '>= 0.8'} - - merge-descriptors@2.0.0: - resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} - engines: {node: '>=18'} - - merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} - - mime-db@1.54.0: - resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} - engines: {node: '>= 0.6'} - - mime-types@3.0.2: - resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} - engines: {node: '>=18'} - - mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - - mimic-function@5.0.1: - resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} - engines: {node: '>=18'} - - minimatch@10.2.5: - resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} - engines: {node: 18 || 20 || >=22} - - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - motion-dom@12.40.0: - resolution: {integrity: sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg==} - - motion-utils@12.39.0: - resolution: {integrity: sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==} - - motion@12.40.0: - resolution: {integrity: sha512-yjrHUrBFW6kQvjJwRsoiPSAhC5tRwRqNGJWmiJ4CrGnbKp0V88AdzkhBmDoqIsIPfarOe0Uddd37Xq43/gIocA==} - peerDependencies: - '@emotion/is-prop-valid': '*' - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@emotion/is-prop-valid': - optional: true - react: - optional: true - react-dom: - optional: true - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - msw@2.14.6: - resolution: {integrity: sha512-ALe+N10S72cyx94cMcy3Zs4HhXCj35sgeAL4c+WTvKi0zWnbd8/h0lcFqv0mb2P+aSgAdD7p9HzvA0DiUPxsyg==} - engines: {node: '>=18'} - hasBin: true - peerDependencies: - typescript: '>= 4.8.x' - peerDependenciesMeta: - typescript: - optional: true - - mute-stream@3.0.0: - resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==} - engines: {node: ^20.17.0 || >=22.9.0} - - nanoid@3.3.12: - resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - negotiator@1.0.0: - resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} - engines: {node: '>= 0.6'} - - node-domexception@1.0.0: - resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} - engines: {node: '>=10.5.0'} - deprecated: Use your platform's native DOMException instead - - node-fetch@3.3.2: - resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - node-releases@2.0.45: - resolution: {integrity: sha512-iIbHXV9eBB2nB0wa7oTsrrXq+qQt+9SIlx9AX3T96YgobtEQfis5n6TJ6vV+3QP8DwdriEAcGhARaFCu37peBg==} - engines: {node: '>=18'} - - npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} - - npm-run-path@6.0.0: - resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} - engines: {node: '>=18'} - - nth-check@2.1.1: - resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} - - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - object-treeify@1.1.33: - resolution: {integrity: sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==} - engines: {node: '>= 10'} - - obug@2.1.1: - resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} - - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} - - onetime@7.0.0: - resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} - engines: {node: '>=18'} - - open@11.0.0: - resolution: {integrity: sha512-smsWv2LzFjP03xmvFoJ331ss6h+jixfA4UUV/Bsiyuu4YJPfN+FIQGOIiv4w9/+MoHkfkJ22UIaQWRVFRfH6Vw==} - engines: {node: '>=20'} - - ora@8.2.0: - resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} - engines: {node: '>=18'} - - outvariant@1.4.3: - resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} - - oxc-parser@0.120.0: - resolution: {integrity: sha512-WyPWZlcIm+Fkte63FGfgFB8mAAk33aH9h5N9lphXVOHSXEBFFsmYdOBedVKly363aWABjZdaj/m9lBfEY4wt+w==} - engines: {node: ^20.19.0 || >=22.12.0} - - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - - parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} - - parse-ms@4.0.0: - resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==} - engines: {node: '>=18'} - - parse5-htmlparser2-tree-adapter@7.1.0: - resolution: {integrity: sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==} - - parse5-parser-stream@7.1.2: - resolution: {integrity: sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==} - - parse5@7.3.0: - resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} - - parse5@8.0.1: - resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} - - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - - path-browserify@1.0.1: - resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-key@4.0.0: - resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} - engines: {node: '>=12'} - - path-to-regexp@6.3.0: - resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} - - path-to-regexp@8.4.2: - resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} - - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@2.3.2: - resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} - engines: {node: '>=8.6'} - - picomatch@4.0.4: - resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} - engines: {node: '>=12'} - - pkce-challenge@5.0.1: - resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} - engines: {node: '>=16.20.0'} - - postcss-selector-parser@6.0.10: - resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} - engines: {node: '>=4'} - - postcss-selector-parser@7.1.1: - resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} - engines: {node: '>=4'} - - postcss@8.5.15: - resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} - engines: {node: ^10 || ^12 || >=14} - - powershell-utils@0.1.0: - resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} - engines: {node: '>=20'} - - prettier@3.8.3: - resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==} - engines: {node: '>=14'} - hasBin: true - - pretty-format@27.5.1: - resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - - pretty-ms@9.3.0: - resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} - engines: {node: '>=18'} - - prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} - - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - qs@6.15.2: - resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==} - engines: {node: '>=0.6'} - - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - - radix-ui@1.4.3: - resolution: {integrity: sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - - raw-body@3.0.2: - resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} - engines: {node: '>= 0.10'} - - react-day-picker@10.0.1: - resolution: {integrity: sha512-eNh6BlwcYInWaJtRv18mXQ06Ys/H6rdTZAnTaSdOYJuTpwP1JMCHNd1FDRadA+gbeinq+psdULN5Xnowy9mV8w==} - engines: {node: '>=18'} - peerDependencies: - '@types/react': '>=16.8.0' - react: '>=16.8.0' - peerDependenciesMeta: - '@types/react': - optional: true - - react-dom@19.2.6: - resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==} - peerDependencies: - react: ^19.2.6 - - react-is@17.0.2: - resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - - react-remove-scroll-bar@2.3.8: - resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - react-remove-scroll@2.7.2: - resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - react-style-singleton@2.2.3: - resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - react-use-websocket@4.13.0: - resolution: {integrity: sha512-anMuVoV//g2N76Wxqvqjjo1X48r9Np3y1/gMl7arX84tAPXdy5R7sB5lO5hvCzQRYjqXwV8XMAiEBOUbyrZFrw==} - - react@19.2.6: - resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} - engines: {node: '>=0.10.0'} - - readdirp@5.0.0: - resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} - engines: {node: '>= 20.19.0'} - - recast@0.23.11: - resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} - engines: {node: '>= 4'} - - remove-accents@0.5.0: - resolution: {integrity: sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==} - - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - - reselect@5.2.0: - resolution: {integrity: sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==} - - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - - restore-cursor@5.1.0: - resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} - engines: {node: '>=18'} - - rettime@0.11.11: - resolution: {integrity: sha512-ILJRqVWBCTlg9r42fFgwVZx1gnFAcQF8mRoMkbgQfIrjEDf9nbBFDFx00oloOa+Q869FUtaYDXZvEfnecQSCoQ==} - - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - rolldown@1.0.2: - resolution: {integrity: sha512-oZx5zVDtVB44AW3eaifgDml1gWRDZGvjcfdxonE4swNPG98PrrXjaO/KrnUjzlMnztCCRVlUueA1kCXhARGk6g==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - - rou3@0.8.1: - resolution: {integrity: sha512-ePa+XGk00/3HuCqrEnK3LxJW7I0SdNg6EFzKUJG73hMAdDcOUC/i/aSz7LSDwLrGr33kal/rqOGydzwl6U7zBA==} - - router@2.2.0: - resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} - engines: {node: '>= 18'} - - run-applescript@7.1.0: - resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} - engines: {node: '>=18'} - - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - saxes@6.0.0: - resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} - engines: {node: '>=v12.22.7'} - - scheduler@0.27.0: - resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - - scichart-financial-tools@5.2.28: - resolution: {integrity: sha512-ZrmIlgnnMWpLmGjdhomJ4yfB26QzbbFi8gFGoS0i58Ku/llQ10mp4j6VcJ8VjSbLLNbehvGuJkaW8UGicpNU5A==} - peerDependencies: - scichart: ^5.2.28 - - scichart-react@1.0.0: - resolution: {integrity: sha512-fadf70hDbK1W9lSgNV28ovc+3W75MBOwshZ2+Wdr0oTtpGnzIkEDfVCkutaHa4UylzzpcB2jrYeyawKk3iqq7w==} - peerDependencies: - react: '>=16.8.0' - scichart: '>=4.0.828' - - scichart@5.2.28: - resolution: {integrity: sha512-zVwt1n55vyoVeBxUdBxzXFmaEsaxOO004z9EdmXjPxu/DNjFeBWeNktnhgAckjgfDV/+W4cEUnA9DTlLpV43GA==} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - send@1.2.1: - resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} - engines: {node: '>= 18'} - - seroval-plugins@1.5.4: - resolution: {integrity: sha512-S0xQPhUTefAhNvNWFg0c1J8qJArHt5KdtJ/cFAofo06KD1MVSeFWyl4iiu+ApDIuw0WhjpOfCdgConOfAnLgkw==} - engines: {node: '>=10'} - peerDependencies: - seroval: ^1.0 - - seroval@1.5.4: - resolution: {integrity: sha512-46uFvgrXTVxZcUorgSSRZ4y+ieqLLQRMlG4bnCZKW3qI6BZm7Rg4ntMW4p1mILEEBZWrFlcpp0AyIIlM6jD9iw==} - engines: {node: '>=10'} - - serve-static@2.2.1: - resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} - engines: {node: '>= 18'} - - set-cookie-parser@3.1.0: - resolution: {integrity: sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - - shadcn@4.10.0: - resolution: {integrity: sha512-84IJhUsK0xqSCRJx3QxyZe2NpUXj2Nwk8Vc8Ow/tCOND3yz4CT6uU4655vqicNXhzG9Q1cyUt+TBl2SiCJwNgg==} - hasBin: true - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - shell-quote@1.8.3: - resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} - engines: {node: '>= 0.4'} - - side-channel-list@1.0.1: - resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - - signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - - solid-js@1.9.13: - resolution: {integrity: sha512-6hJeJMOcEX8ktqjpDoJZEmld3ijvcvWBDtiXBm7f4332SiFN66QeAQI1REQshvyUoISsSeJ4PHDauKYbwao9JQ==} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - - source-map@0.7.6: - resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} - engines: {node: '>= 12'} - - srvx@0.11.15: - resolution: {integrity: sha512-iXsux0UcOjdvs0LCMa2Ws3WwcDUozA3JN3BquNXkaFPP7TpRqgunKdEgoZ/uwb1J6xaYHfxtz9Twlh6yzwM6Tg==} - engines: {node: '>=20.16.0'} - hasBin: true - - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - - statuses@2.0.2: - resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} - engines: {node: '>= 0.8'} - - std-env@4.1.0: - resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} - - stdin-discarder@0.2.2: - resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} - engines: {node: '>=18'} - - strict-event-emitter@0.5.1: - resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string-width@7.2.0: - resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} - engines: {node: '>=18'} - - stringify-object@5.0.0: - resolution: {integrity: sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==} - engines: {node: '>=14.16'} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-ansi@7.2.0: - resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} - engines: {node: '>=12'} - - strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - - strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - - strip-final-newline@4.0.0: - resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==} - engines: {node: '>=18'} - - symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - - tagged-tag@1.0.0: - resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} - engines: {node: '>=20'} - - tailwind-merge@3.6.0: - resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==} - - tailwindcss@4.3.0: - resolution: {integrity: sha512-y6nxMGB1nMW9R6k96e5gdIFzcfL/gTJRNaqGes1YvkLnPVXzWgbqFF2yLC0T8G774n24cx3Pe8XrKoniCOAH+Q==} - - tapable@2.3.3: - resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} - engines: {node: '>=6'} - - tiny-invariant@1.3.3: - resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} - - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - - tinyexec@1.1.2: - resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} - engines: {node: '>=18'} - - tinyglobby@0.2.16: - resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} - engines: {node: '>=12.0.0'} - - tinyrainbow@3.1.0: - resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} - engines: {node: '>=14.0.0'} - - tldts-core@7.0.30: - resolution: {integrity: sha512-uiHN8PIB1VmWyS98eZYja4xzlYqeFZVjb4OuYlJQnZAuJhMw4PbKQOKgHKhBdJR3FE/t5mUQ1Kd80++B+qhD1Q==} - - tldts@7.0.30: - resolution: {integrity: sha512-ELrFxuqsDdHUwoh0XxDbxuLD3Wnz49Z57IFvTtvWy1hJdcMZjXLIuonjilCiWHlT2GbE4Wlv1wKVTzDFnXH1aw==} - hasBin: true - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - - tough-cookie@6.0.1: - resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} - engines: {node: '>=16'} - - tr46@6.0.0: - resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} - engines: {node: '>=20'} - - ts-morph@26.0.0: - resolution: {integrity: sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug==} - - tsconfig-paths@4.2.0: - resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} - engines: {node: '>=6'} - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - tw-animate-css@1.4.0: - resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} - - type-fest@5.7.0: - resolution: {integrity: sha512-1URUxUqfHFM1c+zfSPsa3gnkO7Aq21qyH75SIduNYz4SzY964rn1X2vCMQaHSHhktiw+0kPa2iyb6PUpXqB6Vg==} - engines: {node: '>=20'} - - type-is@2.1.0: - resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} - engines: {node: '>= 18'} - - typescript@6.0.3: - resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} - engines: {node: '>=14.17'} - hasBin: true - - ufo@1.6.4: - resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} - - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - - undici@7.25.0: - resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==} - engines: {node: '>=20.18.1'} - - unicorn-magic@0.3.0: - resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==} - engines: {node: '>=18'} - - universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} - - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - - unplugin@3.0.0: - resolution: {integrity: sha512-0Mqk3AT2TZCXWKdcoaufeXNukv2mTrEZExeXlHIOZXdqYoHHr4n51pymnwV8x2BOVxwXbK2HLlI7usrqMpycdg==} - engines: {node: ^20.19.0 || >=22.12.0} - - until-async@3.0.2: - resolution: {integrity: sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==} - - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - use-callback-ref@1.3.3: - resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - use-sidecar@1.1.3: - resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - use-sync-external-store@1.6.0: - resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - validate-npm-package-name@7.0.2: - resolution: {integrity: sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==} - engines: {node: ^20.17.0 || >=22.9.0} - - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - - vite@8.0.14: - resolution: {integrity: sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.1.18 - esbuild: ^0.27.0 || ^0.28.0 - jiti: '>=1.21.0' - less: ^4.0.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - '@vitejs/devtools': - optional: true - esbuild: - optional: true - jiti: - optional: true - less: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - vitefu@1.1.3: - resolution: {integrity: sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==} - peerDependencies: - vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - vite: - optional: true - - vitest@4.1.7: - resolution: {integrity: sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA==} - engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@opentelemetry/api': ^1.9.0 - '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.7 - '@vitest/browser-preview': 4.1.7 - '@vitest/browser-webdriverio': 4.1.7 - '@vitest/coverage-istanbul': 4.1.7 - '@vitest/coverage-v8': 4.1.7 - '@vitest/ui': 4.1.7 - happy-dom: '*' - jsdom: '*' - vite: ^6.0.0 || ^7.0.0 || ^8.0.0 - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@opentelemetry/api': - optional: true - '@types/node': - optional: true - '@vitest/browser-playwright': - optional: true - '@vitest/browser-preview': - optional: true - '@vitest/browser-webdriverio': - optional: true - '@vitest/coverage-istanbul': - optional: true - '@vitest/coverage-v8': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - - w3c-xmlserializer@5.0.0: - resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} - engines: {node: '>=18'} - - web-streams-polyfill@3.3.3: - resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} - engines: {node: '>= 8'} - - webidl-conversions@8.0.1: - resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} - engines: {node: '>=20'} - - webpack-virtual-modules@0.6.2: - resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - - whatwg-encoding@3.1.1: - resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} - engines: {node: '>=18'} - deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation - - whatwg-mimetype@4.0.0: - resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} - engines: {node: '>=18'} - - whatwg-mimetype@5.0.0: - resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} - engines: {node: '>=20'} - - whatwg-url@16.0.1: - resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - which@4.0.0: - resolution: {integrity: sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==} - engines: {node: ^16.13.0 || >=18.0.0} - hasBin: true - - why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} - hasBin: true - - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - ws@8.20.1: - resolution: {integrity: sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - wsl-utils@0.3.1: - resolution: {integrity: sha512-g/eziiSUNBSsdDJtCLB8bdYEUMj4jR7AGeUo96p/3dTafgjHhpF4RiCFPiRILwjQoDXx5MqkBr4fwWtR3Ky4Wg==} - engines: {node: '>=20'} - - xml-name-validator@5.0.0: - resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} - engines: {node: '>=18'} - - xmlbuilder2@4.0.3: - resolution: {integrity: sha512-bx8Q1STctnNaaDymWnkfQLKofs0mGNN7rLLapJlGuV3VlvegD7Ls4ggMjE3aUSWItCCzU0PEv45lI87iSigiCA==} - engines: {node: '>=20.0'} - - xmlchars@2.2.0: - resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - - yocto-spinner@1.2.0: - resolution: {integrity: sha512-Yw0hUB6UA3o4YUgKy3oSe9a4cxoaZ9sBfYDw+JSxo6Id0KoJGoxzPA24qqUXYKBWABs/zDSGTz9kww7t3F0XGw==} - engines: {node: '>=18.19'} - - yoctocolors@2.1.2: - resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} - engines: {node: '>=18'} - - zod-to-json-schema@3.25.2: - resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} - peerDependencies: - zod: ^3.25.28 || ^4 - - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - - zod@4.4.3: - resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} - -snapshots: - - '@acemir/cssom@0.9.31': {} - - '@asamuzakjp/css-color@5.1.11': - dependencies: - '@asamuzakjp/generational-cache': 1.0.1 - '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-color-parser': 4.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - - '@asamuzakjp/dom-selector@6.8.1': - dependencies: - '@asamuzakjp/nwsapi': 2.3.9 - bidi-js: 1.0.3 - css-tree: 3.2.1 - is-potential-custom-element-name: 1.0.1 - lru-cache: 11.5.0 - - '@asamuzakjp/generational-cache@1.0.1': {} - - '@asamuzakjp/nwsapi@2.3.9': {} - - '@babel/code-frame@7.27.1': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/code-frame@7.29.0': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/code-frame@7.29.7': - dependencies: - '@babel/helper-validator-identifier': 7.29.7 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.29.3': {} - - '@babel/core@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.29.2 - '@babel/parser': 7.29.3 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.29.1': - dependencies: - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/generator@7.29.7': - dependencies: - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-annotate-as-pure@7.29.7': - dependencies: - '@babel/types': 7.29.7 - - '@babel/helper-compilation-targets@7.28.6': - dependencies: - '@babel/compat-data': 7.29.3 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.2 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-member-expression-to-functions': 7.29.7 - '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.0) - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 - '@babel/traverse': 7.29.7 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-globals@7.29.7': {} - - '@babel/helper-member-expression-to-functions@7.29.7': - dependencies: - '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-imports@7.28.6': - dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-imports@7.29.7': - dependencies: - '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.29.7 - '@babel/helper-validator-identifier': 7.29.7 - '@babel/traverse': 7.29.7 - transitivePeerDependencies: - - supports-color - - '@babel/helper-optimise-call-expression@7.29.7': - dependencies: - '@babel/types': 7.29.7 - - '@babel/helper-plugin-utils@7.28.6': {} - - '@babel/helper-plugin-utils@7.29.7': {} - - '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-member-expression-to-functions': 7.29.7 - '@babel/helper-optimise-call-expression': 7.29.7 - '@babel/traverse': 7.29.7 - transitivePeerDependencies: - - supports-color - - '@babel/helper-skip-transparent-expression-wrappers@7.29.7': - dependencies: - '@babel/traverse': 7.29.7 - '@babel/types': 7.29.7 - transitivePeerDependencies: - - supports-color - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-string-parser@7.29.7': {} - - '@babel/helper-validator-identifier@7.28.5': {} - - '@babel/helper-validator-identifier@7.29.7': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helper-validator-option@7.29.7': {} - - '@babel/helpers@7.29.2': - dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - - '@babel/parser@7.29.3': - dependencies: - '@babel/types': 7.29.0 - - '@babel/parser@7.29.7': - dependencies: - '@babel/types': 7.29.7 - - '@babel/plugin-syntax-jsx@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.28.6 - - '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - - '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.29.7 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-typescript@7.29.7(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-annotate-as-pure': 7.29.7 - '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.0) - '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-skip-transparent-expression-wrappers': 7.29.7 - '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.0) - transitivePeerDependencies: - - supports-color - - '@babel/preset-typescript@7.29.7(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-plugin-utils': 7.29.7 - '@babel/helper-validator-option': 7.29.7 - '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.0) - '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.0) - '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.0) - transitivePeerDependencies: - - supports-color - - '@babel/runtime@7.29.2': {} - - '@babel/template@7.28.6': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.3 - '@babel/types': 7.29.0 - - '@babel/template@7.29.7': - dependencies: - '@babel/code-frame': 7.29.7 - '@babel/parser': 7.29.7 - '@babel/types': 7.29.7 - - '@babel/traverse@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.3 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - '@babel/traverse@7.29.7': - dependencies: - '@babel/code-frame': 7.29.7 - '@babel/generator': 7.29.7 - '@babel/helper-globals': 7.29.7 - '@babel/parser': 7.29.7 - '@babel/template': 7.29.7 - '@babel/types': 7.29.7 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.29.0': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - '@babel/types@7.29.7': - dependencies: - '@babel/helper-string-parser': 7.29.7 - '@babel/helper-validator-identifier': 7.29.7 - - '@base-ui/react@1.5.0(@date-fns/tz@1.5.0)(@types/react@19.2.15)(date-fns@4.4.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@babel/runtime': 7.29.2 - '@base-ui/utils': 0.2.9(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@floating-ui/react-dom': 2.1.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@floating-ui/utils': 0.2.11 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - use-sync-external-store: 1.6.0(react@19.2.6) - optionalDependencies: - '@date-fns/tz': 1.5.0 - '@types/react': 19.2.15 - date-fns: 4.4.0 - - '@base-ui/utils@0.2.9(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@babel/runtime': 7.29.2 - '@floating-ui/utils': 0.2.11 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - reselect: 5.2.0 - use-sync-external-store: 1.6.0(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - - '@bramus/specificity@2.4.2': - dependencies: - css-tree: 3.2.1 - - '@csstools/color-helpers@6.0.2': {} - - '@csstools/css-calc@3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': - dependencies: - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - - '@csstools/css-color-parser@4.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': - dependencies: - '@csstools/color-helpers': 6.0.2 - '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 - - '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': - dependencies: - '@csstools/css-tokenizer': 4.0.0 - - '@csstools/css-syntax-patches-for-csstree@1.1.4(css-tree@3.2.1)': - optionalDependencies: - css-tree: 3.2.1 - - '@csstools/css-tokenizer@4.0.0': {} - - '@date-fns/tz@1.5.0': {} - - '@dotenvx/dotenvx@1.71.0': - dependencies: - commander: 11.1.0 - dotenv: 17.4.2 - eciesjs: 0.4.18 - enquirer: 2.4.1 - execa: 5.1.1 - fdir: 6.5.0(picomatch@4.0.4) - ignore: 5.3.2 - object-treeify: 1.1.33 - picomatch: 4.0.4 - which: 4.0.0 - yocto-spinner: 1.2.0 - - '@ecies/ciphers@0.2.6(@noble/ciphers@1.3.0)': - dependencies: - '@noble/ciphers': 1.3.0 - - '@emnapi/core@1.10.0': - dependencies: - '@emnapi/wasi-threads': 1.2.1 - tslib: 2.8.1 - optional: true - - '@emnapi/runtime@1.10.0': - dependencies: - tslib: 2.8.1 - optional: true - - '@emnapi/wasi-threads@1.2.1': - dependencies: - tslib: 2.8.1 - optional: true - - '@esbuild/aix-ppc64@0.28.1': - optional: true - - '@esbuild/android-arm64@0.28.1': - optional: true - - '@esbuild/android-arm@0.28.1': - optional: true - - '@esbuild/android-x64@0.28.1': - optional: true - - '@esbuild/darwin-arm64@0.28.1': - optional: true - - '@esbuild/darwin-x64@0.28.1': - optional: true - - '@esbuild/freebsd-arm64@0.28.1': - optional: true - - '@esbuild/freebsd-x64@0.28.1': - optional: true - - '@esbuild/linux-arm64@0.28.1': - optional: true - - '@esbuild/linux-arm@0.28.1': - optional: true - - '@esbuild/linux-ia32@0.28.1': - optional: true - - '@esbuild/linux-loong64@0.28.1': - optional: true - - '@esbuild/linux-mips64el@0.28.1': - optional: true - - '@esbuild/linux-ppc64@0.28.1': - optional: true - - '@esbuild/linux-riscv64@0.28.1': - optional: true - - '@esbuild/linux-s390x@0.28.1': - optional: true - - '@esbuild/linux-x64@0.28.1': - optional: true - - '@esbuild/netbsd-arm64@0.28.1': - optional: true - - '@esbuild/netbsd-x64@0.28.1': - optional: true - - '@esbuild/openbsd-arm64@0.28.1': - optional: true - - '@esbuild/openbsd-x64@0.28.1': - optional: true - - '@esbuild/openharmony-arm64@0.28.1': - optional: true - - '@esbuild/sunos-x64@0.28.1': - optional: true - - '@esbuild/win32-arm64@0.28.1': - optional: true - - '@esbuild/win32-ia32@0.28.1': - optional: true - - '@esbuild/win32-x64@0.28.1': - optional: true - - '@exodus/bytes@1.15.1(@noble/hashes@1.8.0)': - optionalDependencies: - '@noble/hashes': 1.8.0 - - '@faker-js/faker@10.4.0': {} - - '@floating-ui/core@1.7.5': - dependencies: - '@floating-ui/utils': 0.2.11 - - '@floating-ui/dom@1.7.6': - dependencies: - '@floating-ui/core': 1.7.5 - '@floating-ui/utils': 0.2.11 - - '@floating-ui/react-dom@2.1.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@floating-ui/dom': 1.7.6 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - - '@floating-ui/utils@0.2.11': {} - - '@fontsource-variable/geist@5.2.9': {} - - '@fontsource-variable/inter@5.2.8': {} - - '@hono/node-server@1.19.14(hono@4.12.23)': - dependencies: - hono: 4.12.23 - - '@inquirer/ansi@2.0.7': {} - - '@inquirer/confirm@6.1.1(@types/node@22.19.19)': - dependencies: - '@inquirer/core': 11.2.1(@types/node@22.19.19) - '@inquirer/type': 4.0.7(@types/node@22.19.19) - optionalDependencies: - '@types/node': 22.19.19 - - '@inquirer/core@11.2.1(@types/node@22.19.19)': - dependencies: - '@inquirer/ansi': 2.0.7 - '@inquirer/figures': 2.0.7 - '@inquirer/type': 4.0.7(@types/node@22.19.19) - cli-width: 4.1.0 - fast-wrap-ansi: 0.2.2 - mute-stream: 3.0.0 - signal-exit: 4.1.0 - optionalDependencies: - '@types/node': 22.19.19 - - '@inquirer/figures@2.0.7': {} - - '@inquirer/type@4.0.7(@types/node@22.19.19)': - optionalDependencies: - '@types/node': 22.19.19 - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@modelcontextprotocol/sdk@1.29.0(zod@3.25.76)': - dependencies: - '@hono/node-server': 1.19.14(hono@4.12.23) - ajv: 8.20.0 - ajv-formats: 3.0.1(ajv@8.20.0) - content-type: 1.0.5 - cors: 2.8.6 - cross-spawn: 7.0.6 - eventsource: 3.0.7 - eventsource-parser: 3.1.0 - express: 5.2.1 - express-rate-limit: 8.5.2(express@5.2.1) - hono: 4.12.23 - jose: 6.2.3 - json-schema-typed: 8.0.2 - pkce-challenge: 5.0.1 - raw-body: 3.0.2 - zod: 3.25.76 - zod-to-json-schema: 3.25.2(zod@3.25.76) - transitivePeerDependencies: - - supports-color - - '@mswjs/interceptors@0.41.9': - dependencies: - '@open-draft/deferred-promise': 2.2.0 - '@open-draft/logger': 0.3.0 - '@open-draft/until': 2.1.0 - is-node-process: 1.2.0 - outvariant: 1.4.3 - strict-event-emitter: 0.5.1 - - '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.2 - optional: true - - '@noble/ciphers@1.3.0': {} - - '@noble/curves@1.9.7': - dependencies: - '@noble/hashes': 1.8.0 - - '@noble/hashes@1.8.0': {} - - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.20.1 - - '@oozcitak/dom@2.0.2': - dependencies: - '@oozcitak/infra': 2.0.2 - '@oozcitak/url': 3.0.0 - '@oozcitak/util': 10.0.0 - - '@oozcitak/infra@2.0.2': - dependencies: - '@oozcitak/util': 10.0.0 - - '@oozcitak/url@3.0.0': - dependencies: - '@oozcitak/infra': 2.0.2 - '@oozcitak/util': 10.0.0 - - '@oozcitak/util@10.0.0': {} - - '@open-draft/deferred-promise@2.2.0': {} - - '@open-draft/deferred-promise@3.0.0': {} - - '@open-draft/logger@0.3.0': - dependencies: - is-node-process: 1.2.0 - outvariant: 1.4.3 - - '@open-draft/until@2.1.0': {} - - '@oxc-parser/binding-android-arm-eabi@0.120.0': - optional: true - - '@oxc-parser/binding-android-arm64@0.120.0': - optional: true - - '@oxc-parser/binding-darwin-arm64@0.120.0': - optional: true - - '@oxc-parser/binding-darwin-x64@0.120.0': - optional: true - - '@oxc-parser/binding-freebsd-x64@0.120.0': - optional: true - - '@oxc-parser/binding-linux-arm-gnueabihf@0.120.0': - optional: true - - '@oxc-parser/binding-linux-arm-musleabihf@0.120.0': - optional: true - - '@oxc-parser/binding-linux-arm64-gnu@0.120.0': - optional: true - - '@oxc-parser/binding-linux-arm64-musl@0.120.0': - optional: true - - '@oxc-parser/binding-linux-ppc64-gnu@0.120.0': - optional: true - - '@oxc-parser/binding-linux-riscv64-gnu@0.120.0': - optional: true - - '@oxc-parser/binding-linux-riscv64-musl@0.120.0': - optional: true - - '@oxc-parser/binding-linux-s390x-gnu@0.120.0': - optional: true - - '@oxc-parser/binding-linux-x64-gnu@0.120.0': - optional: true - - '@oxc-parser/binding-linux-x64-musl@0.120.0': - optional: true - - '@oxc-parser/binding-openharmony-arm64@0.120.0': - optional: true - - '@oxc-parser/binding-wasm32-wasi@0.120.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': - dependencies: - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - optional: true - - '@oxc-parser/binding-win32-arm64-msvc@0.120.0': - optional: true - - '@oxc-parser/binding-win32-ia32-msvc@0.120.0': - optional: true - - '@oxc-parser/binding-win32-x64-msvc@0.120.0': - optional: true - - '@oxc-project/types@0.120.0': {} - - '@oxc-project/types@0.132.0': {} - - '@radix-ui/number@1.1.1': {} - - '@radix-ui/primitive@1.1.3': {} - - '@radix-ui/react-accessible-icon@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-accordion@1.2.12(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-aspect-ratio@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-avatar@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.15)(react@19.2.6)': - dependencies: - react: 19.2.6 - optionalDependencies: - '@types/react': 19.2.15 - - '@radix-ui/react-context-menu@2.2.16(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-context@1.1.2(@types/react@19.2.15)(react@19.2.6)': - dependencies: - react: 19.2.6 - optionalDependencies: - '@types/react': 19.2.15 - - '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - aria-hidden: 1.2.6 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - react-remove-scroll: 2.7.2(@types/react@19.2.15)(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-direction@1.1.1(@types/react@19.2.15)(react@19.2.6)': - dependencies: - react: 19.2.6 - optionalDependencies: - '@types/react': 19.2.15 - - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.15)(react@19.2.6)': - dependencies: - react: 19.2.6 - optionalDependencies: - '@types/react': 19.2.15 - - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-form@0.1.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-label': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-hover-card@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-id@1.1.1(@types/react@19.2.15)(react@19.2.6)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - optionalDependencies: - '@types/react': 19.2.15 - - '@radix-ui/react-label@2.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) - aria-hidden: 1.2.6 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - react-remove-scroll: 2.7.2(@types/react@19.2.15)(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-menubar@1.1.16(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-one-time-password-field@0.1.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-password-toggle-field@0.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - aria-hidden: 1.2.6 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - react-remove-scroll: 2.7.2(@types/react@19.2.15)(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@floating-ui/react-dom': 2.1.8(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/rect': 1.1.1 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-progress@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-radio-group@1.3.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - aria-hidden: 1.2.6 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - react-remove-scroll: 2.7.2(@types/react@19.2.15)(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-separator@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-slider@1.3.6(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-slot@1.2.3(@types/react@19.2.15)(react@19.2.6)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - optionalDependencies: - '@types/react': 19.2.15 - - '@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-toast@1.2.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-toggle-group@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-toggle@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-toolbar@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@jridgewell/sourcemap-codec@1.5.5': {} - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.15)(react@19.2.6)': + '@jridgewell/trace-mapping@0.3.31': dependencies: - react: 19.2.6 - optionalDependencies: - '@types/react': 19.2.15 + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.15)(react@19.2.6)': + '@mswjs/interceptors@0.41.9': dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - optionalDependencies: - '@types/react': 19.2.15 + '@open-draft/deferred-promise': 2.2.0 + '@open-draft/logger': 0.3.0 + '@open-draft/until': 2.1.0 + is-node-process: 1.2.0 + outvariant: 1.4.3 + strict-event-emitter: 0.5.1 + optional: true - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.15)(react@19.2.6)': + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - optionalDependencies: - '@types/react': 19.2.15 + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.2 + optional: true - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.15)(react@19.2.6)': - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - optionalDependencies: - '@types/react': 19.2.15 + '@noble/hashes@1.8.0': + optional: true - '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@19.2.15)(react@19.2.6)': + '@oozcitak/dom@2.0.2': dependencies: - react: 19.2.6 - use-sync-external-store: 1.6.0(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 + '@oozcitak/infra': 2.0.2 + '@oozcitak/url': 3.0.0 + '@oozcitak/util': 10.0.0 - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.15)(react@19.2.6)': + '@oozcitak/infra@2.0.2': dependencies: - react: 19.2.6 - optionalDependencies: - '@types/react': 19.2.15 + '@oozcitak/util': 10.0.0 - '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.15)(react@19.2.6)': + '@oozcitak/url@3.0.0': dependencies: - react: 19.2.6 - optionalDependencies: - '@types/react': 19.2.15 + '@oozcitak/infra': 2.0.2 + '@oozcitak/util': 10.0.0 - '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.15)(react@19.2.6)': - dependencies: - '@radix-ui/rect': 1.1.1 - react: 19.2.6 - optionalDependencies: - '@types/react': 19.2.15 + '@oozcitak/util@10.0.0': {} - '@radix-ui/react-use-size@1.1.1(@types/react@19.2.15)(react@19.2.6)': + '@open-draft/deferred-promise@2.2.0': + optional: true + + '@open-draft/deferred-promise@3.0.0': + optional: true + + '@open-draft/logger@0.3.0': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - react: 19.2.6 - optionalDependencies: - '@types/react': 19.2.15 + is-node-process: 1.2.0 + outvariant: 1.4.3 + optional: true + + '@open-draft/until@2.1.0': + optional: true + + '@oxc-parser/binding-android-arm-eabi@0.120.0': + optional: true + + '@oxc-parser/binding-android-arm64@0.120.0': + optional: true + + '@oxc-parser/binding-darwin-arm64@0.120.0': + optional: true + + '@oxc-parser/binding-darwin-x64@0.120.0': + optional: true + + '@oxc-parser/binding-freebsd-x64@0.120.0': + optional: true + + '@oxc-parser/binding-linux-arm-gnueabihf@0.120.0': + optional: true + + '@oxc-parser/binding-linux-arm-musleabihf@0.120.0': + optional: true + + '@oxc-parser/binding-linux-arm64-gnu@0.120.0': + optional: true - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': + '@oxc-parser/binding-linux-arm64-musl@0.120.0': + optional: true + + '@oxc-parser/binding-linux-ppc64-gnu@0.120.0': + optional: true + + '@oxc-parser/binding-linux-riscv64-gnu@0.120.0': + optional: true + + '@oxc-parser/binding-linux-riscv64-musl@0.120.0': + optional: true + + '@oxc-parser/binding-linux-s390x-gnu@0.120.0': + optional: true + + '@oxc-parser/binding-linux-x64-gnu@0.120.0': + optional: true + + '@oxc-parser/binding-linux-x64-musl@0.120.0': + optional: true + + '@oxc-parser/binding-openharmony-arm64@0.120.0': + optional: true + + '@oxc-parser/binding-wasm32-wasi@0.120.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + transitivePeerDependencies: + - '@emnapi/core' + - '@emnapi/runtime' + optional: true + + '@oxc-parser/binding-win32-arm64-msvc@0.120.0': + optional: true + + '@oxc-parser/binding-win32-ia32-msvc@0.120.0': + optional: true - '@radix-ui/rect@1.1.1': {} + '@oxc-parser/binding-win32-x64-msvc@0.120.0': + optional: true + + '@oxc-project/types@0.120.0': {} + + '@oxc-project/types@0.132.0': {} '@rolldown/binding-android-arm64@1.0.2': optional: true @@ -5519,44 +2487,6 @@ snapshots: '@rolldown/pluginutils@1.0.1': {} - '@sec-ant/readable-stream@0.4.1': {} - - '@sindresorhus/merge-streams@4.0.0': {} - - '@solid-primitives/event-listener@2.4.5(solid-js@1.9.13)': - dependencies: - '@solid-primitives/utils': 6.4.0(solid-js@1.9.13) - solid-js: 1.9.13 - - '@solid-primitives/keyboard@1.3.5(solid-js@1.9.13)': - dependencies: - '@solid-primitives/event-listener': 2.4.5(solid-js@1.9.13) - '@solid-primitives/rootless': 1.5.3(solid-js@1.9.13) - '@solid-primitives/utils': 6.4.0(solid-js@1.9.13) - solid-js: 1.9.13 - - '@solid-primitives/resize-observer@2.1.5(solid-js@1.9.13)': - dependencies: - '@solid-primitives/event-listener': 2.4.5(solid-js@1.9.13) - '@solid-primitives/rootless': 1.5.3(solid-js@1.9.13) - '@solid-primitives/static-store': 0.1.3(solid-js@1.9.13) - '@solid-primitives/utils': 6.4.0(solid-js@1.9.13) - solid-js: 1.9.13 - - '@solid-primitives/rootless@1.5.3(solid-js@1.9.13)': - dependencies: - '@solid-primitives/utils': 6.4.0(solid-js@1.9.13) - solid-js: 1.9.13 - - '@solid-primitives/static-store@0.1.3(solid-js@1.9.13)': - dependencies: - '@solid-primitives/utils': 6.4.0(solid-js@1.9.13) - solid-js: 1.9.13 - - '@solid-primitives/utils@6.4.0(solid-js@1.9.13)': - dependencies: - solid-js: 1.9.13 - '@standard-schema/spec@1.1.0': {} '@tailwindcss/node@4.3.0': @@ -5645,15 +2575,6 @@ snapshots: '@tanstack/devtools-event-client@0.4.3': {} - '@tanstack/devtools-ui@0.5.2(csstype@3.2.3)(solid-js@1.9.13)': - dependencies: - clsx: 2.1.1 - dayjs: 1.11.20 - goober: 2.1.19(csstype@3.2.3) - solid-js: 1.9.13 - transitivePeerDependencies: - - csstype - '@tanstack/devtools-vite@0.7.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)(vite@8.0.14(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0))': dependencies: '@tanstack/devtools-client': 0.0.6 @@ -5670,70 +2591,8 @@ snapshots: - bufferutil - utf-8-validate - '@tanstack/devtools@0.12.2(csstype@3.2.3)(solid-js@1.9.13)': - dependencies: - '@solid-primitives/event-listener': 2.4.5(solid-js@1.9.13) - '@solid-primitives/keyboard': 1.3.5(solid-js@1.9.13) - '@solid-primitives/resize-observer': 2.1.5(solid-js@1.9.13) - '@tanstack/devtools-client': 0.0.6 - '@tanstack/devtools-event-bus': 0.4.1 - '@tanstack/devtools-ui': 0.5.2(csstype@3.2.3)(solid-js@1.9.13) - clsx: 2.1.1 - goober: 2.1.19(csstype@3.2.3) - solid-js: 1.9.13 - transitivePeerDependencies: - - bufferutil - - csstype - - utf-8-validate - - '@tanstack/form-core@1.32.0': - dependencies: - '@tanstack/devtools-event-client': 0.4.3 - '@tanstack/pacer-lite': 0.1.1 - '@tanstack/store': 0.9.3 - '@tanstack/history@1.162.0': {} - '@tanstack/match-sorter-utils@8.19.4': - dependencies: - remove-accents: 0.5.0 - - '@tanstack/pacer-lite@0.1.1': {} - - '@tanstack/react-devtools@0.10.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(csstype@3.2.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(solid-js@1.9.13)': - dependencies: - '@tanstack/devtools': 0.12.2(csstype@3.2.3)(solid-js@1.9.13) - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - transitivePeerDependencies: - - bufferutil - - csstype - - solid-js - - utf-8-validate - - '@tanstack/react-form@1.32.0(@tanstack/react-start@1.168.9(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite@8.0.14(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0)))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@tanstack/form-core': 1.32.0 - '@tanstack/react-store': 0.9.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react: 19.2.6 - optionalDependencies: - '@tanstack/react-start': 1.168.9(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(vite@8.0.14(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0)) - transitivePeerDependencies: - - react-dom - - '@tanstack/react-router-devtools@1.167.0(@tanstack/react-router@1.170.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(@tanstack/router-core@1.171.4)(csstype@3.2.3)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@tanstack/react-router': 1.170.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@tanstack/router-devtools-core': 1.168.0(@tanstack/router-core@1.171.4)(csstype@3.2.3) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@tanstack/router-core': 1.171.4 - transitivePeerDependencies: - - csstype - '@tanstack/react-router@1.170.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': dependencies: '@tanstack/history': 1.162.0 @@ -5822,12 +2681,6 @@ snapshots: react-dom: 19.2.6(react@19.2.6) use-sync-external-store: 1.6.0(react@19.2.6) - '@tanstack/react-table@8.21.3(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@tanstack/table-core': 8.21.3 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - '@tanstack/router-core@1.171.4': dependencies: '@tanstack/history': 1.162.0 @@ -5835,14 +2688,6 @@ snapshots: seroval: 1.5.4 seroval-plugins: 1.5.4(seroval@1.5.4) - '@tanstack/router-devtools-core@1.168.0(@tanstack/router-core@1.171.4)(csstype@3.2.3)': - dependencies: - '@tanstack/router-core': 1.171.4 - clsx: 2.1.1 - goober: 2.1.19(csstype@3.2.3) - optionalDependencies: - csstype: 3.2.3 - '@tanstack/router-generator@1.167.8': dependencies: '@babel/types': 7.29.0 @@ -5954,44 +2799,13 @@ snapshots: '@tanstack/store@0.9.3': {} - '@tanstack/table-core@8.21.3': {} - '@tanstack/virtual-file-routes@1.162.0': {} - '@testing-library/dom@10.4.1': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/runtime': 7.29.2 - '@types/aria-query': 5.0.4 - aria-query: 5.3.0 - dom-accessibility-api: 0.5.16 - lz-string: 1.5.0 - picocolors: 1.1.1 - pretty-format: 27.5.1 - - '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)': - dependencies: - '@babel/runtime': 7.29.2 - '@testing-library/dom': 10.4.1 - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - '@ts-morph/common@0.27.0': - dependencies: - fast-glob: 3.3.3 - minimatch: 10.2.5 - path-browserify: 1.0.1 - '@tybys/wasm-util@0.10.2': dependencies: tslib: 2.8.1 optional: true - '@types/aria-query@5.0.4': {} - '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 @@ -6016,10 +2830,10 @@ snapshots: '@types/set-cookie-parser@2.4.10': dependencies: '@types/node': 22.19.19 + optional: true - '@types/statuses@2.0.6': {} - - '@types/validate-npm-package-name@4.0.2': {} + '@types/statuses@2.0.6': + optional: true '@vitejs/plugin-react@6.0.2(vite@8.0.14(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0))': dependencies: @@ -6068,54 +2882,23 @@ snapshots: convert-source-map: 2.0.0 tinyrainbow: 3.1.0 - accepts@2.0.0: - dependencies: - mime-types: 3.0.2 - negotiator: 1.0.0 - - agent-base@7.1.4: {} - - ajv-formats@3.0.1(ajv@8.20.0): - optionalDependencies: - ajv: 8.20.0 - - ajv@8.20.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.2 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - - ansi-colors@4.1.3: {} - - ansi-regex@5.0.1: {} + agent-base@7.1.4: + optional: true - ansi-regex@6.2.2: {} + ansi-regex@5.0.1: + optional: true ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 - - ansi-styles@5.2.0: {} + optional: true ansis@4.3.0: {} argparse@2.0.1: {} - aria-hidden@1.2.6: - dependencies: - tslib: 2.8.1 - - aria-query@5.3.0: - dependencies: - dequal: 2.0.3 - assertion-error@2.0.1: {} - ast-types@0.16.1: - dependencies: - tslib: 2.8.1 - babel-dead-code-elimination@1.0.12: dependencies: '@babel/core': 7.29.0 @@ -6125,37 +2908,14 @@ snapshots: transitivePeerDependencies: - supports-color - balanced-match@4.0.4: {} - baseline-browser-mapping@2.10.31: {} bidi-js@1.0.3: dependencies: - require-from-string: 2.0.2 - - body-parser@2.2.2: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 4.4.3 - http-errors: 2.0.1 - iconv-lite: 0.7.2 - on-finished: 2.4.1 - qs: 6.15.2 - raw-body: 3.0.2 - type-is: 2.1.0 - transitivePeerDependencies: - - supports-color - - boolbase@1.0.0: {} - - brace-expansion@5.0.6: - dependencies: - balanced-match: 4.0.4 + require-from-string: 2.0.2 + optional: true - braces@3.0.3: - dependencies: - fill-range: 7.1.1 + boolbase@1.0.0: {} browserslist@4.28.2: dependencies: @@ -6165,24 +2925,6 @@ snapshots: node-releases: 2.0.45 update-browserslist-db: 1.2.3(browserslist@4.28.2) - bundle-name@4.1.0: - dependencies: - run-applescript: 7.1.0 - - bytes@3.1.2: {} - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - - callsites@3.1.0: {} - caniuse-lite@1.0.30001793: {} chai@6.2.2: {} @@ -6216,73 +2958,32 @@ snapshots: dependencies: readdirp: 5.0.0 - class-variance-authority@0.7.1: - dependencies: - clsx: 2.1.1 - - cli-cursor@5.0.0: - dependencies: - restore-cursor: 5.1.0 - - cli-spinners@2.9.2: {} - - cli-width@4.1.0: {} + cli-width@4.1.0: + optional: true cliui@8.0.1: dependencies: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + optional: true clsx@2.1.1: {} - code-block-writer@13.0.3: {} - color-convert@2.0.1: dependencies: color-name: 1.1.4 + optional: true - color-name@1.1.4: {} - - commander@11.1.0: {} - - commander@14.0.3: {} - - content-disposition@1.1.0: {} - - content-type@1.0.5: {} - - content-type@2.0.0: {} + color-name@1.1.4: + optional: true convert-source-map@2.0.0: {} cookie-es@3.1.1: {} - cookie-signature@1.2.2: {} - - cookie@0.7.2: {} - - cookie@1.1.1: {} - - cors@2.8.6: - dependencies: - object-assign: 4.1.1 - vary: 1.1.2 - - cosmiconfig@9.0.1(typescript@6.0.3): - dependencies: - env-paths: 2.2.1 - import-fresh: 3.3.1 - js-yaml: 4.1.1 - parse-json: 5.2.0 - optionalDependencies: - typescript: 6.0.3 - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 + cookie@1.1.1: + optional: true css-select@5.2.2: dependencies: @@ -6296,6 +2997,7 @@ snapshots: dependencies: mdn-data: 2.27.1 source-map-js: 1.2.1 + optional: true css-what@6.2.2: {} @@ -6307,53 +3009,29 @@ snapshots: '@csstools/css-syntax-patches-for-csstree': 1.1.4(css-tree@3.2.1) css-tree: 3.2.1 lru-cache: 11.5.0 + optional: true csstype@3.2.3: {} - data-uri-to-buffer@4.0.1: {} - data-urls@7.0.0(@noble/hashes@1.8.0): dependencies: whatwg-mimetype: 5.0.0 whatwg-url: 16.0.1(@noble/hashes@1.8.0) transitivePeerDependencies: - '@noble/hashes' - - date-fns@4.4.0: {} - - dayjs@1.11.20: {} + optional: true debug@4.4.3: dependencies: ms: 2.1.3 - decimal.js@10.6.0: {} - - dedent@1.7.2: {} - - deepmerge@4.3.1: {} - - default-browser-id@5.0.1: {} - - default-browser@5.5.0: - dependencies: - bundle-name: 4.1.0 - default-browser-id: 5.0.1 - - define-lazy-prop@3.0.0: {} - - depd@2.0.0: {} - - dequal@2.0.3: {} + decimal.js@10.6.0: + optional: true detect-libc@2.1.2: {} - detect-node-es@1.1.0: {} - diff@8.0.4: {} - dom-accessibility-api@0.5.16: {} - dom-serializer@2.0.0: dependencies: domelementtype: 2.3.0 @@ -6372,30 +3050,10 @@ snapshots: domelementtype: 2.3.0 domhandler: 5.0.3 - dotenv@17.4.2: {} - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - eciesjs@0.4.18: - dependencies: - '@ecies/ciphers': 0.2.6(@noble/ciphers@1.3.0) - '@noble/ciphers': 1.3.0 - '@noble/curves': 1.9.7 - '@noble/hashes': 1.8.0 - - ee-first@1.1.1: {} - electron-to-chromium@1.5.360: {} - emoji-regex@10.6.0: {} - - emoji-regex@8.0.0: {} - - encodeurl@2.0.0: {} + emoji-regex@8.0.0: + optional: true encoding-sniffer@0.2.1: dependencies: @@ -6407,35 +3065,17 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.3 - enquirer@2.4.1: - dependencies: - ansi-colors: 4.1.3 - strip-ansi: 6.0.1 - entities@4.5.0: {} entities@6.0.1: {} entities@7.0.1: {} - entities@8.0.0: {} - - env-paths@2.2.1: {} - - error-ex@1.3.4: - dependencies: - is-arrayish: 0.2.1 - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} + entities@8.0.0: + optional: true es-module-lexer@2.1.0: {} - es-object-atoms@1.1.2: - dependencies: - es-errors: 1.3.0 - esbuild@0.28.1: optionalDependencies: '@esbuild/aix-ppc64': 0.28.1 @@ -6467,249 +3107,63 @@ snapshots: escalade@3.2.0: {} - escape-html@1.0.3: {} - - esprima@4.0.1: {} - estree-walker@3.0.3: dependencies: '@types/estree': 1.0.9 - etag@1.8.1: {} - - eventsource-parser@3.1.0: {} - - eventsource@3.0.7: - dependencies: - eventsource-parser: 3.1.0 - - execa@5.1.1: - dependencies: - cross-spawn: 7.0.6 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - - execa@9.6.1: - dependencies: - '@sindresorhus/merge-streams': 4.0.0 - cross-spawn: 7.0.6 - figures: 6.1.0 - get-stream: 9.0.1 - human-signals: 8.0.1 - is-plain-obj: 4.1.0 - is-stream: 4.0.1 - npm-run-path: 6.0.0 - pretty-ms: 9.3.0 - signal-exit: 4.1.0 - strip-final-newline: 4.0.0 - yoctocolors: 2.1.2 - expect-type@1.3.0: {} - express-rate-limit@8.5.2(express@5.2.1): - dependencies: - express: 5.2.1 - ip-address: 10.2.0 - - express@5.2.1: - dependencies: - accepts: 2.0.0 - body-parser: 2.2.2 - content-disposition: 1.1.0 - content-type: 1.0.5 - cookie: 0.7.2 - cookie-signature: 1.2.2 - debug: 4.4.3 - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 2.1.1 - fresh: 2.0.0 - http-errors: 2.0.1 - merge-descriptors: 2.0.0 - mime-types: 3.0.2 - on-finished: 2.4.1 - once: 1.4.0 - parseurl: 1.3.3 - proxy-addr: 2.0.7 - qs: 6.15.2 - range-parser: 1.2.1 - router: 2.2.0 - send: 1.2.1 - serve-static: 2.2.1 - statuses: 2.0.2 - type-is: 2.1.0 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - exsolve@1.0.8: {} - fast-deep-equal@3.1.3: {} - - fast-glob@3.3.3: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - - fast-string-truncated-width@3.0.3: {} + fast-string-truncated-width@3.0.3: + optional: true fast-string-width@3.0.2: dependencies: fast-string-truncated-width: 3.0.3 - - fast-uri@3.1.2: {} + optional: true fast-wrap-ansi@0.2.2: dependencies: fast-string-width: 3.0.2 - - fastq@1.20.1: - dependencies: - reusify: 1.1.0 + optional: true fdir@6.5.0(picomatch@4.0.4): optionalDependencies: picomatch: 4.0.4 - fetch-blob@3.2.0: - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 3.3.3 - fetchdts@0.1.7: {} - figures@6.1.0: - dependencies: - is-unicode-supported: 2.1.0 - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - finalhandler@2.1.1: - dependencies: - debug: 4.4.3 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - - formdata-polyfill@4.0.10: - dependencies: - fetch-blob: 3.2.0 - - forwarded@0.2.0: {} - - framer-motion@12.40.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): - dependencies: - motion-dom: 12.40.0 - motion-utils: 12.39.0 - tslib: 2.8.1 - optionalDependencies: - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - - fresh@2.0.0: {} - - fs-extra@11.3.5: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.2.1 - universalify: 2.0.1 - fsevents@2.3.3: optional: true - function-bind@1.1.2: {} - - fuzzysort@3.1.0: {} - gensync@1.0.0-beta.2: {} - get-caller-file@2.0.5: {} - - get-east-asian-width@1.6.0: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.2 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.4 - math-intrinsics: 1.1.0 - - get-nonce@1.0.1: {} - - get-own-enumerable-keys@1.0.0: {} - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.2 - - get-stream@6.0.1: {} - - get-stream@9.0.1: - dependencies: - '@sec-ant/readable-stream': 0.4.1 - is-stream: 4.0.1 - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - goober@2.1.19(csstype@3.2.3): - dependencies: - csstype: 3.2.3 - - gopd@1.2.0: {} + get-caller-file@2.0.5: + optional: true graceful-fs@4.2.11: {} - graphql@16.14.1: {} + graphql@16.14.1: + optional: true h3@2.0.1-rc.20: dependencies: rou3: 0.8.1 srvx: 0.11.15 - has-symbols@1.1.0: {} - - hasown@2.0.4: - dependencies: - function-bind: 1.1.2 - headers-polyfill@5.0.1: dependencies: '@types/set-cookie-parser': 2.4.10 set-cookie-parser: 3.1.0 - - hono@4.12.23: {} + optional: true html-encoding-sniffer@6.0.0(@noble/hashes@1.8.0): dependencies: '@exodus/bytes': 1.15.1(@noble/hashes@1.8.0) transitivePeerDependencies: - '@noble/hashes' + optional: true htmlparser2@10.1.0: dependencies: @@ -6718,20 +3172,13 @@ snapshots: domutils: 3.2.2 entities: 7.0.1 - http-errors@2.0.1: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.2 - toidentifier: 1.0.1 - http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 debug: 4.4.3 transitivePeerDependencies: - supports-color + optional: true https-proxy-agent@7.0.6: dependencies: @@ -6739,88 +3186,25 @@ snapshots: debug: 4.4.3 transitivePeerDependencies: - supports-color - - human-signals@2.1.0: {} - - human-signals@8.0.1: {} + optional: true iconv-lite@0.6.3: dependencies: safer-buffer: 2.1.2 - iconv-lite@0.7.2: - dependencies: - safer-buffer: 2.1.2 - - ignore@5.3.2: {} - - import-fresh@3.3.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - - inherits@2.0.4: {} - - ip-address@10.2.0: {} - - ipaddr.js@1.9.1: {} - - is-arrayish@0.2.1: {} - - is-docker@3.0.0: {} - - is-extglob@2.1.1: {} - - is-fullwidth-code-point@3.0.0: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-in-ssh@1.0.0: {} - - is-inside-container@1.0.0: - dependencies: - is-docker: 3.0.0 - - is-interactive@2.0.0: {} - - is-node-process@1.2.0: {} - - is-number@7.0.0: {} - - is-obj@3.0.0: {} - - is-plain-obj@4.1.0: {} - - is-potential-custom-element-name@1.0.1: {} - - is-promise@4.0.0: {} - - is-regexp@3.1.0: {} - - is-stream@2.0.1: {} - - is-stream@4.0.1: {} - - is-unicode-supported@1.3.0: {} + is-fullwidth-code-point@3.0.0: + optional: true - is-unicode-supported@2.1.0: {} + is-node-process@1.2.0: + optional: true - is-wsl@3.1.1: - dependencies: - is-inside-container: 1.0.0 + is-potential-custom-element-name@1.0.1: + optional: true isbot@5.1.40: {} - isexe@2.0.0: {} - - isexe@3.1.5: {} - jiti@2.7.0: {} - jose@6.2.3: {} - js-tokens@4.0.0: {} js-yaml@4.1.1: @@ -6853,27 +3237,12 @@ snapshots: transitivePeerDependencies: - '@noble/hashes' - supports-color + optional: true jsesc@3.1.0: {} - json-parse-even-better-errors@2.3.1: {} - - json-schema-traverse@1.0.0: {} - - json-schema-typed@8.0.2: {} - json5@2.2.3: {} - jsonfile@6.2.1: - dependencies: - universalify: 2.0.1 - optionalDependencies: - graceful-fs: 4.2.11 - - kleur@3.0.3: {} - - kleur@4.1.5: {} - launch-editor@2.13.2: dependencies: picocolors: 1.1.1 @@ -6928,75 +3297,19 @@ snapshots: lightningcss-win32-arm64-msvc: 1.32.0 lightningcss-win32-x64-msvc: 1.32.0 - lines-and-columns@1.2.4: {} - - log-symbols@6.0.0: - dependencies: - chalk: 5.6.2 - is-unicode-supported: 1.3.0 - - lru-cache@11.5.0: {} + lru-cache@11.5.0: + optional: true lru-cache@5.1.1: dependencies: yallist: 3.1.1 - lucide-react@0.577.0(react@19.2.6): - dependencies: - react: 19.2.6 - - lz-string@1.5.0: {} - magic-string@0.30.21: dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - math-intrinsics@1.1.0: {} - - mdn-data@2.27.1: {} - - media-typer@1.1.0: {} - - merge-descriptors@2.0.0: {} - - merge-stream@2.0.0: {} - - merge2@1.4.1: {} - - micromatch@4.0.8: - dependencies: - braces: 3.0.3 - picomatch: 2.3.2 - - mime-db@1.54.0: {} - - mime-types@3.0.2: - dependencies: - mime-db: 1.54.0 - - mimic-fn@2.1.0: {} - - mimic-function@5.0.1: {} - - minimatch@10.2.5: - dependencies: - brace-expansion: 5.0.6 - - minimist@1.2.8: {} - - motion-dom@12.40.0: - dependencies: - motion-utils: 12.39.0 - - motion-utils@12.39.0: {} - - motion@12.40.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): - dependencies: - framer-motion: 12.40.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - tslib: 2.8.1 - optionalDependencies: - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) + '@jridgewell/sourcemap-codec': 1.5.5 + + mdn-data@2.27.1: + optional: true ms@2.1.3: {} @@ -7024,82 +3337,23 @@ snapshots: typescript: 6.0.3 transitivePeerDependencies: - '@types/node' + optional: true - mute-stream@3.0.0: {} + mute-stream@3.0.0: + optional: true nanoid@3.3.12: {} - negotiator@1.0.0: {} - - node-domexception@1.0.0: {} - - node-fetch@3.3.2: - dependencies: - data-uri-to-buffer: 4.0.1 - fetch-blob: 3.2.0 - formdata-polyfill: 4.0.10 - node-releases@2.0.45: {} - npm-run-path@4.0.1: - dependencies: - path-key: 3.1.1 - - npm-run-path@6.0.0: - dependencies: - path-key: 4.0.0 - unicorn-magic: 0.3.0 - nth-check@2.1.1: dependencies: boolbase: 1.0.0 - object-assign@4.1.1: {} - - object-inspect@1.13.4: {} - - object-treeify@1.1.33: {} - obug@2.1.1: {} - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - onetime@5.1.2: - dependencies: - mimic-fn: 2.1.0 - - onetime@7.0.0: - dependencies: - mimic-function: 5.0.1 - - open@11.0.0: - dependencies: - default-browser: 5.5.0 - define-lazy-prop: 3.0.0 - is-in-ssh: 1.0.0 - is-inside-container: 1.0.0 - powershell-utils: 0.1.0 - wsl-utils: 0.3.1 - - ora@8.2.0: - dependencies: - chalk: 5.6.2 - cli-cursor: 5.0.0 - cli-spinners: 2.9.2 - is-interactive: 2.0.0 - is-unicode-supported: 2.1.0 - log-symbols: 6.0.0 - stdin-discarder: 0.2.2 - string-width: 7.2.0 - strip-ansi: 7.2.0 - - outvariant@1.4.3: {} + outvariant@1.4.3: + optional: true oxc-parser@0.120.0(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0): dependencies: @@ -7129,19 +3383,6 @@ snapshots: - '@emnapi/core' - '@emnapi/runtime' - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - - parse-json@5.2.0: - dependencies: - '@babel/code-frame': 7.29.0 - error-ex: 1.3.4 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - - parse-ms@4.0.0: {} - parse5-htmlparser2-tree-adapter@7.1.0: dependencies: domhandler: 5.0.3 @@ -7158,223 +3399,50 @@ snapshots: parse5@8.0.1: dependencies: entities: 8.0.0 + optional: true - parseurl@1.3.3: {} - - path-browserify@1.0.1: {} - - path-key@3.1.1: {} - - path-key@4.0.0: {} - - path-to-regexp@6.3.0: {} - - path-to-regexp@8.4.2: {} + path-to-regexp@6.3.0: + optional: true pathe@2.0.3: {} picocolors@1.1.1: {} - picomatch@2.3.2: {} - picomatch@4.0.4: {} - pkce-challenge@5.0.1: {} - postcss-selector-parser@6.0.10: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-selector-parser@7.1.1: - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 - postcss@8.5.15: dependencies: nanoid: 3.3.12 picocolors: 1.1.1 source-map-js: 1.2.1 - powershell-utils@0.1.0: {} - prettier@3.8.3: {} - pretty-format@27.5.1: - dependencies: - ansi-regex: 5.0.1 - ansi-styles: 5.2.0 - react-is: 17.0.2 - - pretty-ms@9.3.0: - dependencies: - parse-ms: 4.0.0 - - prompts@2.4.2: - dependencies: - kleur: 3.0.3 - sisteransi: 1.0.5 - - proxy-addr@2.0.7: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - - punycode@2.3.1: {} - - qs@6.15.2: - dependencies: - side-channel: 1.1.0 - - queue-microtask@1.2.3: {} - - radix-ui@1.4.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6): - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-accessible-icon': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-accordion': 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-alert-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-aspect-ratio': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-avatar': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-checkbox': 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-context-menu': 2.2.16(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-form': 0.1.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-hover-card': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-label': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-menubar': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-one-time-password-field': 0.1.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-password-toggle-field': 0.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-popover': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-progress': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-radio-group': 1.3.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-select': 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slider': 1.3.6(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-switch': 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-toast': 1.2.15(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-toolbar': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.15)(react@19.2.6) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.15))(@types/react@19.2.15)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react: 19.2.6 - react-dom: 19.2.6(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - '@types/react-dom': 19.2.3(@types/react@19.2.15) - - range-parser@1.2.1: {} - - raw-body@3.0.2: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.1 - iconv-lite: 0.7.2 - unpipe: 1.0.0 - - react-day-picker@10.0.1(@types/react@19.2.15)(react@19.2.6): - dependencies: - '@date-fns/tz': 1.5.0 - date-fns: 4.4.0 - react: 19.2.6 - optionalDependencies: - '@types/react': 19.2.15 + punycode@2.3.1: + optional: true react-dom@19.2.6(react@19.2.6): dependencies: react: 19.2.6 scheduler: 0.27.0 - react-is@17.0.2: {} - - react-remove-scroll-bar@2.3.8(@types/react@19.2.15)(react@19.2.6): - dependencies: - react: 19.2.6 - react-style-singleton: 2.2.3(@types/react@19.2.15)(react@19.2.6) - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.15 - - react-remove-scroll@2.7.2(@types/react@19.2.15)(react@19.2.6): - dependencies: - react: 19.2.6 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.15)(react@19.2.6) - react-style-singleton: 2.2.3(@types/react@19.2.15)(react@19.2.6) - tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.15)(react@19.2.6) - use-sidecar: 1.1.3(@types/react@19.2.15)(react@19.2.6) - optionalDependencies: - '@types/react': 19.2.15 - - react-style-singleton@2.2.3(@types/react@19.2.15)(react@19.2.6): - dependencies: - get-nonce: 1.0.1 - react: 19.2.6 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.15 - - react-use-websocket@4.13.0: {} - react@19.2.6: {} readdirp@5.0.0: {} - recast@0.23.11: - dependencies: - ast-types: 0.16.1 - esprima: 4.0.1 - source-map: 0.6.1 - tiny-invariant: 1.3.3 - tslib: 2.8.1 - - remove-accents@0.5.0: {} - - require-directory@2.1.1: {} - - require-from-string@2.0.2: {} - - reselect@5.2.0: {} - - resolve-from@4.0.0: {} - - restore-cursor@5.1.0: - dependencies: - onetime: 7.0.0 - signal-exit: 4.1.0 + require-directory@2.1.1: + optional: true - rettime@0.11.11: {} + require-from-string@2.0.2: + optional: true - reusify@1.1.0: {} + rettime@0.11.11: + optional: true rolldown@1.0.2: dependencies: @@ -7399,224 +3467,66 @@ snapshots: rou3@0.8.1: {} - router@2.2.0: - dependencies: - debug: 4.4.3 - depd: 2.0.0 - is-promise: 4.0.0 - parseurl: 1.3.3 - path-to-regexp: 8.4.2 - transitivePeerDependencies: - - supports-color - - run-applescript@7.1.0: {} - - run-parallel@1.2.0: - dependencies: - queue-microtask: 1.2.3 - safer-buffer@2.1.2: {} saxes@6.0.0: dependencies: xmlchars: 2.2.0 + optional: true scheduler@0.27.0: {} - scichart-financial-tools@5.2.28(scichart@5.2.28): - dependencies: - scichart: 5.2.28 - - scichart-react@1.0.0(react@19.2.6)(scichart@5.2.28): - dependencies: - react: 19.2.6 - scichart: 5.2.28 - - scichart@5.2.28: {} - semver@6.3.1: {} - send@1.2.1: - dependencies: - debug: 4.4.3 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 2.0.0 - http-errors: 2.0.1 - mime-types: 3.0.2 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - seroval-plugins@1.5.4(seroval@1.5.4): dependencies: seroval: 1.5.4 seroval@1.5.4: {} - serve-static@2.2.1: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 1.2.1 - transitivePeerDependencies: - - supports-color - - set-cookie-parser@3.1.0: {} - - setprototypeof@1.2.0: {} - - shadcn@4.10.0(@types/node@22.19.19)(typescript@6.0.3): - dependencies: - '@babel/core': 7.29.0 - '@babel/parser': 7.29.3 - '@babel/plugin-transform-typescript': 7.29.7(@babel/core@7.29.0) - '@babel/preset-typescript': 7.29.7(@babel/core@7.29.0) - '@dotenvx/dotenvx': 1.71.0 - '@modelcontextprotocol/sdk': 1.29.0(zod@3.25.76) - '@types/validate-npm-package-name': 4.0.2 - browserslist: 4.28.2 - commander: 14.0.3 - cosmiconfig: 9.0.1(typescript@6.0.3) - dedent: 1.7.2 - deepmerge: 4.3.1 - diff: 8.0.4 - execa: 9.6.1 - fast-glob: 3.3.3 - fs-extra: 11.3.5 - fuzzysort: 3.1.0 - https-proxy-agent: 7.0.6 - kleur: 4.1.5 - msw: 2.14.6(@types/node@22.19.19)(typescript@6.0.3) - node-fetch: 3.3.2 - open: 11.0.0 - ora: 8.2.0 - postcss: 8.5.15 - postcss-selector-parser: 7.1.1 - prompts: 2.4.2 - recast: 0.23.11 - stringify-object: 5.0.0 - tailwind-merge: 3.6.0 - ts-morph: 26.0.0 - tsconfig-paths: 4.2.0 - validate-npm-package-name: 7.0.2 - zod: 3.25.76 - zod-to-json-schema: 3.25.2(zod@3.25.76) - transitivePeerDependencies: - - '@cfworker/json-schema' - - '@types/node' - - babel-plugin-macros - - supports-color - - typescript - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} + set-cookie-parser@3.1.0: + optional: true shell-quote@1.8.3: {} - side-channel-list@1.0.1: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.1 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - siginfo@2.0.0: {} - signal-exit@3.0.7: {} - - signal-exit@4.1.0: {} - - sisteransi@1.0.5: {} - - solid-js@1.9.13: - dependencies: - csstype: 3.2.3 - seroval: 1.5.4 - seroval-plugins: 1.5.4(seroval@1.5.4) + signal-exit@4.1.0: + optional: true source-map-js@1.2.1: {} - source-map@0.6.1: {} - source-map@0.7.6: {} srvx@0.11.15: {} stackback@0.0.2: {} - statuses@2.0.2: {} + statuses@2.0.2: + optional: true std-env@4.1.0: {} - stdin-discarder@0.2.2: {} - - strict-event-emitter@0.5.1: {} + strict-event-emitter@0.5.1: + optional: true string-width@4.2.3: dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - - string-width@7.2.0: - dependencies: - emoji-regex: 10.6.0 - get-east-asian-width: 1.6.0 - strip-ansi: 7.2.0 - - stringify-object@5.0.0: - dependencies: - get-own-enumerable-keys: 1.0.0 - is-obj: 3.0.0 - is-regexp: 3.1.0 + optional: true strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 + optional: true - strip-ansi@7.2.0: - dependencies: - ansi-regex: 6.2.2 - - strip-bom@3.0.0: {} - - strip-final-newline@2.0.0: {} - - strip-final-newline@4.0.0: {} - - symbol-tree@3.2.4: {} + symbol-tree@3.2.4: + optional: true - tagged-tag@1.0.0: {} + tagged-tag@1.0.0: + optional: true tailwind-merge@3.6.0: {} @@ -7624,8 +3534,6 @@ snapshots: tapable@2.3.3: {} - tiny-invariant@1.3.3: {} - tinybench@2.9.0: {} tinyexec@1.1.2: {} @@ -7637,50 +3545,33 @@ snapshots: tinyrainbow@3.1.0: {} - tldts-core@7.0.30: {} + tldts-core@7.0.30: + optional: true tldts@7.0.30: dependencies: tldts-core: 7.0.30 - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - toidentifier@1.0.1: {} + optional: true tough-cookie@6.0.1: dependencies: tldts: 7.0.30 + optional: true tr46@6.0.0: dependencies: punycode: 2.3.1 + optional: true - ts-morph@26.0.0: - dependencies: - '@ts-morph/common': 0.27.0 - code-block-writer: 13.0.3 - - tsconfig-paths@4.2.0: - dependencies: - json5: 2.2.3 - minimist: 1.2.8 - strip-bom: 3.0.0 - - tslib@2.8.1: {} + tslib@2.8.1: + optional: true tw-animate-css@1.4.0: {} type-fest@5.7.0: dependencies: tagged-tag: 1.0.0 - - type-is@2.1.0: - dependencies: - content-type: 2.0.0 - media-typer: 1.1.0 - mime-types: 3.0.2 + optional: true typescript@6.0.3: {} @@ -7690,19 +3581,14 @@ snapshots: undici@7.25.0: {} - unicorn-magic@0.3.0: {} - - universalify@2.0.1: {} - - unpipe@1.0.0: {} - unplugin@3.0.0: dependencies: '@jridgewell/remapping': 2.3.5 picomatch: 4.0.4 webpack-virtual-modules: 0.6.2 - until-async@3.0.2: {} + until-async@3.0.2: + optional: true update-browserslist-db@1.2.3(browserslist@4.28.2): dependencies: @@ -7710,31 +3596,12 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - use-callback-ref@1.3.3(@types/react@19.2.15)(react@19.2.6): - dependencies: - react: 19.2.6 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.15 - - use-sidecar@1.1.3(@types/react@19.2.15)(react@19.2.6): - dependencies: - detect-node-es: 1.1.0 - react: 19.2.6 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.15 - use-sync-external-store@1.6.0(react@19.2.6): dependencies: react: 19.2.6 util-deprecate@1.0.2: {} - validate-npm-package-name@7.0.2: {} - - vary@1.1.2: {} - vite@8.0.14(@types/node@22.19.19)(esbuild@0.28.1)(jiti@2.7.0): dependencies: lightningcss: 1.32.0 @@ -7783,10 +3650,10 @@ snapshots: w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 + optional: true - web-streams-polyfill@3.3.3: {} - - webidl-conversions@8.0.1: {} + webidl-conversions@8.0.1: + optional: true webpack-virtual-modules@0.6.2: {} @@ -7796,7 +3663,8 @@ snapshots: whatwg-mimetype@4.0.0: {} - whatwg-mimetype@5.0.0: {} + whatwg-mimetype@5.0.0: + optional: true whatwg-url@16.0.1(@noble/hashes@1.8.0): dependencies: @@ -7805,14 +3673,7 @@ snapshots: webidl-conversions: 8.0.1 transitivePeerDependencies: - '@noble/hashes' - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - which@4.0.0: - dependencies: - isexe: 3.1.5 + optional: true why-is-node-running@2.3.0: dependencies: @@ -7824,17 +3685,12 @@ snapshots: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - - wrappy@1.0.2: {} + optional: true ws@8.20.1: {} - wsl-utils@0.3.1: - dependencies: - is-wsl: 3.1.1 - powershell-utils: 0.1.0 - - xml-name-validator@5.0.0: {} + xml-name-validator@5.0.0: + optional: true xmlbuilder2@4.0.3: dependencies: @@ -7843,13 +3699,16 @@ snapshots: '@oozcitak/util': 10.0.0 js-yaml: 4.1.1 - xmlchars@2.2.0: {} + xmlchars@2.2.0: + optional: true - y18n@5.0.8: {} + y18n@5.0.8: + optional: true yallist@3.1.1: {} - yargs-parser@21.1.1: {} + yargs-parser@21.1.1: + optional: true yargs@17.7.2: dependencies: @@ -7860,17 +3719,6 @@ snapshots: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 - - yocto-spinner@1.2.0: - dependencies: - yoctocolors: 2.1.2 - - yoctocolors@2.1.2: {} - - zod-to-json-schema@3.25.2(zod@3.25.76): - dependencies: - zod: 3.25.76 - - zod@3.25.76: {} + optional: true zod@4.4.3: {} diff --git a/frontend/public/scichart/scichart2d-nosimd.wasm b/frontend/public/scichart/scichart2d-nosimd.wasm deleted file mode 100644 index 9c087a45..00000000 Binary files a/frontend/public/scichart/scichart2d-nosimd.wasm and /dev/null differ diff --git a/frontend/public/scichart/scichart2d.js b/frontend/public/scichart/scichart2d.js deleted file mode 100644 index 9355e77a..00000000 --- a/frontend/public/scichart/scichart2d.js +++ /dev/null @@ -1,22 +0,0 @@ - -var Module = (() => { - var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined; - - return ( -function(moduleArg = {}) { - var moduleRtn; - -var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;var readyPromise=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var ENVIRONMENT_IS_WEB=true;var ENVIRONMENT_IS_WORKER=false;var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptName){scriptDirectory=_scriptName}if(scriptDirectory.startsWith("blob:")){scriptDirectory=""}else{scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}{readAsync=async url=>{var response=await fetch(url,{credentials:"same-origin"});if(response.ok){return response.arrayBuffer()}throw new Error(response.status+" : "+response.url)}}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];var wasmBinary=Module["wasmBinary"];var wasmMemory;var ABORT=false;var EXITSTATUS;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b)}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.initialized)FS.init();FS.ignorePermissions=false;TTY.init();callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;Module["monitorRunDependencies"]?.(runDependencies)}function removeRunDependency(id){runDependencies--;Module["monitorRunDependencies"]?.(runDependencies);if(runDependencies==0){if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";var isDataURI=filename=>filename.startsWith(dataURIPrefix);function findWasmBinary(){var f="scichart2d.wasm";if(!isDataURI(f)){return locateFile(f)}return f}var wasmBinaryFile;function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}async function getWasmBinary(binaryFile){if(!wasmBinary){try{var response=await readAsync(binaryFile);return new Uint8Array(response)}catch{}}return getBinarySync(binaryFile)}async function instantiateArrayBuffer(binaryFile,imports){try{var binary=await getWasmBinary(binaryFile);var instance=await WebAssembly.instantiate(binary,imports);return instance}catch(reason){err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)}}async function instantiateAsync(binary,binaryFile,imports){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&typeof fetch=="function"){try{var response=fetch(binaryFile,{credentials:"same-origin"});var instantiationResult=await WebAssembly.instantiateStreaming(response,imports);return instantiationResult}catch(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation")}}return instantiateArrayBuffer(binaryFile,imports)}function getWasmImports(){return{a:wasmImports}}async function createWasm(){function receiveInstance(instance,module){wasmExports=instance.exports;wasmExports=applySignatureConversions(wasmExports);wasmMemory=wasmExports["lb"];updateMemoryViews();wasmTable=wasmExports["qb"];addOnInit(wasmExports["mb"]);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}var info=getWasmImports();if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e)}}wasmBinaryFile??=findWasmBinary();try{var result=await instantiateAsync(wasmBinary,wasmBinaryFile,info);receiveInstantiationResult(result);return result}catch(e){readyPromiseReject(e);return}}var tempDouble;var tempI64;var ASM_CONSTS={459018:()=>Module.getRandomValue(),459034:()=>Module.getRandomValue(),459054:()=>{if(Module.getRandomValue===undefined){try{var window_="object"===typeof window?window:self;var crypto_=typeof window_.crypto!=="undefined"?window_.crypto:window_.msCrypto;var randomValuesStandard=function(){var buf=new Uint32Array(1);crypto_.getRandomValues(buf);return buf[0]>>>0};randomValuesStandard();Module.getRandomValue=randomValuesStandard}catch(e){try{var max=Math.pow(2,32);var randomValueNodeJS=function(){var r=Math.floor(Math.random()*Math.floor(max));return r>>>0};randomValueNodeJS();Module.getRandomValue=randomValueNodeJS}catch(e){throw"No secure random number generator found"}}}},459070:()=>{if(Module.getRandomValue===undefined){try{var window_="object"===typeof window?window:self;var crypto_=typeof window_.crypto!=="undefined"?window_.crypto:window_.msCrypto;var randomValuesStandard=function(){var buf=new Uint32Array(1);crypto_.getRandomValues(buf);return buf[0]>>>0};randomValuesStandard();Module.getRandomValue=randomValuesStandard}catch(e){try{var max=Math.pow(2,32);var randomValueNodeJS=function(){var r=Math.floor(Math.random()*Math.floor(max));return r>>>0};randomValueNodeJS();Module.getRandomValue=randomValueNodeJS}catch(e){throw"No secure random number generator found"}}}}};function get_host(){var host="";if(typeof window!=="undefined"){host=window.location.hostname}else if(typeof process!=="undefined"){host="node"}var lengthBytes=lengthBytesUTF8(host)+1;var stringOnWasmHeap=_malloc(lengthBytes);stringToUTF8(host,stringOnWasmHeap,lengthBytes);return stringOnWasmHeap}class ExitStatus{name="ExitStatus";constructor(status){this.message=`Program terminated with exit(${status})`;this.status=status}}var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var noExitRuntime=Module["noExitRuntime"]||true;var stackRestore=val=>__emscripten_stack_restore(val);var stackSave=()=>_emscripten_stack_get_current();class ExceptionInfo{constructor(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24}set_type(type){HEAPU32[this.ptr+4>>>2>>>0]=type}get_type(){return HEAPU32[this.ptr+4>>>2>>>0]}set_destructor(destructor){HEAPU32[this.ptr+8>>>2>>>0]=destructor}get_destructor(){return HEAPU32[this.ptr+8>>>2>>>0]}set_caught(caught){caught=caught?1:0;HEAP8[this.ptr+12>>>0]=caught}get_caught(){return HEAP8[this.ptr+12>>>0]!=0}set_rethrown(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13>>>0]=rethrown}get_rethrown(){return HEAP8[this.ptr+13>>>0]!=0}init(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)}set_adjusted_ptr(adjustedPtr){HEAPU32[this.ptr+16>>>2>>>0]=adjustedPtr}get_adjusted_ptr(){return HEAPU32[this.ptr+16>>>2>>>0]}}var exceptionLast=0;var uncaughtExceptionCount=0;var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;function ___cxa_throw(ptr,type,destructor){ptr>>>=0;type>>>=0;destructor>>>=0;var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw exceptionLast}var syscallGetVarargI=()=>{var ret=HEAP32[+SYSCALLS.varargs>>>2>>>0];SYSCALLS.varargs+=4;return ret};var syscallGetVarargP=syscallGetVarargI;var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:path=>{if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:(...paths)=>PATH.normalize(paths.join("/")),join2:(l,r)=>PATH.normalize(l+"/"+r)};var initRandomFill=()=>{if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>crypto.getRandomValues(view)}else abort("initRandomDevice")};var randomFill=view=>(randomFill=initRandomFill())(view);var PATH_FS={resolve:(...args)=>{var resolvedPath="",resolvedAbsolute=false;for(var i=args.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?args[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{idx>>>=0;var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var FS_stdin_getChar_buffer=[];var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{outIdx>>>=0;if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++>>>0]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++>>>0]=192|u>>6;heap[outIdx++>>>0]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++>>>0]=224|u>>12;heap[outIdx++>>>0]=128|u>>6&63;heap[outIdx++>>>0]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++>>>0]=240|u>>18;heap[outIdx++>>>0]=128|u>>12&63;heap[outIdx++>>>0]=128|u>>6&63;heap[outIdx++>>>0]=128|u&63}}heap[outIdx>>>0]=0;return outIdx-startIdx};function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else{}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true)}return FS_stdin_getChar_buffer.shift()};var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close(stream){stream.tty.ops.fsync(stream.tty)},fsync(stream){stream.tty.ops.fsync(stream.tty)},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output));tty.output=[]}},ioctl_tcgets(tty){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return[24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output));tty.output=[]}}}};var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var mmapAlloc=size=>{abort()};var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16895,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}MEMFS.ops_table||={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}};var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.atime=node.mtime=node.ctime=Date.now();if(parent){parent.contents[name]=node;parent.atime=parent.mtime=parent.ctime=node.atime}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.atime);attr.mtime=new Date(node.mtime);attr.ctime=new Date(node.ctime);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){for(const key of["mode","atime","mtime","ctime"]){if(attr[key]){node[key]=attr[key]}}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup(parent,name){throw MEMFS.doesNotExistError},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){if(FS.isDir(old_node.mode)){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}FS.hashRemoveNode(new_node)}delete old_node.parent.contents[old_node.name];new_dir.contents[new_name]=old_node;old_node.name=new_name;new_dir.ctime=new_dir.mtime=old_node.parent.ctime=old_node.parent.mtime=Date.now()},unlink(parent,name){delete parent.contents[name];parent.ctime=parent.mtime=Date.now()},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.ctime=parent.mtime=Date.now()},readdir(node){return[".","..",...Object.keys(node.contents)]},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length>>0)}}return{ptr,allocated}},msync(stream,buffer,offset,length,mmapFlags){MEMFS.stream_ops.write(stream,buffer,0,length,offset,false);return 0}}};var asyncLoad=async url=>{var arrayBuffer=await readAsync(url);return new Uint8Array(arrayBuffer)};var FS_createDataFile=(parent,name,fileData,canRead,canWrite,canOwn)=>{FS.createDataFile(parent,name,fileData,canRead,canWrite,canOwn)};var preloadPlugins=Module["preloadPlugins"]||[];var FS_handledByPreloadPlugin=(byteArray,fullname,finish,onerror)=>{if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}});return handled};var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);function processData(byteArray){function finish(byteArray){preFinish?.();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}onload?.();removeRunDependency(dep)}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{onerror?.();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url).then(processData,onerror)}else{processData(url)}};var FS_modeStringToFlags=str=>{var flagModes={r:0,"r+":2,w:512|64|1,"w+":512|64|2,a:1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:class{name="ErrnoError";constructor(errno){this.errno=errno}},filesystems:null,syncFSRequests:0,readFiles:{},FSStream:class{shared={};get object(){return this.node}set object(val){this.node=val}get isRead(){return(this.flags&2097155)!==1}get isWrite(){return(this.flags&2097155)!==0}get isAppend(){return this.flags&1024}get flags(){return this.shared.flags}set flags(val){this.shared.flags=val}get position(){return this.shared.position}set position(val){this.shared.position=val}},FSNode:class{node_ops={};stream_ops={};readMode=292|73;writeMode=146;mounted=null;constructor(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.rdev=rdev;this.atime=this.mtime=this.ctime=Date.now()}get read(){return(this.mode&this.readMode)===this.readMode}set read(val){val?this.mode|=this.readMode:this.mode&=~this.readMode}get write(){return(this.mode&this.writeMode)===this.writeMode}set write(val){val?this.mode|=this.writeMode:this.mode&=~this.writeMode}get isFolder(){return FS.isDir(this.mode)}get isDevice(){return FS.isChrdev(this.mode)}},lookupPath(path,opts={}){if(!path)return{path:"",node:null};opts.follow_mount??=true;if(!PATH.isAbs(path)){path=FS.cwd()+"/"+path}linkloop:for(var nlinks=0;nlinks<40;nlinks++){var parts=path.split("/").filter(p=>!!p&&p!==".");var current=FS.root;var current_path="/";for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node)},isRoot(node){return node===node.parent},isMountpoint(node){return!!node.mounted},isFile(mode){return(mode&61440)===32768},isDir(mode){return(mode&61440)===16384},isLink(mode){return(mode&61440)===40960},isChrdev(mode){return(mode&61440)===8192},isBlkdev(mode){return(mode&61440)===24576},isFIFO(mode){return(mode&61440)===4096},isSocket(mode){return(mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){if(!FS.isDir(dir.mode))return 54;var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){if(!FS.isDir(dir.mode)){return 54}try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null},dupStream(origStream,fd=-1){var stream=FS.createStream(origStream,fd);stream.stream_ops?.dup?.(stream);return stream},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;stream.stream_ops.open?.(stream)},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push(...m.mounts)}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type,opts,mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},statfs(path){var rtn={bsize:4096,frsize:4096,blocks:1e6,bfree:5e5,bavail:5e5,files:FS.nextInode,ffree:FS.nextInode-1,fsid:42,flags:2,namelen:255};var parent=FS.lookupPath(path,{follow:true}).node;if(parent?.node_ops.statfs){Object.assign(rtn,parent.node_ops.statfs(parent.mount.opts.root))}return rtn},create(path,mode=438){mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode=511){mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var i=0;iFS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length,llseek:()=>0});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16895,73);node.stream_ops={llseek:MEMFS.stream_ops.llseek};node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path},id:fd+1};ret.parent=ret;return ret},readdir(){return Array.from(FS.streams.entries()).filter(([k,v])=>v).map(([k,v])=>k.toString())}};return node}},{},"/proc/self/fd")},createStandardStreams(input,output,error){if(input){FS.createDevice("/dev","stdin",input)}else{FS.symlink("/dev/tty","/dev/stdin")}if(output){FS.createDevice("/dev","stdout",null,output)}else{FS.symlink("/dev/tty","/dev/stdout")}if(error){FS.createDevice("/dev","stderr",null,error)}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},staticInit(){FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={MEMFS}},init(input,output,error){FS.initialized=true;input??=Module["stdin"];output??=Module["stdout"];error??=Module["stderr"];FS.createStandardStreams(input,output,error)},quit(){FS.initialized=false;for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]}setDataGetter(getter){this.getter=getter}cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true}get length(){if(!this.lengthKnown){this.cacheLength()}return this._length}get chunkSize(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=(...args)=>{FS.forceLoadFile(node);return fn(...args)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr,allocated:true}};node.stream_ops=stream_ops;return node}};var UTF8ToString=(ptr,maxBytesToRead)=>{ptr>>>=0;return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""};var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return dir+"/"+path},doStat(func,path,buf){var stat=func(path);HEAP32[buf>>>2>>>0]=stat.dev;HEAP32[buf+4>>>2>>>0]=stat.mode;HEAPU32[buf+8>>>2>>>0]=stat.nlink;HEAP32[buf+12>>>2>>>0]=stat.uid;HEAP32[buf+16>>>2>>>0]=stat.gid;HEAP32[buf+20>>>2>>>0]=stat.rdev;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+24>>>2>>>0]=tempI64[0],HEAP32[buf+28>>>2>>>0]=tempI64[1];HEAP32[buf+32>>>2>>>0]=4096;HEAP32[buf+36>>>2>>>0]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();tempI64=[Math.floor(atime/1e3)>>>0,(tempDouble=Math.floor(atime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>>2>>>0]=tempI64[0],HEAP32[buf+44>>>2>>>0]=tempI64[1];HEAPU32[buf+48>>>2>>>0]=atime%1e3*1e3*1e3;tempI64=[Math.floor(mtime/1e3)>>>0,(tempDouble=Math.floor(mtime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+56>>>2>>>0]=tempI64[0],HEAP32[buf+60>>>2>>>0]=tempI64[1];HEAPU32[buf+64>>>2>>>0]=mtime%1e3*1e3*1e3;tempI64=[Math.floor(ctime/1e3)>>>0,(tempDouble=Math.floor(ctime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+72>>>2>>>0]=tempI64[0],HEAP32[buf+76>>>2>>>0]=tempI64[1];HEAPU32[buf+80>>>2>>>0]=ctime%1e3*1e3*1e3;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+88>>>2>>>0]=tempI64[0],HEAP32[buf+92>>>2>>>0]=tempI64[1];return 0},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream},varargs:undefined,getStr(ptr){var ret=UTF8ToString(ptr);return ret}};function ___syscall_fcntl64(fd,cmd,varargs){varargs>>>=0;SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=syscallGetVarargI();if(arg<0){return-28}while(FS.streams[arg]){arg++}var newStream;newStream=FS.dupStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=syscallGetVarargI();stream.flags|=arg;return 0}case 12:{var arg=syscallGetVarargP();var offset=0;HEAP16[arg+offset>>>1>>>0]=2;return 0}case 13:case 14:return 0}return-28}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_ioctl(fd,op,varargs){varargs>>>=0;SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:{if(!stream.tty)return-59;return 0}case 21505:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcgets){var termios=stream.tty.ops.ioctl_tcgets(stream);var argp=syscallGetVarargP();HEAP32[argp>>>2>>>0]=termios.c_iflag||0;HEAP32[argp+4>>>2>>>0]=termios.c_oflag||0;HEAP32[argp+8>>>2>>>0]=termios.c_cflag||0;HEAP32[argp+12>>>2>>>0]=termios.c_lflag||0;for(var i=0;i<32;i++){HEAP8[argp+i+17>>>0]=termios.c_cc[i]||0}return 0}return 0}case 21510:case 21511:case 21512:{if(!stream.tty)return-59;return 0}case 21506:case 21507:case 21508:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcsets){var argp=syscallGetVarargP();var c_iflag=HEAP32[argp>>>2>>>0];var c_oflag=HEAP32[argp+4>>>2>>>0];var c_cflag=HEAP32[argp+8>>>2>>>0];var c_lflag=HEAP32[argp+12>>>2>>>0];var c_cc=[];for(var i=0;i<32;i++){c_cc.push(HEAP8[argp+i+17>>>0])}return stream.tty.ops.ioctl_tcsets(stream.tty,op,{c_iflag,c_oflag,c_cflag,c_lflag,c_cc})}return 0}case 21519:{if(!stream.tty)return-59;var argp=syscallGetVarargP();HEAP32[argp>>>2>>>0]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=syscallGetVarargP();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tiocgwinsz){var winsize=stream.tty.ops.ioctl_tiocgwinsz(stream.tty);var argp=syscallGetVarargP();HEAP16[argp>>>1>>>0]=winsize[0];HEAP16[argp+2>>>1>>>0]=winsize[1]}return 0}case 21524:{if(!stream.tty)return-59;return 0}case 21515:{if(!stream.tty)return-59;return 0}default:return-28}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_openat(dirfd,path,flags,varargs){path>>>=0;varargs>>>=0;SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?syscallGetVarargI():0;return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_stat64(path,buf){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var __abort_js=()=>abort("");var createNamedFunction=(name,body)=>Object.defineProperty(body,"name",{value:name});var emval_freelist=[];var emval_handles=[];var BindingError;var throwBindingError=message=>{throw new BindingError(message)};var count_emval_handles=()=>emval_handles.length/2-5-emval_freelist.length;var init_emval=()=>{emval_handles.push(0,1,undefined,1,null,1,true,1,false,1);Module["count_emval_handles"]=count_emval_handles};var Emval={toValue:handle=>{if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handles[handle]},toHandle:value=>{switch(value){case undefined:return 2;case null:return 4;case true:return 6;case false:return 8;default:{const handle=emval_freelist.pop()||emval_handles.length;emval_handles[handle]=value;emval_handles[handle+1]=1;return handle}}}};var extendError=(baseErrorType,errorName)=>{var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return`${this.name}: ${this.message}`}};return errorClass};var PureVirtualError;var embind_init_charCodes=()=>{var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes};var embind_charCodes;var readLatin1String=ptr=>{var ret="";var c=ptr;while(HEAPU8[c>>>0]){ret+=embind_charCodes[HEAPU8[c++>>>0]]}return ret};var registeredInstances={};var getBasestPointer=(class_,ptr)=>{if(ptr===undefined){throwBindingError("ptr should not be undefined")}while(class_.baseClass){ptr=class_.upcast(ptr);class_=class_.baseClass}return ptr};var registerInheritedInstance=(class_,ptr,instance)=>{ptr=getBasestPointer(class_,ptr);if(registeredInstances.hasOwnProperty(ptr)){throwBindingError(`Tried to register registered instance: ${ptr}`)}else{registeredInstances[ptr]=instance}};var registeredTypes={};var getTypeName=type=>{var ptr=___getTypeName(type);var rv=readLatin1String(ptr);_free(ptr);return rv};var requireRegisteredType=(rawType,humanName)=>{var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(`${humanName} has unknown type ${getTypeName(rawType)}`)}return impl};var unregisterInheritedInstance=(class_,ptr)=>{ptr=getBasestPointer(class_,ptr);if(registeredInstances.hasOwnProperty(ptr)){delete registeredInstances[ptr]}else{throwBindingError(`Tried to unregister unregistered instance: ${ptr}`)}};var detachFinalizer=handle=>{};var finalizationRegistry=false;var runDestructor=$$=>{if($$.smartPtr){$$.smartPtrType.rawDestructor($$.smartPtr)}else{$$.ptrType.registeredClass.rawDestructor($$.ptr)}};var releaseClassHandle=$$=>{$$.count.value-=1;var toDelete=0===$$.count.value;if(toDelete){runDestructor($$)}};var downcastPointer=(ptr,ptrClass,desiredClass)=>{if(ptrClass===desiredClass){return ptr}if(undefined===desiredClass.baseClass){return null}var rv=downcastPointer(ptr,ptrClass,desiredClass.baseClass);if(rv===null){return null}return desiredClass.downcast(rv)};var registeredPointers={};var getInheritedInstance=(class_,ptr)=>{ptr=getBasestPointer(class_,ptr);return registeredInstances[ptr]};var InternalError;var throwInternalError=message=>{throw new InternalError(message)};var makeClassHandle=(prototype,record)=>{if(!record.ptrType||!record.ptr){throwInternalError("makeClassHandle requires ptr and ptrType")}var hasSmartPtrType=!!record.smartPtrType;var hasSmartPtr=!!record.smartPtr;if(hasSmartPtrType!==hasSmartPtr){throwInternalError("Both smartPtrType and smartPtr must be specified")}record.count={value:1};return attachFinalizer(Object.create(prototype,{$$:{value:record,writable:true}}))};function RegisteredPointer_fromWireType(ptr){var rawPointer=this.getPointee(ptr);if(!rawPointer){this.destructor(ptr);return null}var registeredInstance=getInheritedInstance(this.registeredClass,rawPointer);if(undefined!==registeredInstance){if(0===registeredInstance.$$.count.value){registeredInstance.$$.ptr=rawPointer;registeredInstance.$$.smartPtr=ptr;return registeredInstance["clone"]()}else{var rv=registeredInstance["clone"]();this.destructor(ptr);return rv}}function makeDefaultHandle(){if(this.isSmartPointer){return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this.pointeeType,ptr:rawPointer,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this,ptr})}}var actualType=this.registeredClass.getActualType(rawPointer);var registeredPointerRecord=registeredPointers[actualType];if(!registeredPointerRecord){return makeDefaultHandle.call(this)}var toType;if(this.isConst){toType=registeredPointerRecord.constPointerType}else{toType=registeredPointerRecord.pointerType}var dp=downcastPointer(rawPointer,this.registeredClass,toType.registeredClass);if(dp===null){return makeDefaultHandle.call(this)}if(this.isSmartPointer){return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp})}}var attachFinalizer=handle=>{if("undefined"===typeof FinalizationRegistry){attachFinalizer=handle=>handle;return handle}finalizationRegistry=new FinalizationRegistry(info=>{releaseClassHandle(info.$$)});attachFinalizer=handle=>{var $$=handle.$$;var hasSmartPtr=!!$$.smartPtr;if(hasSmartPtr){var info={$$};finalizationRegistry.register(handle,info,handle)}return handle};detachFinalizer=handle=>finalizationRegistry.unregister(handle);return attachFinalizer(handle)};function __embind_create_inheriting_constructor(constructorName,wrapperType,properties){constructorName>>>=0;wrapperType>>>=0;properties>>>=0;constructorName=readLatin1String(constructorName);wrapperType=requireRegisteredType(wrapperType,"wrapper");properties=Emval.toValue(properties);var registeredClass=wrapperType.registeredClass;var wrapperPrototype=registeredClass.instancePrototype;var baseClass=registeredClass.baseClass;var baseClassPrototype=baseClass.instancePrototype;var baseConstructor=registeredClass.baseClass.constructor;var ctor=createNamedFunction(constructorName,function(...args){registeredClass.baseClass.pureVirtualFunctions.forEach(function(name){if(this[name]===baseClassPrototype[name]){throw new PureVirtualError(`Pure virtual function ${name} must be implemented in JavaScript`)}}.bind(this));Object.defineProperty(this,"__parent",{value:wrapperPrototype});this["__construct"](...args)});wrapperPrototype["__construct"]=function __construct(...args){if(this===wrapperPrototype){throwBindingError("Pass correct 'this' to __construct")}var inner=baseConstructor["implement"](this,...args);detachFinalizer(inner);var $$=inner.$$;inner["notifyOnDestruction"]();$$.preservePointerOnDelete=true;Object.defineProperties(this,{$$:{value:$$}});attachFinalizer(this);registerInheritedInstance(registeredClass,$$.ptr,this)};wrapperPrototype["__destruct"]=function __destruct(){if(this===wrapperPrototype){throwBindingError("Pass correct 'this' to __destruct")}detachFinalizer(this);unregisterInheritedInstance(registeredClass,this.$$.ptr)};ctor.prototype=Object.create(wrapperPrototype);Object.assign(ctor.prototype,properties);return Emval.toHandle(ctor)}function __embind_register_bigint(primitiveType,name,size,minRange,maxRange){primitiveType>>>=0;name>>>=0;size>>>=0}var awaitingDependencies={};var typeDependencies={};var whenDependentTypesAreResolved=(myTypes,dependentTypes,getTypeConverters)=>{myTypes.forEach(type=>typeDependencies[type]=dependentTypes);function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i{if(registeredTypes.hasOwnProperty(dt)){typeConverters[i]=registeredTypes[dt]}else{unregisteredTypes.push(dt);if(!awaitingDependencies.hasOwnProperty(dt)){awaitingDependencies[dt]=[]}awaitingDependencies[dt].push(()=>{typeConverters[i]=registeredTypes[dt];++registered;if(registered===unregisteredTypes.length){onComplete(typeConverters)}})}});if(0===unregisteredTypes.length){onComplete(typeConverters)}};function sharedRegisterType(rawType,registeredInstance,options={}){var name=registeredInstance.name;if(!rawType){throwBindingError(`type "${name}" must have a positive integer typeid pointer`)}if(registeredTypes.hasOwnProperty(rawType)){if(options.ignoreDuplicateRegistrations){return}else{throwBindingError(`Cannot register type '${name}' twice`)}}registeredTypes[rawType]=registeredInstance;delete typeDependencies[rawType];if(awaitingDependencies.hasOwnProperty(rawType)){var callbacks=awaitingDependencies[rawType];delete awaitingDependencies[rawType];callbacks.forEach(cb=>cb())}}function registerType(rawType,registeredInstance,options={}){return sharedRegisterType(rawType,registeredInstance,options)}var GenericWireTypeSize=8;function __embind_register_bool(rawType,name,trueValue,falseValue){rawType>>>=0;name>>>=0;name=readLatin1String(name);registerType(rawType,{name,fromWireType:function(wt){return!!wt},toWireType:function(destructors,o){return o?trueValue:falseValue},argPackAdvance:GenericWireTypeSize,readValueFromPointer:function(pointer){return this["fromWireType"](HEAPU8[pointer>>>0])},destructorFunction:null})}var shallowCopyInternalPointer=o=>({count:o.count,deleteScheduled:o.deleteScheduled,preservePointerOnDelete:o.preservePointerOnDelete,ptr:o.ptr,ptrType:o.ptrType,smartPtr:o.smartPtr,smartPtrType:o.smartPtrType});var throwInstanceAlreadyDeleted=obj=>{function getInstanceTypeName(handle){return handle.$$.ptrType.registeredClass.name}throwBindingError(getInstanceTypeName(obj)+" instance already deleted")};var deletionQueue=[];var flushPendingDeletes=()=>{while(deletionQueue.length){var obj=deletionQueue.pop();obj.$$.deleteScheduled=false;obj["delete"]()}};var delayFunction;var init_ClassHandle=()=>{Object.assign(ClassHandle.prototype,{isAliasOf(other){if(!(this instanceof ClassHandle)){return false}if(!(other instanceof ClassHandle)){return false}var leftClass=this.$$.ptrType.registeredClass;var left=this.$$.ptr;other.$$=other.$$;var rightClass=other.$$.ptrType.registeredClass;var right=other.$$.ptr;while(leftClass.baseClass){left=leftClass.upcast(left);leftClass=leftClass.baseClass}while(rightClass.baseClass){right=rightClass.upcast(right);rightClass=rightClass.baseClass}return leftClass===rightClass&&left===right},clone(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.preservePointerOnDelete){this.$$.count.value+=1;return this}else{var clone=attachFinalizer(Object.create(Object.getPrototypeOf(this),{$$:{value:shallowCopyInternalPointer(this.$$)}}));clone.$$.count.value+=1;clone.$$.deleteScheduled=false;return clone}},delete(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}detachFinalizer(this);releaseClassHandle(this.$$);if(!this.$$.preservePointerOnDelete){this.$$.smartPtr=undefined;this.$$.ptr=undefined}},isDeleted(){return!this.$$.ptr},deleteLater(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}deletionQueue.push(this);if(deletionQueue.length===1&&delayFunction){delayFunction(flushPendingDeletes)}this.$$.deleteScheduled=true;return this}})};function ClassHandle(){}var ensureOverloadTable=(proto,methodName,humanName)=>{if(undefined===proto[methodName].overloadTable){var prevFunc=proto[methodName];proto[methodName]=function(...args){if(!proto[methodName].overloadTable.hasOwnProperty(args.length)){throwBindingError(`Function '${humanName}' called with an invalid number of arguments (${args.length}) - expects one of (${proto[methodName].overloadTable})!`)}return proto[methodName].overloadTable[args.length].apply(this,args)};proto[methodName].overloadTable=[];proto[methodName].overloadTable[prevFunc.argCount]=prevFunc}};var exposePublicSymbol=(name,value,numArguments)=>{if(Module.hasOwnProperty(name)){if(undefined===numArguments||undefined!==Module[name].overloadTable&&undefined!==Module[name].overloadTable[numArguments]){throwBindingError(`Cannot register public name '${name}' twice`)}ensureOverloadTable(Module,name,name);if(Module[name].overloadTable.hasOwnProperty(numArguments)){throwBindingError(`Cannot register multiple overloads of a function with the same number of arguments (${numArguments})!`)}Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}};var char_0=48;var char_9=57;var makeLegalFunctionName=name=>{name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return`_${name}`}return name};function RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast){this.name=name;this.constructor=constructor;this.instancePrototype=instancePrototype;this.rawDestructor=rawDestructor;this.baseClass=baseClass;this.getActualType=getActualType;this.upcast=upcast;this.downcast=downcast;this.pureVirtualFunctions=[]}var upcastPointer=(ptr,ptrClass,desiredClass)=>{while(ptrClass!==desiredClass){if(!ptrClass.upcast){throwBindingError(`Expected null or instance of ${desiredClass.name}, got an instance of ${ptrClass.name}`)}ptr=ptrClass.upcast(ptr);ptrClass=ptrClass.baseClass}return ptr};function constNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}return 0}if(!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function genericPointerToWireType(destructors,handle){var ptr;if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}if(this.isSmartPointer){ptr=this.rawConstructor();if(destructors!==null){destructors.push(this.rawDestructor,ptr)}return ptr}else{return 0}}if(!handle||!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}if(!this.isConst&&handle.$$.ptrType.isConst){throwBindingError(`Cannot convert argument of type ${handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name} to parameter type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);if(this.isSmartPointer){if(undefined===handle.$$.smartPtr){throwBindingError("Passing raw pointer to smart pointer is illegal")}switch(this.sharingPolicy){case 0:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{throwBindingError(`Cannot convert argument of type ${handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name} to parameter type ${this.name}`)}break;case 1:ptr=handle.$$.smartPtr;break;case 2:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{var clonedHandle=handle["clone"]();ptr=this.rawShare(ptr,Emval.toHandle(()=>clonedHandle["delete"]()));if(destructors!==null){destructors.push(this.rawDestructor,ptr)}}break;default:throwBindingError("Unsupporting sharing policy")}}return ptr}function nonConstNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}return 0}if(!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}if(handle.$$.ptrType.isConst){throwBindingError(`Cannot convert argument of type ${handle.$$.ptrType.name} to parameter type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function readPointer(pointer){return this["fromWireType"](HEAPU32[pointer>>>2>>>0])}var init_RegisteredPointer=()=>{Object.assign(RegisteredPointer.prototype,{getPointee(ptr){if(this.rawGetPointee){ptr=this.rawGetPointee(ptr)}return ptr},destructor(ptr){this.rawDestructor?.(ptr)},argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,fromWireType:RegisteredPointer_fromWireType})};function RegisteredPointer(name,registeredClass,isReference,isConst,isSmartPointer,pointeeType,sharingPolicy,rawGetPointee,rawConstructor,rawShare,rawDestructor){this.name=name;this.registeredClass=registeredClass;this.isReference=isReference;this.isConst=isConst;this.isSmartPointer=isSmartPointer;this.pointeeType=pointeeType;this.sharingPolicy=sharingPolicy;this.rawGetPointee=rawGetPointee;this.rawConstructor=rawConstructor;this.rawShare=rawShare;this.rawDestructor=rawDestructor;if(!isSmartPointer&®isteredClass.baseClass===undefined){if(isConst){this["toWireType"]=constNoSmartPtrRawPointerToWireType;this.destructorFunction=null}else{this["toWireType"]=nonConstNoSmartPtrRawPointerToWireType;this.destructorFunction=null}}else{this["toWireType"]=genericPointerToWireType}}var replacePublicSymbol=(name,value,numArguments)=>{if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistent public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}};var dynCallLegacy=(sig,ptr,args)=>{sig=sig.replace(/p/g,"i");var f=Module["dynCall_"+sig];return f(ptr,...args)};var wasmTable;var getWasmTableEntry=funcPtr=>wasmTable.get(funcPtr);var dynCall=(sig,ptr,args=[])=>{if(sig.includes("j")){return dynCallLegacy(sig,ptr,args)}var rtn=getWasmTableEntry(ptr)(...args);return sig[0]=="p"?rtn>>>0:rtn};var getDynCaller=(sig,ptr)=>(...args)=>dynCall(sig,ptr,args);var embind__requireFunction=(signature,rawFunction)=>{signature=readLatin1String(signature);function makeDynCaller(){if(signature.includes("j")){return getDynCaller(signature,rawFunction)}if(signature.includes("p")){return getDynCaller(signature,rawFunction)}return getWasmTableEntry(rawFunction)}var fp=makeDynCaller();if(typeof fp!="function"){throwBindingError(`unknown function pointer with signature ${signature}: ${rawFunction}`)}return fp};var UnboundTypeError;var throwUnboundTypeError=(message,types)=>{var unboundTypes=[];var seen={};function visit(type){if(seen[type]){return}if(registeredTypes[type]){return}if(typeDependencies[type]){typeDependencies[type].forEach(visit);return}unboundTypes.push(type);seen[type]=true}types.forEach(visit);throw new UnboundTypeError(`${message}: `+unboundTypes.map(getTypeName).join([", "]))};function __embind_register_class(rawType,rawPointerType,rawConstPointerType,baseClassRawType,getActualTypeSignature,getActualType,upcastSignature,upcast,downcastSignature,downcast,name,destructorSignature,rawDestructor){rawType>>>=0;rawPointerType>>>=0;rawConstPointerType>>>=0;baseClassRawType>>>=0;getActualTypeSignature>>>=0;getActualType>>>=0;upcastSignature>>>=0;upcast>>>=0;downcastSignature>>>=0;downcast>>>=0;name>>>=0;destructorSignature>>>=0;rawDestructor>>>=0;name=readLatin1String(name);getActualType=embind__requireFunction(getActualTypeSignature,getActualType);upcast&&=embind__requireFunction(upcastSignature,upcast);downcast&&=embind__requireFunction(downcastSignature,downcast);rawDestructor=embind__requireFunction(destructorSignature,rawDestructor);var legalFunctionName=makeLegalFunctionName(name);exposePublicSymbol(legalFunctionName,function(){throwUnboundTypeError(`Cannot construct ${name} due to unbound types`,[baseClassRawType])});whenDependentTypesAreResolved([rawType,rawPointerType,rawConstPointerType],baseClassRawType?[baseClassRawType]:[],base=>{base=base[0];var baseClass;var basePrototype;if(baseClassRawType){baseClass=base.registeredClass;basePrototype=baseClass.instancePrototype}else{basePrototype=ClassHandle.prototype}var constructor=createNamedFunction(name,function(...args){if(Object.getPrototypeOf(this)!==instancePrototype){throw new BindingError("Use 'new' to construct "+name)}if(undefined===registeredClass.constructor_body){throw new BindingError(name+" has no accessible constructor")}var body=registeredClass.constructor_body[args.length];if(undefined===body){throw new BindingError(`Tried to invoke ctor of ${name} with invalid number of parameters (${args.length}) - expected (${Object.keys(registeredClass.constructor_body).toString()}) parameters instead!`)}return body.apply(this,args)});var instancePrototype=Object.create(basePrototype,{constructor:{value:constructor}});constructor.prototype=instancePrototype;var registeredClass=new RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast);if(registeredClass.baseClass){registeredClass.baseClass.__derivedClasses??=[];registeredClass.baseClass.__derivedClasses.push(registeredClass)}var referenceConverter=new RegisteredPointer(name,registeredClass,true,false,false);var pointerConverter=new RegisteredPointer(name+"*",registeredClass,false,false,false);var constPointerConverter=new RegisteredPointer(name+" const*",registeredClass,false,true,false);registeredPointers[rawType]={pointerType:pointerConverter,constPointerType:constPointerConverter};replacePublicSymbol(legalFunctionName,constructor);return[referenceConverter,pointerConverter,constPointerConverter]})}var runDestructors=destructors=>{while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}};function usesDestructorStack(argTypes){for(var i=1;i{var array=[];for(var i=0;i>>2>>>0])}return array};var getFunctionName=signature=>{signature=signature.trim();const argsIndex=signature.indexOf("(");if(argsIndex!==-1){return signature.substr(0,argsIndex)}else{return signature}};var __embind_register_class_class_function=function(rawClassType,methodName,argCount,rawArgTypesAddr,invokerSignature,rawInvoker,fn,isAsync,isNonnullReturn){rawClassType>>>=0;methodName>>>=0;rawArgTypesAddr>>>=0;invokerSignature>>>=0;rawInvoker>>>=0;fn>>>=0;var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);methodName=readLatin1String(methodName);methodName=getFunctionName(methodName);rawInvoker=embind__requireFunction(invokerSignature,rawInvoker);whenDependentTypesAreResolved([],[rawClassType],classType=>{classType=classType[0];var humanName=`${classType.name}.${methodName}`;function unboundTypesHandler(){throwUnboundTypeError(`Cannot call ${humanName} due to unbound types`,rawArgTypes)}if(methodName.startsWith("@@")){methodName=Symbol[methodName.substring(2)]}var proto=classType.registeredClass.constructor;if(undefined===proto[methodName]){unboundTypesHandler.argCount=argCount-1;proto[methodName]=unboundTypesHandler}else{ensureOverloadTable(proto,methodName,humanName);proto[methodName].overloadTable[argCount-1]=unboundTypesHandler}whenDependentTypesAreResolved([],rawArgTypes,argTypes=>{var invokerArgsArray=[argTypes[0],null].concat(argTypes.slice(1));var func=craftInvokerFunction(humanName,invokerArgsArray,null,rawInvoker,fn,isAsync);if(undefined===proto[methodName].overloadTable){func.argCount=argCount-1;proto[methodName]=func}else{proto[methodName].overloadTable[argCount-1]=func}if(classType.registeredClass.__derivedClasses){for(const derivedClass of classType.registeredClass.__derivedClasses){if(!derivedClass.constructor.hasOwnProperty(methodName)){derivedClass.constructor[methodName]=func}}}return[]});return[]})};var __embind_register_class_constructor=function(rawClassType,argCount,rawArgTypesAddr,invokerSignature,invoker,rawConstructor){rawClassType>>>=0;rawArgTypesAddr>>>=0;invokerSignature>>>=0;invoker>>>=0;rawConstructor>>>=0;var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);invoker=embind__requireFunction(invokerSignature,invoker);whenDependentTypesAreResolved([],[rawClassType],classType=>{classType=classType[0];var humanName=`constructor ${classType.name}`;if(undefined===classType.registeredClass.constructor_body){classType.registeredClass.constructor_body=[]}if(undefined!==classType.registeredClass.constructor_body[argCount-1]){throw new BindingError(`Cannot register multiple constructors with identical number of parameters (${argCount-1}) for class '${classType.name}'! Overload resolution is currently only performed using the parameter count, not actual type info!`)}classType.registeredClass.constructor_body[argCount-1]=()=>{throwUnboundTypeError(`Cannot construct ${classType.name} due to unbound types`,rawArgTypes)};whenDependentTypesAreResolved([],rawArgTypes,argTypes=>{argTypes.splice(1,0,null);classType.registeredClass.constructor_body[argCount-1]=craftInvokerFunction(humanName,argTypes,null,invoker,rawConstructor);return[]});return[]})};var __embind_register_class_function=function(rawClassType,methodName,argCount,rawArgTypesAddr,invokerSignature,rawInvoker,context,isPureVirtual,isAsync,isNonnullReturn){rawClassType>>>=0;methodName>>>=0;rawArgTypesAddr>>>=0;invokerSignature>>>=0;rawInvoker>>>=0;context>>>=0;var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);methodName=readLatin1String(methodName);methodName=getFunctionName(methodName);rawInvoker=embind__requireFunction(invokerSignature,rawInvoker);whenDependentTypesAreResolved([],[rawClassType],classType=>{classType=classType[0];var humanName=`${classType.name}.${methodName}`;if(methodName.startsWith("@@")){methodName=Symbol[methodName.substring(2)]}if(isPureVirtual){classType.registeredClass.pureVirtualFunctions.push(methodName)}function unboundTypesHandler(){throwUnboundTypeError(`Cannot call ${humanName} due to unbound types`,rawArgTypes)}var proto=classType.registeredClass.instancePrototype;var method=proto[methodName];if(undefined===method||undefined===method.overloadTable&&method.className!==classType.name&&method.argCount===argCount-2){unboundTypesHandler.argCount=argCount-2;unboundTypesHandler.className=classType.name;proto[methodName]=unboundTypesHandler}else{ensureOverloadTable(proto,methodName,humanName);proto[methodName].overloadTable[argCount-2]=unboundTypesHandler}whenDependentTypesAreResolved([],rawArgTypes,argTypes=>{var memberFunction=craftInvokerFunction(humanName,argTypes,classType,rawInvoker,context,isAsync);if(undefined===proto[methodName].overloadTable){memberFunction.argCount=argCount-2;proto[methodName]=memberFunction}else{proto[methodName].overloadTable[argCount-2]=memberFunction}return[]});return[]})};var validateThis=(this_,classType,humanName)=>{if(!(this_ instanceof Object)){throwBindingError(`${humanName} with invalid "this": ${this_}`)}if(!(this_ instanceof classType.registeredClass.constructor)){throwBindingError(`${humanName} incompatible with "this" of type ${this_.constructor.name}`)}if(!this_.$$.ptr){throwBindingError(`cannot call emscripten binding method ${humanName} on deleted object`)}return upcastPointer(this_.$$.ptr,this_.$$.ptrType.registeredClass,classType.registeredClass)};var __embind_register_class_property=function(classType,fieldName,getterReturnType,getterSignature,getter,getterContext,setterArgumentType,setterSignature,setter,setterContext){classType>>>=0;fieldName>>>=0;getterReturnType>>>=0;getterSignature>>>=0;getter>>>=0;getterContext>>>=0;setterArgumentType>>>=0;setterSignature>>>=0;setter>>>=0;setterContext>>>=0;fieldName=readLatin1String(fieldName);getter=embind__requireFunction(getterSignature,getter);whenDependentTypesAreResolved([],[classType],classType=>{classType=classType[0];var humanName=`${classType.name}.${fieldName}`;var desc={get(){throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`,[getterReturnType,setterArgumentType])},enumerable:true,configurable:true};if(setter){desc.set=()=>throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`,[getterReturnType,setterArgumentType])}else{desc.set=v=>throwBindingError(humanName+" is a read-only property")}Object.defineProperty(classType.registeredClass.instancePrototype,fieldName,desc);whenDependentTypesAreResolved([],setter?[getterReturnType,setterArgumentType]:[getterReturnType],types=>{var getterReturnType=types[0];var desc={get(){var ptr=validateThis(this,classType,humanName+" getter");return getterReturnType["fromWireType"](getter(getterContext,ptr))},enumerable:true};if(setter){setter=embind__requireFunction(setterSignature,setter);var setterArgumentType=types[1];desc.set=function(v){var ptr=validateThis(this,classType,humanName+" setter");var destructors=[];setter(setterContext,ptr,setterArgumentType["toWireType"](destructors,v));runDestructors(destructors)}}Object.defineProperty(classType.registeredClass.instancePrototype,fieldName,desc);return[]});return[]})};function __emval_decref(handle){handle>>>=0;if(handle>9&&0===--emval_handles[handle+1]){emval_handles[handle]=undefined;emval_freelist.push(handle)}}var EmValType={name:"emscripten::val",fromWireType:handle=>{var rv=Emval.toValue(handle);__emval_decref(handle);return rv},toWireType:(destructors,value)=>Emval.toHandle(value),argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,destructorFunction:null};function __embind_register_emval(rawType){rawType>>>=0;return registerType(rawType,EmValType)}var enumReadValueFromPointer=(name,width,signed)=>{switch(width){case 1:return signed?function(pointer){return this["fromWireType"](HEAP8[pointer>>>0])}:function(pointer){return this["fromWireType"](HEAPU8[pointer>>>0])};case 2:return signed?function(pointer){return this["fromWireType"](HEAP16[pointer>>>1>>>0])}:function(pointer){return this["fromWireType"](HEAPU16[pointer>>>1>>>0])};case 4:return signed?function(pointer){return this["fromWireType"](HEAP32[pointer>>>2>>>0])}:function(pointer){return this["fromWireType"](HEAPU32[pointer>>>2>>>0])};default:throw new TypeError(`invalid integer width (${width}): ${name}`)}};function __embind_register_enum(rawType,name,size,isSigned){rawType>>>=0;name>>>=0;size>>>=0;name=readLatin1String(name);function ctor(){}ctor.values={};registerType(rawType,{name,constructor:ctor,fromWireType:function(c){return this.constructor.values[c]},toWireType:(destructors,c)=>c.value,argPackAdvance:GenericWireTypeSize,readValueFromPointer:enumReadValueFromPointer(name,size,isSigned),destructorFunction:null});exposePublicSymbol(name,ctor)}function __embind_register_enum_value(rawEnumType,name,enumValue){rawEnumType>>>=0;name>>>=0;var enumType=requireRegisteredType(rawEnumType,"enum");name=readLatin1String(name);var Enum=enumType.constructor;var Value=Object.create(enumType.constructor.prototype,{value:{value:enumValue},constructor:{value:createNamedFunction(`${enumType.name}_${name}`,function(){})}});Enum.values[enumValue]=Value;Enum[name]=Value}var embindRepr=v=>{if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}};var floatReadValueFromPointer=(name,width)=>{switch(width){case 4:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>>2>>>0])};case 8:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>>3>>>0])};default:throw new TypeError(`invalid float width (${width}): ${name}`)}};var __embind_register_float=function(rawType,name,size){rawType>>>=0;name>>>=0;size>>>=0;name=readLatin1String(name);registerType(rawType,{name,fromWireType:value=>value,toWireType:(destructors,value)=>value,argPackAdvance:GenericWireTypeSize,readValueFromPointer:floatReadValueFromPointer(name,size),destructorFunction:null})};function __embind_register_function(name,argCount,rawArgTypesAddr,signature,rawInvoker,fn,isAsync,isNonnullReturn){name>>>=0;rawArgTypesAddr>>>=0;signature>>>=0;rawInvoker>>>=0;fn>>>=0;var argTypes=heap32VectorToArray(argCount,rawArgTypesAddr);name=readLatin1String(name);name=getFunctionName(name);rawInvoker=embind__requireFunction(signature,rawInvoker);exposePublicSymbol(name,function(){throwUnboundTypeError(`Cannot call ${name} due to unbound types`,argTypes)},argCount-1);whenDependentTypesAreResolved([],argTypes,argTypes=>{var invokerArgsArray=[argTypes[0],null].concat(argTypes.slice(1));replacePublicSymbol(name,craftInvokerFunction(name,invokerArgsArray,null,rawInvoker,fn,isAsync),argCount-1);return[]})}var integerReadValueFromPointer=(name,width,signed)=>{switch(width){case 1:return signed?pointer=>HEAP8[pointer>>>0]:pointer=>HEAPU8[pointer>>>0];case 2:return signed?pointer=>HEAP16[pointer>>>1>>>0]:pointer=>HEAPU16[pointer>>>1>>>0];case 4:return signed?pointer=>HEAP32[pointer>>>2>>>0]:pointer=>HEAPU32[pointer>>>2>>>0];default:throw new TypeError(`invalid integer width (${width}): ${name}`)}};function __embind_register_integer(primitiveType,name,size,minRange,maxRange){primitiveType>>>=0;name>>>=0;size>>>=0;name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var fromWireType=value=>value;if(minRange===0){var bitshift=32-8*size;fromWireType=value=>value<>>bitshift}var isUnsignedType=name.includes("unsigned");var checkAssertions=(value,toTypeName)=>{};var toWireType;if(isUnsignedType){toWireType=function(destructors,value){checkAssertions(value,this.name);return value>>>0}}else{toWireType=function(destructors,value){checkAssertions(value,this.name);return value}}registerType(primitiveType,{name,fromWireType,toWireType,argPackAdvance:GenericWireTypeSize,readValueFromPointer:integerReadValueFromPointer(name,size,minRange!==0),destructorFunction:null})}function __embind_register_memory_view(rawType,dataTypeIndex,name){rawType>>>=0;name>>>=0;var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){var size=HEAPU32[handle>>>2>>>0];var data=HEAPU32[handle+4>>>2>>>0];return new TA(HEAP8.buffer,data,size)}name=readLatin1String(name);registerType(rawType,{name,fromWireType:decodeMemoryView,argPackAdvance:GenericWireTypeSize,readValueFromPointer:decodeMemoryView},{ignoreDuplicateRegistrations:true})}var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);function __embind_register_std_string(rawType,name){rawType>>>=0;name>>>=0;name=readLatin1String(name);var stdStringIsUTF8=true;registerType(rawType,{name,fromWireType(value){var length=HEAPU32[value>>>2>>>0];var payload=value+4;var str;if(stdStringIsUTF8){var decodeStartPtr=payload;for(var i=0;i<=length;++i){var currentBytePtr=payload+i;if(i==length||HEAPU8[currentBytePtr>>>0]==0){var maxRead=currentBytePtr-decodeStartPtr;var stringSegment=UTF8ToString(decodeStartPtr,maxRead);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}}else{var a=new Array(length);for(var i=0;i>>0])}str=a.join("")}_free(value);return str},toWireType(destructors,value){if(value instanceof ArrayBuffer){value=new Uint8Array(value)}var length;var valueIsOfTypeString=typeof value=="string";if(!(valueIsOfTypeString||value instanceof Uint8Array||value instanceof Uint8ClampedArray||value instanceof Int8Array)){throwBindingError("Cannot pass non-string to std::string")}if(stdStringIsUTF8&&valueIsOfTypeString){length=lengthBytesUTF8(value)}else{length=value.length}var base=_malloc(4+length+1);var ptr=base+4;HEAPU32[base>>>2>>>0]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+i>>>0]=charCode}}else{for(var i=0;i>>0]=value[i]}}}if(destructors!==null){destructors.push(_free,base)}return base},argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,destructorFunction(ptr){_free(ptr)}})}var UTF16Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf-16le"):undefined;var UTF16ToString=(ptr,maxBytesToRead)=>{var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx>>>0])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(HEAPU8.subarray(ptr>>>0,endPtr>>>0));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=HEAP16[ptr+i*2>>>1>>>0];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit)}return str};var stringToUTF16=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>>1>>>0]=codeUnit;outPtr+=2}HEAP16[outPtr>>>1>>>0]=0;return outPtr-startPtr};var lengthBytesUTF16=str=>str.length*2;var UTF32ToString=(ptr,maxBytesToRead)=>{var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>>2>>>0];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str};var stringToUTF32=(str,outPtr,maxBytesToWrite)=>{outPtr>>>=0;maxBytesToWrite??=2147483647;if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>>2>>>0]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>>2>>>0]=0;return outPtr-startPtr};var lengthBytesUTF32=str=>{var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len};var __embind_register_std_wstring=function(rawType,charSize,name){rawType>>>=0;charSize>>>=0;name>>>=0;name=readLatin1String(name);var decodeString,encodeString,readCharAt,lengthBytesUTF;if(charSize===2){decodeString=UTF16ToString;encodeString=stringToUTF16;lengthBytesUTF=lengthBytesUTF16;readCharAt=pointer=>HEAPU16[pointer>>>1>>>0]}else if(charSize===4){decodeString=UTF32ToString;encodeString=stringToUTF32;lengthBytesUTF=lengthBytesUTF32;readCharAt=pointer=>HEAPU32[pointer>>>2>>>0]}registerType(rawType,{name,fromWireType:value=>{var length=HEAPU32[value>>>2>>>0];var str;var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i*charSize;if(i==length||readCharAt(currentBytePtr)==0){var maxReadBytes=currentBytePtr-decodeStartPtr;var stringSegment=decodeString(decodeStartPtr,maxReadBytes);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+charSize}}_free(value);return str},toWireType:(destructors,value)=>{if(!(typeof value=="string")){throwBindingError(`Cannot pass non-string to C++ string type ${name}`)}var length=lengthBytesUTF(value);var ptr=_malloc(4+length+charSize);HEAPU32[ptr>>>2>>>0]=length/charSize;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,destructorFunction(ptr){_free(ptr)}})};var __embind_register_void=function(rawType,name){rawType>>>=0;name>>>=0;name=readLatin1String(name);registerType(rawType,{isVoid:true,name,argPackAdvance:0,fromWireType:()=>undefined,toWireType:(destructors,o)=>undefined})};function __emscripten_fetch_free(id){if(Fetch.xhrs.has(id)){var xhr=Fetch.xhrs.get(id);Fetch.xhrs.free(id);if(xhr.readyState>0&&xhr.readyState<4){xhr.abort()}}}var __emscripten_throw_longjmp=()=>{throw Infinity};var emval_symbols={};var getStringOrSymbol=address=>{var symbol=emval_symbols[address];if(symbol===undefined){return readLatin1String(address)}return symbol};var emval_methodCallers=[];function __emval_call_method(caller,objHandle,methodName,destructorsRef,args){caller>>>=0;objHandle>>>=0;methodName>>>=0;destructorsRef>>>=0;args>>>=0;caller=emval_methodCallers[caller];objHandle=Emval.toValue(objHandle);methodName=getStringOrSymbol(methodName);return caller(objHandle,objHandle[methodName],destructorsRef,args)}var emval_addMethodCaller=caller=>{var id=emval_methodCallers.length;emval_methodCallers.push(caller);return id};var emval_lookupTypes=(argCount,argTypes)=>{var a=new Array(argCount);for(var i=0;i>>2>>>0],"parameter "+i)}return a};var reflectConstruct=Reflect.construct;var emval_returnValue=(returnType,destructorsRef,handle)=>{var destructors=[];var result=returnType["toWireType"](destructors,handle);if(destructors.length){HEAPU32[destructorsRef>>>2>>>0]=Emval.toHandle(destructors)}return result};var __emval_get_method_caller=function(argCount,argTypes,kind){argTypes>>>=0;var types=emval_lookupTypes(argCount,argTypes);var retType=types.shift();argCount--;var argN=new Array(argCount);var invokerFunction=(obj,func,destructorsRef,args)=>{var offset=0;for(var i=0;it.name).join(", ")}) => ${retType.name}>`;return emval_addMethodCaller(createNamedFunction(functionName,invokerFunction))};function __emval_run_destructors(handle){handle>>>=0;var destructors=Emval.toValue(handle);runDestructors(destructors);__emval_decref(handle)}function __emval_take_value(type,arg){type>>>=0;arg>>>=0;type=requireRegisteredType(type,"_emval_take_value");var v=type["readValueFromPointer"](arg);return Emval.toHandle(v)}var isLeapYear=year=>year%4===0&&(year%100!==0||year%400===0);var MONTH_DAYS_LEAP_CUMULATIVE=[0,31,60,91,121,152,182,213,244,274,305,335];var MONTH_DAYS_REGULAR_CUMULATIVE=[0,31,59,90,120,151,181,212,243,273,304,334];var ydayFromDate=date=>{var leap=isLeapYear(date.getFullYear());var monthDaysCumulative=leap?MONTH_DAYS_LEAP_CUMULATIVE:MONTH_DAYS_REGULAR_CUMULATIVE;var yday=monthDaysCumulative[date.getMonth()]+date.getDate()-1;return yday};function __localtime_js(time_low,time_high,tmPtr){var time=convertI32PairToI53Checked(time_low,time_high);tmPtr>>>=0;var date=new Date(time*1e3);HEAP32[tmPtr>>>2>>>0]=date.getSeconds();HEAP32[tmPtr+4>>>2>>>0]=date.getMinutes();HEAP32[tmPtr+8>>>2>>>0]=date.getHours();HEAP32[tmPtr+12>>>2>>>0]=date.getDate();HEAP32[tmPtr+16>>>2>>>0]=date.getMonth();HEAP32[tmPtr+20>>>2>>>0]=date.getFullYear()-1900;HEAP32[tmPtr+24>>>2>>>0]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>>2>>>0]=yday;HEAP32[tmPtr+36>>>2>>>0]=-(date.getTimezoneOffset()*60);var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>>2>>>0]=dst}var __tzset_js=function(timezone,daylight,std_name,dst_name){timezone>>>=0;daylight>>>=0;std_name>>>=0;dst_name>>>=0;var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);var winterOffset=winter.getTimezoneOffset();var summerOffset=summer.getTimezoneOffset();var stdTimezoneOffset=Math.max(winterOffset,summerOffset);HEAPU32[timezone>>>2>>>0]=stdTimezoneOffset*60;HEAP32[daylight>>>2>>>0]=Number(winterOffset!=summerOffset);var extractZone=timezoneOffset=>{var sign=timezoneOffset>=0?"-":"+";var absOffset=Math.abs(timezoneOffset);var hours=String(Math.floor(absOffset/60)).padStart(2,"0");var minutes=String(absOffset%60).padStart(2,"0");return`UTC${sign}${hours}${minutes}`};var winterName=extractZone(winterOffset);var summerName=extractZone(summerOffset);if(summerOffsetperformance.now();var _emscripten_date_now=()=>Date.now();var nowIsMonotonic=1;var checkWasiClock=clock_id=>clock_id>=0&&clock_id<=3;function _clock_time_get(clk_id,ignored_precision_low,ignored_precision_high,ptime){var ignored_precision=convertI32PairToI53Checked(ignored_precision_low,ignored_precision_high);ptime>>>=0;if(!checkWasiClock(clk_id)){return 28}var now;if(clk_id===0){now=_emscripten_date_now()}else if(nowIsMonotonic){now=_emscripten_get_now()}else{return 52}var nsec=Math.round(now*1e3*1e3);tempI64=[nsec>>>0,(tempDouble=nsec,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[ptime>>>2>>>0]=tempI64[0],HEAP32[ptime+4>>>2>>>0]=tempI64[1];return 0}var readEmAsmArgsArray=[];var readEmAsmArgs=(sigPtr,buf)=>{readEmAsmArgsArray.length=0;var ch;while(ch=HEAPU8[sigPtr++>>>0]){var wide=ch!=105;wide&=ch!=112;buf+=wide&&buf%8?4:0;readEmAsmArgsArray.push(ch==112?HEAPU32[buf>>>2>>>0]:ch==105?HEAP32[buf>>>2>>>0]:HEAPF64[buf>>>3>>>0]);buf+=wide?8:4}return readEmAsmArgsArray};var runEmAsmFunction=(code,sigPtr,argbuf)=>{var args=readEmAsmArgs(sigPtr,argbuf);return ASM_CONSTS[code](...args)};function _emscripten_asm_const_int(code,sigPtr,argbuf){code>>>=0;sigPtr>>>=0;argbuf>>>=0;return runEmAsmFunction(code,sigPtr,argbuf)}var _emscripten_set_main_loop_timing=(mode,value)=>{MainLoop.timingMode=mode;MainLoop.timingValue=value;if(!MainLoop.func){return 1}if(!MainLoop.running){MainLoop.running=true}if(mode==0){MainLoop.scheduler=function MainLoop_scheduler_setTimeout(){var timeUntilNextTick=Math.max(0,MainLoop.tickStartTime+value-_emscripten_get_now())|0;setTimeout(MainLoop.runner,timeUntilNextTick)};MainLoop.method="timeout"}else if(mode==1){MainLoop.scheduler=function MainLoop_scheduler_rAF(){MainLoop.requestAnimationFrame(MainLoop.runner)};MainLoop.method="rAF"}else if(mode==2){if(typeof MainLoop.setImmediate=="undefined"){if(typeof setImmediate=="undefined"){var setImmediates=[];var emscriptenMainLoopMessageId="setimmediate";var MainLoop_setImmediate_messageHandler=event=>{if(event.data===emscriptenMainLoopMessageId||event.data.target===emscriptenMainLoopMessageId){event.stopPropagation();setImmediates.shift()()}};addEventListener("message",MainLoop_setImmediate_messageHandler,true);MainLoop.setImmediate=func=>{setImmediates.push(func);if(ENVIRONMENT_IS_WORKER){Module["setImmediates"]??=[];Module["setImmediates"].push(func);postMessage({target:emscriptenMainLoopMessageId})}else postMessage(emscriptenMainLoopMessageId,"*")}}else{MainLoop.setImmediate=setImmediate}}MainLoop.scheduler=function MainLoop_scheduler_setImmediate(){MainLoop.setImmediate(MainLoop.runner)};MainLoop.method="immediate"}return 0};var runtimeKeepaliveCounter=0;var keepRuntimeAlive=()=>noExitRuntime||runtimeKeepaliveCounter>0;var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){Module["onExit"]?.(code);ABORT=true}quit_(code,new ExitStatus(code))};var exitJS=(status,implicit)=>{EXITSTATUS=status;_proc_exit(status)};var _exit=exitJS;var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)};var maybeExit=()=>{if(!keepRuntimeAlive()){try{_exit(EXITSTATUS)}catch(e){handleException(e)}}};var setMainLoop=(iterFunc,fps,simulateInfiniteLoop,arg,noSetTiming)=>{MainLoop.func=iterFunc;MainLoop.arg=arg;var thisMainLoopId=MainLoop.currentlyRunningMainloop;function checkIsRunning(){if(thisMainLoopId0){var start=Date.now();var blocker=MainLoop.queue.shift();blocker.func(blocker.arg);if(MainLoop.remainingBlockers){var remaining=MainLoop.remainingBlockers;var next=remaining%1==0?remaining-1:Math.floor(remaining);if(blocker.counted){MainLoop.remainingBlockers=next}else{next=next+.5;MainLoop.remainingBlockers=(8*remaining+next)/9}}MainLoop.updateStatus();if(!checkIsRunning())return;setTimeout(MainLoop.runner,0);return}if(!checkIsRunning())return;MainLoop.currentFrameNumber=MainLoop.currentFrameNumber+1|0;if(MainLoop.timingMode==1&&MainLoop.timingValue>1&&MainLoop.currentFrameNumber%MainLoop.timingValue!=0){MainLoop.scheduler();return}else if(MainLoop.timingMode==0){MainLoop.tickStartTime=_emscripten_get_now()}MainLoop.runIter(iterFunc);if(!checkIsRunning())return;MainLoop.scheduler()};if(!noSetTiming){if(fps&&fps>0){_emscripten_set_main_loop_timing(0,1e3/fps)}else{_emscripten_set_main_loop_timing(1,1)}MainLoop.scheduler()}if(simulateInfiniteLoop){throw"unwind"}};var callUserCallback=func=>{if(ABORT){return}try{func();maybeExit()}catch(e){handleException(e)}};var MainLoop={running:false,scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],preMainLoop:[],postMainLoop:[],pause(){MainLoop.scheduler=null;MainLoop.currentlyRunningMainloop++},resume(){MainLoop.currentlyRunningMainloop++;var timingMode=MainLoop.timingMode;var timingValue=MainLoop.timingValue;var func=MainLoop.func;MainLoop.func=null;setMainLoop(func,0,false,MainLoop.arg,true);_emscripten_set_main_loop_timing(timingMode,timingValue);MainLoop.scheduler()},updateStatus(){if(Module["setStatus"]){var message=Module["statusMessage"]||"Please wait...";var remaining=MainLoop.remainingBlockers??0;var expected=MainLoop.expectedBlockers??0;if(remaining){if(remaining=MainLoop.nextRAF){MainLoop.nextRAF+=1e3/60}}var delay=Math.max(MainLoop.nextRAF-now,0);setTimeout(func,delay)},requestAnimationFrame(func){if(typeof requestAnimationFrame=="function"){requestAnimationFrame(func);return}var RAF=MainLoop.fakeRequestAnimationFrame;RAF(func)}};var _emscripten_cancel_main_loop=()=>{MainLoop.pause();MainLoop.func=null};var __emscripten_runtime_keepalive_clear=()=>{noExitRuntime=false;runtimeKeepaliveCounter=0};var _emscripten_force_exit=status=>{__emscripten_runtime_keepalive_clear();_exit(status)};var _emscripten_is_main_browser_thread=()=>!ENVIRONMENT_IS_WORKER;var getHeapMax=()=>4294901760;var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};function _emscripten_resize_heap(requestedSize){requestedSize>>>=0;var oldSize=HEAPU8.length;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false}function _emscripten_set_main_loop(func,fps,simulateInfiniteLoop){func>>>=0;var iterFunc=getWasmTableEntry(func);setMainLoop(iterFunc,fps,simulateInfiniteLoop)}class HandleAllocator{allocated=[undefined];freelist=[];get(id){return this.allocated[id]}has(id){return this.allocated[id]!==undefined}allocate(handle){var id=this.freelist.pop()||this.allocated.length;this.allocated[id]=handle;return id}free(id){this.allocated[id]=undefined;this.freelist.push(id)}}var Fetch={openDatabase(dbname,dbversion,onsuccess,onerror){try{var openRequest=indexedDB.open(dbname,dbversion)}catch(e){return onerror(e)}openRequest.onupgradeneeded=event=>{var db=event.target.result;if(db.objectStoreNames.contains("FILES")){db.deleteObjectStore("FILES")}db.createObjectStore("FILES")};openRequest.onsuccess=event=>onsuccess(event.target.result);openRequest.onerror=onerror},init(){Fetch.xhrs=new HandleAllocator;var onsuccess=db=>{Fetch.dbInstance=db;removeRunDependency("library_fetch_init")};var onerror=()=>{Fetch.dbInstance=false;removeRunDependency("library_fetch_init")};addRunDependency("library_fetch_init");Fetch.openDatabase("emscripten_filesystem",1,onsuccess,onerror)}};function fetchXHR(fetch,onsuccess,onerror,onprogress,onreadystatechange){var url=HEAPU32[fetch+8>>>2>>>0];if(!url){onerror(fetch,0,"no url specified!");return}var url_=UTF8ToString(url);var fetch_attr=fetch+108;var requestMethod=UTF8ToString(fetch_attr+0);requestMethod||="GET";var timeoutMsecs=HEAPU32[fetch_attr+56>>>2>>>0];var userName=HEAPU32[fetch_attr+68>>>2>>>0];var password=HEAPU32[fetch_attr+72>>>2>>>0];var requestHeaders=HEAPU32[fetch_attr+76>>>2>>>0];var overriddenMimeType=HEAPU32[fetch_attr+80>>>2>>>0];var dataPtr=HEAPU32[fetch_attr+84>>>2>>>0];var dataLength=HEAPU32[fetch_attr+88>>>2>>>0];var fetchAttributes=HEAPU32[fetch_attr+52>>>2>>>0];var fetchAttrLoadToMemory=!!(fetchAttributes&1);var fetchAttrStreamData=!!(fetchAttributes&2);var fetchAttrSynchronous=!!(fetchAttributes&64);var userNameStr=userName?UTF8ToString(userName):undefined;var passwordStr=password?UTF8ToString(password):undefined;var xhr=new XMLHttpRequest;xhr.withCredentials=!!HEAPU8[fetch_attr+60>>>0];xhr.open(requestMethod,url_,!fetchAttrSynchronous,userNameStr,passwordStr);if(!fetchAttrSynchronous)xhr.timeout=timeoutMsecs;xhr.url_=url_;xhr.responseType="arraybuffer";if(overriddenMimeType){var overriddenMimeTypeStr=UTF8ToString(overriddenMimeType);xhr.overrideMimeType(overriddenMimeTypeStr)}if(requestHeaders){for(;;){var key=HEAPU32[requestHeaders>>>2>>>0];if(!key)break;var value=HEAPU32[requestHeaders+4>>>2>>>0];if(!value)break;requestHeaders+=8;var keyStr=UTF8ToString(key);var valueStr=UTF8ToString(value);xhr.setRequestHeader(keyStr,valueStr)}}var id=Fetch.xhrs.allocate(xhr);HEAPU32[fetch>>>2>>>0]=id;var data=dataPtr&&dataLength?HEAPU8.slice(dataPtr,dataPtr+dataLength):null;function saveResponseAndStatus(){var ptr=0;var ptrLen=0;if(xhr.response&&fetchAttrLoadToMemory&&HEAPU32[fetch+12>>>2>>>0]===0){ptrLen=xhr.response.byteLength}if(ptrLen>0){ptr=_malloc(ptrLen);HEAPU8.set(new Uint8Array(xhr.response),ptr>>>0)}HEAPU32[fetch+12>>>2>>>0]=ptr;writeI53ToI64(fetch+16,ptrLen);writeI53ToI64(fetch+24,0);var len=xhr.response?xhr.response.byteLength:0;if(len){writeI53ToI64(fetch+32,len)}HEAP16[fetch+40>>>1>>>0]=xhr.readyState;HEAP16[fetch+42>>>1>>>0]=xhr.status;if(xhr.statusText)stringToUTF8(xhr.statusText,fetch+44,64)}xhr.onload=e=>{if(!Fetch.xhrs.has(id)){return}saveResponseAndStatus();if(xhr.status>=200&&xhr.status<300){onsuccess?.(fetch,xhr,e)}else{onerror?.(fetch,xhr,e)}};xhr.onerror=e=>{if(!Fetch.xhrs.has(id)){return}saveResponseAndStatus();onerror?.(fetch,xhr,e)};xhr.ontimeout=e=>{if(!Fetch.xhrs.has(id)){return}onerror?.(fetch,xhr,e)};xhr.onprogress=e=>{if(!Fetch.xhrs.has(id)){return}var ptrLen=fetchAttrLoadToMemory&&fetchAttrStreamData&&xhr.response?xhr.response.byteLength:0;var ptr=0;if(ptrLen>0&&fetchAttrLoadToMemory&&fetchAttrStreamData){ptr=_malloc(ptrLen);HEAPU8.set(new Uint8Array(xhr.response),ptr>>>0)}HEAPU32[fetch+12>>>2>>>0]=ptr;writeI53ToI64(fetch+16,ptrLen);writeI53ToI64(fetch+24,e.loaded-ptrLen);writeI53ToI64(fetch+32,e.total);HEAP16[fetch+40>>>1>>>0]=xhr.readyState;if(xhr.readyState>=3&&xhr.status===0&&e.loaded>0)xhr.status=200;HEAP16[fetch+42>>>1>>>0]=xhr.status;if(xhr.statusText)stringToUTF8(xhr.statusText,fetch+44,64);onprogress?.(fetch,xhr,e);if(ptr){_free(ptr)}};xhr.onreadystatechange=e=>{if(!Fetch.xhrs.has(id)){return}HEAP16[fetch+40>>>1>>>0]=xhr.readyState;if(xhr.readyState>=2){HEAP16[fetch+42>>>1>>>0]=xhr.status}onreadystatechange?.(fetch,xhr,e)};try{xhr.send(data)}catch(e){onerror?.(fetch,xhr,e)}}var writeI53ToI64=(ptr,num)=>{HEAPU32[ptr>>>2>>>0]=num;var lower=HEAPU32[ptr>>>2>>>0];HEAPU32[ptr+4>>>2>>>0]=(num-lower)/4294967296};function fetchCacheData(db,fetch,data,onsuccess,onerror){if(!db){onerror(fetch,0,"IndexedDB not available!");return}var fetch_attr=fetch+108;var destinationPath=HEAPU32[fetch_attr+64>>>2>>>0];destinationPath||=HEAPU32[fetch+8>>>2>>>0];var destinationPathStr=UTF8ToString(destinationPath);try{var transaction=db.transaction(["FILES"],"readwrite");var packages=transaction.objectStore("FILES");var putRequest=packages.put(data,destinationPathStr);putRequest.onsuccess=event=>{HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=200;stringToUTF8("OK",fetch+44,64);onsuccess(fetch,0,destinationPathStr)};putRequest.onerror=error=>{HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=413;stringToUTF8("Payload Too Large",fetch+44,64);onerror(fetch,0,error)}}catch(e){onerror(fetch,0,e)}}function fetchLoadCachedData(db,fetch,onsuccess,onerror){if(!db){onerror(fetch,0,"IndexedDB not available!");return}var fetch_attr=fetch+108;var path=HEAPU32[fetch_attr+64>>>2>>>0];path||=HEAPU32[fetch+8>>>2>>>0];var pathStr=UTF8ToString(path);try{var transaction=db.transaction(["FILES"],"readonly");var packages=transaction.objectStore("FILES");var getRequest=packages.get(pathStr);getRequest.onsuccess=event=>{if(event.target.result){var value=event.target.result;var len=value.byteLength||value.length;var ptr=_malloc(len);HEAPU8.set(new Uint8Array(value),ptr>>>0);HEAPU32[fetch+12>>>2>>>0]=ptr;writeI53ToI64(fetch+16,len);writeI53ToI64(fetch+24,0);writeI53ToI64(fetch+32,len);HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=200;stringToUTF8("OK",fetch+44,64);onsuccess(fetch,0,value)}else{HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=404;stringToUTF8("Not Found",fetch+44,64);onerror(fetch,0,"no data")}};getRequest.onerror=error=>{HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=404;stringToUTF8("Not Found",fetch+44,64);onerror(fetch,0,error)}}catch(e){onerror(fetch,0,e)}}function fetchDeleteCachedData(db,fetch,onsuccess,onerror){if(!db){onerror(fetch,0,"IndexedDB not available!");return}var fetch_attr=fetch+108;var path=HEAPU32[fetch_attr+64>>>2>>>0];path||=HEAPU32[fetch+8>>>2>>>0];var pathStr=UTF8ToString(path);try{var transaction=db.transaction(["FILES"],"readwrite");var packages=transaction.objectStore("FILES");var request=packages.delete(pathStr);request.onsuccess=event=>{var value=event.target.result;HEAPU32[fetch+12>>>2>>>0]=0;writeI53ToI64(fetch+16,0);writeI53ToI64(fetch+24,0);writeI53ToI64(fetch+32,0);HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=200;stringToUTF8("OK",fetch+44,64);onsuccess(fetch,0,value)};request.onerror=error=>{HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=404;stringToUTF8("Not Found",fetch+44,64);onerror(fetch,0,error)}}catch(e){onerror(fetch,0,e)}}function _emscripten_start_fetch(fetch,successcb,errorcb,progresscb,readystatechangecb){fetch>>>=0;var fetch_attr=fetch+108;var onsuccess=HEAPU32[fetch_attr+36>>>2>>>0];var onerror=HEAPU32[fetch_attr+40>>>2>>>0];var onprogress=HEAPU32[fetch_attr+44>>>2>>>0];var onreadystatechange=HEAPU32[fetch_attr+48>>>2>>>0];var fetchAttributes=HEAPU32[fetch_attr+52>>>2>>>0];var fetchAttrSynchronous=!!(fetchAttributes&64);function doCallback(f){if(fetchAttrSynchronous){f()}else{callUserCallback(f)}}var reportSuccess=(fetch,xhr,e)=>{doCallback(()=>{if(onsuccess)getWasmTableEntry(onsuccess)(fetch);else successcb?.(fetch)})};var reportProgress=(fetch,xhr,e)=>{doCallback(()=>{if(onprogress)getWasmTableEntry(onprogress)(fetch);else progresscb?.(fetch)})};var reportError=(fetch,xhr,e)=>{doCallback(()=>{if(onerror)getWasmTableEntry(onerror)(fetch);else errorcb?.(fetch)})};var reportReadyStateChange=(fetch,xhr,e)=>{doCallback(()=>{if(onreadystatechange)getWasmTableEntry(onreadystatechange)(fetch);else readystatechangecb?.(fetch)})};var performUncachedXhr=(fetch,xhr,e)=>{fetchXHR(fetch,reportSuccess,reportError,reportProgress,reportReadyStateChange)};var cacheResultAndReportSuccess=(fetch,xhr,e)=>{var storeSuccess=(fetch,xhr,e)=>{doCallback(()=>{if(onsuccess)getWasmTableEntry(onsuccess)(fetch);else successcb?.(fetch)})};var storeError=(fetch,xhr,e)=>{doCallback(()=>{if(onsuccess)getWasmTableEntry(onsuccess)(fetch);else successcb?.(fetch)})};fetchCacheData(Fetch.dbInstance,fetch,xhr.response,storeSuccess,storeError)};var performCachedXhr=(fetch,xhr,e)=>{fetchXHR(fetch,cacheResultAndReportSuccess,reportError,reportProgress,reportReadyStateChange)};var requestMethod=UTF8ToString(fetch_attr+0);var fetchAttrReplace=!!(fetchAttributes&16);var fetchAttrPersistFile=!!(fetchAttributes&4);var fetchAttrNoDownload=!!(fetchAttributes&32);if(requestMethod==="EM_IDB_STORE"){var ptr=HEAPU32[fetch_attr+84>>>2>>>0];var size=HEAPU32[fetch_attr+88>>>2>>>0];fetchCacheData(Fetch.dbInstance,fetch,HEAPU8.slice(ptr,ptr+size),reportSuccess,reportError)}else if(requestMethod==="EM_IDB_DELETE"){fetchDeleteCachedData(Fetch.dbInstance,fetch,reportSuccess,reportError)}else if(!fetchAttrReplace){fetchLoadCachedData(Fetch.dbInstance,fetch,reportSuccess,fetchAttrNoDownload?reportError:fetchAttrPersistFile?performCachedXhr:performUncachedXhr)}else if(!fetchAttrNoDownload){fetchXHR(fetch,fetchAttrPersistFile?cacheResultAndReportSuccess:reportSuccess,reportError,reportProgress,reportReadyStateChange)}else{return 0}return fetch}var GLctx;var webgl_enable_ANGLE_instanced_arrays=ctx=>{var ext=ctx.getExtension("ANGLE_instanced_arrays");if(ext){ctx["vertexAttribDivisor"]=(index,divisor)=>ext["vertexAttribDivisorANGLE"](index,divisor);ctx["drawArraysInstanced"]=(mode,first,count,primcount)=>ext["drawArraysInstancedANGLE"](mode,first,count,primcount);ctx["drawElementsInstanced"]=(mode,count,type,indices,primcount)=>ext["drawElementsInstancedANGLE"](mode,count,type,indices,primcount);return 1}};var webgl_enable_OES_vertex_array_object=ctx=>{var ext=ctx.getExtension("OES_vertex_array_object");if(ext){ctx["createVertexArray"]=()=>ext["createVertexArrayOES"]();ctx["deleteVertexArray"]=vao=>ext["deleteVertexArrayOES"](vao);ctx["bindVertexArray"]=vao=>ext["bindVertexArrayOES"](vao);ctx["isVertexArray"]=vao=>ext["isVertexArrayOES"](vao);return 1}};var webgl_enable_WEBGL_draw_buffers=ctx=>{var ext=ctx.getExtension("WEBGL_draw_buffers");if(ext){ctx["drawBuffers"]=(n,bufs)=>ext["drawBuffersWEBGL"](n,bufs);return 1}};var webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance=ctx=>!!(ctx.dibvbi=ctx.getExtension("WEBGL_draw_instanced_base_vertex_base_instance"));var webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance=ctx=>!!(ctx.mdibvbi=ctx.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance"));var webgl_enable_EXT_polygon_offset_clamp=ctx=>!!(ctx.extPolygonOffsetClamp=ctx.getExtension("EXT_polygon_offset_clamp"));var webgl_enable_EXT_clip_control=ctx=>!!(ctx.extClipControl=ctx.getExtension("EXT_clip_control"));var webgl_enable_WEBGL_polygon_mode=ctx=>!!(ctx.webglPolygonMode=ctx.getExtension("WEBGL_polygon_mode"));var webgl_enable_WEBGL_multi_draw=ctx=>!!(ctx.multiDrawWebgl=ctx.getExtension("WEBGL_multi_draw"));var getEmscriptenSupportedExtensions=ctx=>{var supportedExtensions=["ANGLE_instanced_arrays","EXT_blend_minmax","EXT_disjoint_timer_query","EXT_frag_depth","EXT_shader_texture_lod","EXT_sRGB","OES_element_index_uint","OES_fbo_render_mipmap","OES_standard_derivatives","OES_texture_float","OES_texture_half_float","OES_texture_half_float_linear","OES_vertex_array_object","WEBGL_color_buffer_float","WEBGL_depth_texture","WEBGL_draw_buffers","EXT_color_buffer_float","EXT_conservative_depth","EXT_disjoint_timer_query_webgl2","EXT_texture_norm16","NV_shader_noperspective_interpolation","WEBGL_clip_cull_distance","EXT_clip_control","EXT_color_buffer_half_float","EXT_depth_clamp","EXT_float_blend","EXT_polygon_offset_clamp","EXT_texture_compression_bptc","EXT_texture_compression_rgtc","EXT_texture_filter_anisotropic","KHR_parallel_shader_compile","OES_texture_float_linear","WEBGL_blend_func_extended","WEBGL_compressed_texture_astc","WEBGL_compressed_texture_etc","WEBGL_compressed_texture_etc1","WEBGL_compressed_texture_s3tc","WEBGL_compressed_texture_s3tc_srgb","WEBGL_debug_renderer_info","WEBGL_debug_shaders","WEBGL_lose_context","WEBGL_multi_draw","WEBGL_polygon_mode"];return(ctx.getSupportedExtensions()||[]).filter(ext=>supportedExtensions.includes(ext))};var GL={counter:1,buffers:[],programs:[],framebuffers:[],renderbuffers:[],textures:[],shaders:[],vaos:[],contexts:[],offscreenCanvases:{},queries:[],samplers:[],transformFeedbacks:[],syncs:[],stringCache:{},stringiCache:{},unpackAlignment:4,unpackRowLength:0,recordError:errorCode=>{if(!GL.lastError){GL.lastError=errorCode}},getNewId:table=>{var ret=GL.counter++;for(var i=table.length;i{for(var i=0;i>>2>>>0]=id}},getSource:(shader,count,string,length)=>{var source="";for(var i=0;i>>2>>>0]:undefined;source+=UTF8ToString(HEAPU32[string+i*4>>>2>>>0],len)}return source},createContext:(canvas,webGLContextAttributes)=>{var ctx=webGLContextAttributes.majorVersion>1?canvas.getContext("webgl2",webGLContextAttributes):canvas.getContext("webgl",webGLContextAttributes);if(!ctx)return 0;var handle=GL.registerContext(ctx,webGLContextAttributes);return handle},registerContext:(ctx,webGLContextAttributes)=>{var handle=GL.getNewId(GL.contexts);var context={handle,attributes:webGLContextAttributes,version:webGLContextAttributes.majorVersion,GLctx:ctx};if(ctx.canvas)ctx.canvas.GLctxObject=context;GL.contexts[handle]=context;if(typeof webGLContextAttributes.enableExtensionsByDefault=="undefined"||webGLContextAttributes.enableExtensionsByDefault){GL.initExtensions(context)}return handle},makeContextCurrent:contextHandle=>{GL.currentContext=GL.contexts[contextHandle];Module["ctx"]=GLctx=GL.currentContext?.GLctx;return!(contextHandle&&!GLctx)},getContext:contextHandle=>GL.contexts[contextHandle],deleteContext:contextHandle=>{if(GL.currentContext===GL.contexts[contextHandle]){GL.currentContext=null}if(typeof JSEvents=="object"){JSEvents.removeAllHandlersOnTarget(GL.contexts[contextHandle].GLctx.canvas)}if(GL.contexts[contextHandle]&&GL.contexts[contextHandle].GLctx.canvas){GL.contexts[contextHandle].GLctx.canvas.GLctxObject=undefined}GL.contexts[contextHandle]=null},initExtensions:context=>{context||=GL.currentContext;if(context.initExtensionsDone)return;context.initExtensionsDone=true;var GLctx=context.GLctx;webgl_enable_WEBGL_multi_draw(GLctx);webgl_enable_EXT_polygon_offset_clamp(GLctx);webgl_enable_EXT_clip_control(GLctx);webgl_enable_WEBGL_polygon_mode(GLctx);webgl_enable_ANGLE_instanced_arrays(GLctx);webgl_enable_OES_vertex_array_object(GLctx);webgl_enable_WEBGL_draw_buffers(GLctx);webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx);webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx);if(context.version>=2){GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query_webgl2")}if(context.version<2||!GLctx.disjointTimerQueryExt){GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query")}getEmscriptenSupportedExtensions(GLctx).forEach(ext=>{if(!ext.includes("lose_context")&&!ext.includes("debug")){GLctx.getExtension(ext)}})}};var JSEvents={memcpy(target,src,size){HEAP8.set(HEAP8.subarray(src>>>0,src+size>>>0),target>>>0)},removeAllEventListeners(){while(JSEvents.eventHandlers.length){JSEvents._removeHandler(JSEvents.eventHandlers.length-1)}JSEvents.deferredCalls=[]},inEventHandler:0,deferredCalls:[],deferCall(targetFunction,precedence,argsList){function arraysHaveEqualContent(arrA,arrB){if(arrA.length!=arrB.length)return false;for(var i in arrA){if(arrA[i]!=arrB[i])return false}return true}for(var call of JSEvents.deferredCalls){if(call.targetFunction==targetFunction&&arraysHaveEqualContent(call.argsList,argsList)){return}}JSEvents.deferredCalls.push({targetFunction,precedence,argsList});JSEvents.deferredCalls.sort((x,y)=>x.precedencecall.targetFunction!=targetFunction)},canPerformEventHandlerRequests(){if(navigator.userActivation){return navigator.userActivation.isActive}return JSEvents.inEventHandler&&JSEvents.currentEventHandler.allowsDeferredCalls},runDeferredCalls(){if(!JSEvents.canPerformEventHandlerRequests()){return}var deferredCalls=JSEvents.deferredCalls;JSEvents.deferredCalls=[];for(var call of deferredCalls){call.targetFunction(...call.argsList)}},eventHandlers:[],removeAllHandlersOnTarget:(target,eventTypeString)=>{for(var i=0;icString>2?UTF8ToString(cString):cString;var specialHTMLTargets=[0,document,window];var findEventTarget=target=>{target=maybeCStringToJsString(target);var domElement=specialHTMLTargets[target]||document.querySelector(target);return domElement};var findCanvasEventTarget=findEventTarget;function _emscripten_webgl_do_create_context(target,attributes){target>>>=0;attributes>>>=0;var attr32=attributes>>>2;var powerPreference=HEAP32[attr32+(8>>2)>>>0];var contextAttributes={alpha:!!HEAP8[attributes+0>>>0],depth:!!HEAP8[attributes+1>>>0],stencil:!!HEAP8[attributes+2>>>0],antialias:!!HEAP8[attributes+3>>>0],premultipliedAlpha:!!HEAP8[attributes+4>>>0],preserveDrawingBuffer:!!HEAP8[attributes+5>>>0],powerPreference:webglPowerPreferences[powerPreference],failIfMajorPerformanceCaveat:!!HEAP8[attributes+12>>>0],majorVersion:HEAP32[attr32+(16>>2)>>>0],minorVersion:HEAP32[attr32+(20>>2)>>>0],enableExtensionsByDefault:HEAP8[attributes+24>>>0],explicitSwapControl:HEAP8[attributes+25>>>0],proxyContextToMainThread:HEAP32[attr32+(28>>2)>>>0],renderViaOffscreenBackBuffer:HEAP8[attributes+32>>>0]};var canvas=findCanvasEventTarget(target);if(!canvas){return 0}if(contextAttributes.explicitSwapControl){return 0}var contextHandle=GL.createContext(canvas,contextAttributes);return contextHandle}var _emscripten_webgl_create_context=_emscripten_webgl_do_create_context;function _emscripten_webgl_do_get_current_context(){return GL.currentContext?GL.currentContext.handle:0}var _emscripten_webgl_get_current_context=_emscripten_webgl_do_get_current_context;function _emscripten_webgl_make_context_current(contextHandle){contextHandle>>>=0;var success=GL.makeContextCurrent(contextHandle);return success?0:-5}var ENV={};var getExecutableName=()=>thisProgram||"./this.program";var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:lang,_:getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`)}getEnvStrings.strings=strings}return getEnvStrings.strings};var stringToAscii=(str,buffer)=>{for(var i=0;i>>0]=str.charCodeAt(i)}HEAP8[buffer>>>0]=0};var _environ_get=function(__environ,environ_buf){__environ>>>=0;environ_buf>>>=0;var bufSize=0;getEnvStrings().forEach((string,i)=>{var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>>2>>>0]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1});return 0};var _environ_sizes_get=function(penviron_count,penviron_buf_size){penviron_count>>>=0;penviron_buf_size>>>=0;var strings=getEnvStrings();HEAPU32[penviron_count>>>2>>>0]=strings.length;var bufSize=0;strings.forEach(string=>bufSize+=string.length+1);HEAPU32[penviron_buf_size>>>2>>>0]=bufSize;return 0};function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>>2>>>0];var len=HEAPU32[iov+4>>>2>>>0];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>>=0;iovcnt>>>=0;pnum>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doReadv(stream,iov,iovcnt);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){var offset=convertI32PairToI53Checked(offset_low,offset_high);newOffset>>>=0;try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>>2>>>0]=tempI64[0],HEAP32[newOffset+4>>>2>>>0]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>>2>>>0];var len=HEAPU32[iov+4>>>2>>>0];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>>=0;iovcnt>>>=0;pnum>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var _glActiveTexture=x0=>GLctx.activeTexture(x0);var _glAttachShader=(program,shader)=>{GLctx.attachShader(GL.programs[program],GL.shaders[shader])};function _glBindAttribLocation(program,index,name){name>>>=0;GLctx.bindAttribLocation(GL.programs[program],index,UTF8ToString(name))}var _glBindBuffer=(target,buffer)=>{if(target==35051){GLctx.currentPixelPackBufferBinding=buffer}else if(target==35052){GLctx.currentPixelUnpackBufferBinding=buffer}GLctx.bindBuffer(target,GL.buffers[buffer])};var _glBindBufferBase=(target,index,buffer)=>{GLctx.bindBufferBase(target,index,GL.buffers[buffer])};var _glBindFramebuffer=(target,framebuffer)=>{GLctx.bindFramebuffer(target,GL.framebuffers[framebuffer])};var _glBindTexture=(target,texture)=>{GLctx.bindTexture(target,GL.textures[texture])};var _glBlendColor=(x0,x1,x2,x3)=>GLctx.blendColor(x0,x1,x2,x3);var _glBlendEquation=x0=>GLctx.blendEquation(x0);var _glBlendFuncSeparate=(x0,x1,x2,x3)=>GLctx.blendFuncSeparate(x0,x1,x2,x3);function _glBufferData(target,size,data,usage){size>>>=0;data>>>=0;GLctx.bufferData(target,data?HEAPU8.subarray(data>>>0,data+size>>>0):size,usage)}function _glBufferSubData(target,offset,size,data){offset>>>=0;size>>>=0;data>>>=0;GLctx.bufferSubData(target,offset,HEAPU8.subarray(data>>>0,data+size>>>0))}var _glCheckFramebufferStatus=x0=>GLctx.checkFramebufferStatus(x0);var _glClear=x0=>GLctx.clear(x0);var _glClearColor=(x0,x1,x2,x3)=>GLctx.clearColor(x0,x1,x2,x3);var _glColorMask=(red,green,blue,alpha)=>{GLctx.colorMask(!!red,!!green,!!blue,!!alpha)};var _glCompileShader=shader=>{GLctx.compileShader(GL.shaders[shader])};function _glCompressedTexImage2D(target,level,internalFormat,width,height,border,imageSize,data){data>>>=0;if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding||!imageSize){GLctx.compressedTexImage2D(target,level,internalFormat,width,height,border,imageSize,data);return}}GLctx.compressedTexImage2D(target,level,internalFormat,width,height,border,HEAPU8.subarray(data>>>0,data+imageSize>>>0))}var _glCreateProgram=()=>{var id=GL.getNewId(GL.programs);var program=GLctx.createProgram();program.name=id;program.maxUniformLength=program.maxAttributeLength=program.maxUniformBlockNameLength=0;program.uniformIdCounter=1;GL.programs[id]=program;return id};var _glCreateShader=shaderType=>{var id=GL.getNewId(GL.shaders);GL.shaders[id]=GLctx.createShader(shaderType);return id};var _glCullFace=x0=>GLctx.cullFace(x0);function _glDeleteBuffers(n,buffers){buffers>>>=0;for(var i=0;i>>2>>>0];var buffer=GL.buffers[id];if(!buffer)continue;GLctx.deleteBuffer(buffer);buffer.name=0;GL.buffers[id]=null;if(id==GLctx.currentPixelPackBufferBinding)GLctx.currentPixelPackBufferBinding=0;if(id==GLctx.currentPixelUnpackBufferBinding)GLctx.currentPixelUnpackBufferBinding=0}}function _glDeleteFramebuffers(n,framebuffers){framebuffers>>>=0;for(var i=0;i>>2>>>0];var framebuffer=GL.framebuffers[id];if(!framebuffer)continue;GLctx.deleteFramebuffer(framebuffer);framebuffer.name=0;GL.framebuffers[id]=null}}var _glDeleteProgram=id=>{if(!id)return;var program=GL.programs[id];if(!program){GL.recordError(1281);return}GLctx.deleteProgram(program);program.name=0;GL.programs[id]=null};function _glDeleteRenderbuffers(n,renderbuffers){renderbuffers>>>=0;for(var i=0;i>>2>>>0];var renderbuffer=GL.renderbuffers[id];if(!renderbuffer)continue;GLctx.deleteRenderbuffer(renderbuffer);renderbuffer.name=0;GL.renderbuffers[id]=null}}var _glDeleteShader=id=>{if(!id)return;var shader=GL.shaders[id];if(!shader){GL.recordError(1281);return}GLctx.deleteShader(shader);GL.shaders[id]=null};function _glDeleteTextures(n,textures){textures>>>=0;for(var i=0;i>>2>>>0];var texture=GL.textures[id];if(!texture)continue;GLctx.deleteTexture(texture);texture.name=0;GL.textures[id]=null}}var _glDepthFunc=x0=>GLctx.depthFunc(x0);var _glDepthMask=flag=>{GLctx.depthMask(!!flag)};var _glDetachShader=(program,shader)=>{GLctx.detachShader(GL.programs[program],GL.shaders[shader])};var _glDisable=x0=>GLctx.disable(x0);var _glDisableVertexAttribArray=index=>{GLctx.disableVertexAttribArray(index)};var _glDrawArrays=(mode,first,count)=>{GLctx.drawArrays(mode,first,count)};function _glDrawElements(mode,count,type,indices){indices>>>=0;GLctx.drawElements(mode,count,type,indices)}function _glDrawElementsInstanced(mode,count,type,indices,primcount){indices>>>=0;GLctx.drawElementsInstanced(mode,count,type,indices,primcount)}var _glEnable=x0=>GLctx.enable(x0);var _glEnableVertexAttribArray=index=>{GLctx.enableVertexAttribArray(index)};var _glFramebufferTexture2D=(target,attachment,textarget,texture,level)=>{GLctx.framebufferTexture2D(target,attachment,textarget,GL.textures[texture],level)};var _glFrontFace=x0=>GLctx.frontFace(x0);function _glGenBuffers(n,buffers){buffers>>>=0;GL.genObject(n,buffers,"createBuffer",GL.buffers)}function _glGenFramebuffers(n,ids){ids>>>=0;GL.genObject(n,ids,"createFramebuffer",GL.framebuffers)}function _glGenTextures(n,textures){textures>>>=0;GL.genObject(n,textures,"createTexture",GL.textures)}var _glGenerateMipmap=x0=>GLctx.generateMipmap(x0);var __glGetActiveAttribOrUniform=(funcName,program,index,bufSize,length,size,type,name)=>{program=GL.programs[program];var info=GLctx[funcName](program,index);if(info){var numBytesWrittenExclNull=name&&stringToUTF8(info.name,name,bufSize);if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull;if(size)HEAP32[size>>>2>>>0]=info.size;if(type)HEAP32[type>>>2>>>0]=info.type}};function _glGetActiveUniform(program,index,bufSize,length,size,type,name){length>>>=0;size>>>=0;type>>>=0;name>>>=0;return __glGetActiveAttribOrUniform("getActiveUniform",program,index,bufSize,length,size,type,name)}var webglGetExtensions=()=>{var exts=getEmscriptenSupportedExtensions(GLctx);exts=exts.concat(exts.map(e=>"GL_"+e));return exts};var emscriptenWebGLGet=(name_,p,type)=>{if(!p){GL.recordError(1281);return}var ret=undefined;switch(name_){case 36346:ret=1;break;case 36344:if(type!=0&&type!=1){GL.recordError(1280)}return;case 34814:case 36345:ret=0;break;case 34466:var formats=GLctx.getParameter(34467);ret=formats?formats.length:0;break;case 33309:if(GL.currentContext.version<2){GL.recordError(1282);return}ret=webglGetExtensions().length;break;case 33307:case 33308:if(GL.currentContext.version<2){GL.recordError(1280);return}ret=name_==33307?3:0;break}if(ret===undefined){var result=GLctx.getParameter(name_);switch(typeof result){case"number":ret=result;break;case"boolean":ret=result?1:0;break;case"string":GL.recordError(1280);return;case"object":if(result===null){switch(name_){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 36662:case 36663:case 35053:case 35055:case 36010:case 35097:case 35869:case 32874:case 36389:case 35983:case 35368:case 34068:{ret=0;break}default:{GL.recordError(1280);return}}}else if(result instanceof Float32Array||result instanceof Uint32Array||result instanceof Int32Array||result instanceof Array){for(var i=0;i>>2>>>0]=result[i];break;case 2:HEAPF32[p+i*4>>>2>>>0]=result[i];break;case 4:HEAP8[p+i>>>0]=result[i]?1:0;break}}return}else{try{ret=result.name|0}catch(e){GL.recordError(1280);err(`GL_INVALID_ENUM in glGet${type}v: Unknown object returned from WebGL getParameter(${name_})! (error: ${e})`);return}}break;default:GL.recordError(1280);err(`GL_INVALID_ENUM in glGet${type}v: Native code calling glGet${type}v(${name_}) and it returns ${result} of type ${typeof result}!`);return}}switch(type){case 1:writeI53ToI64(p,ret);break;case 0:HEAP32[p>>>2>>>0]=ret;break;case 2:HEAPF32[p>>>2>>>0]=ret;break;case 4:HEAP8[p>>>0]=ret?1:0;break}};function _glGetIntegerv(name_,p){p>>>=0;return emscriptenWebGLGet(name_,p,0)}function _glGetProgramInfoLog(program,maxLength,length,infoLog){length>>>=0;infoLog>>>=0;var log=GLctx.getProgramInfoLog(GL.programs[program]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}function _glGetProgramiv(program,pname,p){p>>>=0;if(!p){GL.recordError(1281);return}if(program>=GL.counter){GL.recordError(1281);return}program=GL.programs[program];if(pname==35716){var log=GLctx.getProgramInfoLog(program);if(log===null)log="(unknown error)";HEAP32[p>>>2>>>0]=log.length+1}else if(pname==35719){if(!program.maxUniformLength){var numActiveUniforms=GLctx.getProgramParameter(program,35718);for(var i=0;i>>2>>>0]=program.maxUniformLength}else if(pname==35722){if(!program.maxAttributeLength){var numActiveAttributes=GLctx.getProgramParameter(program,35721);for(var i=0;i>>2>>>0]=program.maxAttributeLength}else if(pname==35381){if(!program.maxUniformBlockNameLength){var numActiveUniformBlocks=GLctx.getProgramParameter(program,35382);for(var i=0;i>>2>>>0]=program.maxUniformBlockNameLength}else{HEAP32[p>>>2>>>0]=GLctx.getProgramParameter(program,pname)}}function _glGetShaderInfoLog(shader,maxLength,length,infoLog){length>>>=0;infoLog>>>=0;var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}function _glGetShaderiv(shader,pname,p){p>>>=0;if(!p){GL.recordError(1281);return}if(pname==35716){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var logLength=log?log.length+1:0;HEAP32[p>>>2>>>0]=logLength}else if(pname==35720){var source=GLctx.getShaderSource(GL.shaders[shader]);var sourceLength=source?source.length+1:0;HEAP32[p>>>2>>>0]=sourceLength}else{HEAP32[p>>>2>>>0]=GLctx.getShaderParameter(GL.shaders[shader],pname)}}var stringToNewUTF8=str=>{var size=lengthBytesUTF8(str)+1;var ret=_malloc(size);if(ret)stringToUTF8(str,ret,size);return ret};function _glGetString(name_){var ret=GL.stringCache[name_];if(!ret){switch(name_){case 7939:ret=stringToNewUTF8(webglGetExtensions().join(" "));break;case 7936:case 7937:case 37445:case 37446:var s=GLctx.getParameter(name_);if(!s){GL.recordError(1280)}ret=s?stringToNewUTF8(s):0;break;case 7938:var webGLVersion=GLctx.getParameter(7938);var glVersion=`OpenGL ES 2.0 (${webGLVersion})`;if(GL.currentContext.version>=2)glVersion=`OpenGL ES 3.0 (${webGLVersion})`;ret=stringToNewUTF8(glVersion);break;case 35724:var glslVersion=GLctx.getParameter(35724);var ver_re=/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/;var ver_num=glslVersion.match(ver_re);if(ver_num!==null){if(ver_num[1].length==3)ver_num[1]=ver_num[1]+"0";glslVersion=`OpenGL ES GLSL ES ${ver_num[1]} (${glslVersion})`}ret=stringToNewUTF8(glslVersion);break;default:GL.recordError(1280)}GL.stringCache[name_]=ret}return ret}function _glGetUniformBlockIndex(program,uniformBlockName){uniformBlockName>>>=0;return GLctx.getUniformBlockIndex(GL.programs[program],UTF8ToString(uniformBlockName))}var jstoi_q=str=>parseInt(str);var webglGetLeftBracePos=name=>name.slice(-1)=="]"&&name.lastIndexOf("[");var webglPrepareUniformLocationsBeforeFirstUse=program=>{var uniformLocsById=program.uniformLocsById,uniformSizeAndIdsByName=program.uniformSizeAndIdsByName,i,j;if(!uniformLocsById){program.uniformLocsById=uniformLocsById={};program.uniformArrayNamesById={};var numActiveUniforms=GLctx.getProgramParameter(program,35718);for(i=0;i0?nm.slice(0,lb):nm;var id=program.uniformIdCounter;program.uniformIdCounter+=sz;uniformSizeAndIdsByName[arrayName]=[sz,id];for(j=0;j>>=0;name=UTF8ToString(name);if(program=GL.programs[program]){webglPrepareUniformLocationsBeforeFirstUse(program);var uniformLocsById=program.uniformLocsById;var arrayIndex=0;var uniformBaseName=name;var leftBrace=webglGetLeftBracePos(name);if(leftBrace>0){arrayIndex=jstoi_q(name.slice(leftBrace+1))>>>0;uniformBaseName=name.slice(0,leftBrace)}var sizeAndId=program.uniformSizeAndIdsByName[uniformBaseName];if(sizeAndId&&arrayIndex{program=GL.programs[program];GLctx.linkProgram(program);program.uniformLocsById=0;program.uniformSizeAndIdsByName={}};var _glPixelStorei=(pname,param)=>{if(pname==3317){GL.unpackAlignment=param}else if(pname==3314){GL.unpackRowLength=param}GLctx.pixelStorei(pname,param)};var computeUnpackAlignedImageSize=(width,height,sizePerPixel)=>{function roundedToNextMultipleOf(x,y){return x+y-1&-y}var plainRowSize=(GL.unpackRowLength||width)*sizePerPixel;var alignedRowSize=roundedToNextMultipleOf(plainRowSize,GL.unpackAlignment);return height*alignedRowSize};var colorChannelsInGlTextureFormat=format=>{var colorChannels={5:3,6:4,8:2,29502:3,29504:4,26917:2,26918:2,29846:3,29847:4};return colorChannels[format-6402]||1};var heapObjectForWebGLType=type=>{type-=5120;if(type==0)return HEAP8;if(type==1)return HEAPU8;if(type==2)return HEAP16;if(type==4)return HEAP32;if(type==6)return HEAPF32;if(type==5||type==28922||type==28520||type==30779||type==30782)return HEAPU32;return HEAPU16};var toTypedArrayIndex=(pointer,heap)=>pointer>>>31-Math.clz32(heap.BYTES_PER_ELEMENT);var emscriptenWebGLGetTexPixelData=(type,format,width,height,pixels,internalFormat)=>{var heap=heapObjectForWebGLType(type);var sizePerPixel=colorChannelsInGlTextureFormat(format)*heap.BYTES_PER_ELEMENT;var bytes=computeUnpackAlignedImageSize(width,height,sizePerPixel);return heap.subarray(toTypedArrayIndex(pixels,heap)>>>0,toTypedArrayIndex(pixels+bytes,heap)>>>0)};function _glReadPixels(x,y,width,height,format,type,pixels){pixels>>>=0;if(GL.currentContext.version>=2){if(GLctx.currentPixelPackBufferBinding){GLctx.readPixels(x,y,width,height,format,type,pixels);return}}var pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,format);if(!pixelData){GL.recordError(1280);return}GLctx.readPixels(x,y,width,height,format,type,pixelData)}var _glScissor=(x0,x1,x2,x3)=>GLctx.scissor(x0,x1,x2,x3);function _glShaderSource(shader,count,string,length){string>>>=0;length>>>=0;var source=GL.getSource(shader,count,string,length);GLctx.shaderSource(GL.shaders[shader],source)}function _glTexImage2D(target,level,internalFormat,width,height,border,format,type,pixels){pixels>>>=0;if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels);return}}var pixelData=pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat):null;GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixelData)}var _glTexParameteri=(x0,x1,x2)=>GLctx.texParameteri(x0,x1,x2);var webglGetUniformLocation=location=>{var p=GLctx.currentProgram;if(p){var webglLoc=p.uniformLocsById[location];if(typeof webglLoc=="number"){p.uniformLocsById[location]=webglLoc=GLctx.getUniformLocation(p,p.uniformArrayNamesById[location]+(webglLoc>0?`[${webglLoc}]`:""))}return webglLoc}else{GL.recordError(1282)}};var _glUniform1i=(location,v0)=>{GLctx.uniform1i(webglGetUniformLocation(location),v0)};var _glUniformBlockBinding=(program,uniformBlockIndex,uniformBlockBinding)=>{program=GL.programs[program];GLctx.uniformBlockBinding(program,uniformBlockIndex,uniformBlockBinding)};var _glUseProgram=program=>{program=GL.programs[program];GLctx.useProgram(program);GLctx.currentProgram=program};var _glVertexAttribDivisor=(index,divisor)=>{GLctx.vertexAttribDivisor(index,divisor)};function _glVertexAttribPointer(index,size,type,normalized,stride,ptr){ptr>>>=0;GLctx.vertexAttribPointer(index,size,type,!!normalized,stride,ptr)}var _glViewport=(x0,x1,x2,x3)=>GLctx.viewport(x0,x1,x2,x3);var stackAlloc=sz=>__emscripten_stack_alloc(sz);var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var getCFunc=ident=>{var func=Module["_"+ident];return func};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer>>>0)};var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={string:str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},array:arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return(...args)=>ccall(ident,returnType,argTypes,args,opts)};FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();MEMFS.doesNotExistError=new FS.ErrnoError(44);MEMFS.doesNotExistError.stack="";BindingError=Module["BindingError"]=class BindingError extends Error{constructor(message){super(message);this.name="BindingError"}};init_emval();PureVirtualError=Module["PureVirtualError"]=extendError(Error,"PureVirtualError");embind_init_charCodes();InternalError=Module["InternalError"]=class InternalError extends Error{constructor(message){super(message);this.name="InternalError"}};init_ClassHandle();init_RegisteredPointer();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");Module["requestAnimationFrame"]=MainLoop.requestAnimationFrame;Module["pauseMainLoop"]=MainLoop.pause;Module["resumeMainLoop"]=MainLoop.resume;MainLoop.init();Fetch.init();var wasmImports={g:___cxa_throw,U:___syscall_fcntl64,ib:___syscall_ioctl,jb:___syscall_openat,gb:___syscall_stat64,W:__abort_js,$:__embind_create_inheriting_constructor,Za:__embind_register_bigint,Z:__embind_register_bool,c:__embind_register_class,f:__embind_register_class_class_function,d:__embind_register_class_constructor,a:__embind_register_class_function,b:__embind_register_class_property,X:__embind_register_emval,j:__embind_register_enum,e:__embind_register_enum_value,H:__embind_register_float,i:__embind_register_function,o:__embind_register_integer,k:__embind_register_memory_view,Y:__embind_register_std_string,D:__embind_register_std_wstring,_:__embind_register_void,Ca:__emscripten_fetch_free,bb:__emscripten_throw_longjmp,u:__emval_call_method,ba:__emval_decref,t:__emval_get_method_caller,aa:__emval_run_destructors,r:__emval_take_value,Wa:__localtime_js,db:__tzset_js,Ya:_clock_time_get,K:_emscripten_asm_const_int,wa:_emscripten_cancel_main_loop,kb:_emscripten_force_exit,Sa:_emscripten_is_main_browser_thread,cb:_emscripten_resize_heap,na:_emscripten_set_main_loop,La:_emscripten_start_fetch,J:_emscripten_webgl_create_context,ha:_emscripten_webgl_get_current_context,I:_emscripten_webgl_make_context_current,eb:_environ_get,fb:_environ_sizes_get,V:_fd_close,hb:_fd_read,Xa:_fd_seek,T:_fd_write,ca:get_host,ra:_glActiveTexture,P:_glAttachShader,l:_glBindAttribLocation,m:_glBindBuffer,ua:_glBindBufferBase,s:_glBindFramebuffer,q:_glBindTexture,Ka:_glBlendColor,Ja:_glBlendEquation,Ma:_glBlendFuncSeparate,w:_glBufferData,da:_glBufferSubData,L:_glCheckFramebufferStatus,Ta:_glClear,Ua:_glClearColor,Ga:_glColorMask,oa:_glCompileShader,B:_glCompressedTexImage2D,Ba:_glCreateProgram,qa:_glCreateShader,Qa:_glCullFace,S:_glDeleteBuffers,Ea:_glDeleteFramebuffers,Q:_glDeleteProgram,Da:_glDeleteRenderbuffers,O:_glDeleteShader,Fa:_glDeleteTextures,Na:_glDepthFunc,Oa:_glDepthMask,R:_glDetachShader,z:_glDisable,Ra:_glDisableVertexAttribArray,fa:_glDrawArrays,ga:_glDrawElements,ea:_glDrawElementsInstanced,y:_glEnable,ka:_glEnableVertexAttribArray,E:_glFramebufferTexture2D,Pa:_glFrontFace,x:_glGenBuffers,M:_glGenFramebuffers,C:_glGenTextures,Va:_glGenerateMipmap,xa:_glGetActiveUniform,p:_glGetIntegerv,za:_glGetProgramInfoLog,F:_glGetProgramiv,ma:_glGetShaderInfoLog,N:_glGetShaderiv,v:_glGetString,ya:_glGetUniformBlockIndex,va:_glGetUniformLocation,Aa:_glLinkProgram,la:_glPixelStorei,Ia:_glReadPixels,Ha:_glScissor,pa:_glShaderSource,n:_glTexImage2D,h:_glTexParameteri,sa:_glUniform1i,ta:_glUniformBlockBinding,G:_glUseProgram,ia:_glVertexAttribDivisor,ja:_glVertexAttribPointer,A:_glViewport,$a:invoke_iii,ab:invoke_iiii,_a:invoke_iiiii};var wasmExports;createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["mb"])();var ___getTypeName=a0=>(___getTypeName=wasmExports["nb"])(a0);var _free=Module["_free"]=a0=>(_free=Module["_free"]=wasmExports["ob"])(a0);var _malloc=Module["_malloc"]=a0=>(_malloc=Module["_malloc"]=wasmExports["pb"])(a0);var _SCRTFillActiveTextureCharArray=Module["_SCRTFillActiveTextureCharArray"]=(a0,a1,a2)=>(_SCRTFillActiveTextureCharArray=Module["_SCRTFillActiveTextureCharArray"]=wasmExports["rb"])(a0,a1,a2);var _SCRTFillActiveTextureFloat=Module["_SCRTFillActiveTextureFloat"]=(a0,a1,a2)=>(_SCRTFillActiveTextureFloat=Module["_SCRTFillActiveTextureFloat"]=wasmExports["sb"])(a0,a1,a2);var _main=Module["_main"]=(a0,a1)=>(_main=Module["_main"]=wasmExports["tb"])(a0,a1);var _setThrew=Module["_setThrew"]=(a0,a1)=>(_setThrew=Module["_setThrew"]=wasmExports["ub"])(a0,a1);var __emscripten_stack_restore=a0=>(__emscripten_stack_restore=wasmExports["vb"])(a0);var __emscripten_stack_alloc=a0=>(__emscripten_stack_alloc=wasmExports["wb"])(a0);var _emscripten_stack_get_current=()=>(_emscripten_stack_get_current=wasmExports["xb"])();var dynCall_jiji=Module["dynCall_jiji"]=(a0,a1,a2,a3,a4)=>(dynCall_jiji=Module["dynCall_jiji"]=wasmExports["yb"])(a0,a1,a2,a3,a4);var dynCall_viijii=Module["dynCall_viijii"]=(a0,a1,a2,a3,a4,a5,a6)=>(dynCall_viijii=Module["dynCall_viijii"]=wasmExports["zb"])(a0,a1,a2,a3,a4,a5,a6);var dynCall_iiiiij=Module["dynCall_iiiiij"]=(a0,a1,a2,a3,a4,a5,a6)=>(dynCall_iiiiij=Module["dynCall_iiiiij"]=wasmExports["Ab"])(a0,a1,a2,a3,a4,a5,a6);var dynCall_iiiiijj=Module["dynCall_iiiiijj"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(dynCall_iiiiijj=Module["dynCall_iiiiijj"]=wasmExports["Bb"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);var dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9)=>(dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=wasmExports["Cb"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9);function invoke_iiii(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iii(index,a1,a2){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiii(index,a1,a2,a3,a4){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function applySignatureConversions(wasmExports){wasmExports=Object.assign({},wasmExports);var makeWrapper_pp=f=>a0=>f(a0)>>>0;var makeWrapper_p=f=>()=>f()>>>0;wasmExports["nb"]=makeWrapper_pp(wasmExports["nb"]);wasmExports["pb"]=makeWrapper_pp(wasmExports["pb"]);wasmExports["wb"]=makeWrapper_pp(wasmExports["wb"]);wasmExports["xb"]=makeWrapper_p(wasmExports["xb"]);return wasmExports}Module["callMain"]=callMain;Module["ccall"]=ccall;Module["cwrap"]=cwrap;Module["UTF8ToString"]=UTF8ToString;Module["stringToUTF8"]=stringToUTF8;Module["lengthBytesUTF8"]=lengthBytesUTF8;Module["specialHTMLTargets"]=specialHTMLTargets;var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function callMain(args=[]){var entryFunction=_main;args.unshift(thisProgram);var argc=args.length;var argv=stackAlloc((argc+1)*4);var argv_ptr=argv;args.forEach(arg=>{HEAPU32[argv_ptr>>>2>>>0]=stringToUTF8OnStack(arg);argv_ptr+=4});HEAPU32[argv_ptr>>>2>>>0]=0;try{var ret=entryFunction(argc,argv);exitJS(ret,true);return ret}catch(e){return handleException(e)}}function run(args=arguments_){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);Module["onRuntimeInitialized"]?.();if(shouldRunNow)callMain(args);postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(()=>{setTimeout(()=>Module["setStatus"](""),1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}var shouldRunNow=true;if(Module["noInitialRun"])shouldRunNow=false;run();if(GL){GL.getNewId=function(table){GL.counter++;var len=table.length;if(len===0){return 1}for(var i=1;i Module); diff --git a/frontend/public/scichart/scichart2d.wasm b/frontend/public/scichart/scichart2d.wasm deleted file mode 100644 index bd2d03e1..00000000 Binary files a/frontend/public/scichart/scichart2d.wasm and /dev/null differ diff --git a/frontend/public/scichart/scichart3d-nosimd.wasm b/frontend/public/scichart/scichart3d-nosimd.wasm deleted file mode 100644 index 0de5b849..00000000 Binary files a/frontend/public/scichart/scichart3d-nosimd.wasm and /dev/null differ diff --git a/frontend/public/scichart/scichart3d.js b/frontend/public/scichart/scichart3d.js deleted file mode 100644 index 4ee34f3d..00000000 --- a/frontend/public/scichart/scichart3d.js +++ /dev/null @@ -1,22 +0,0 @@ - -var Module = (() => { - var _scriptName = typeof document != 'undefined' ? document.currentScript?.src : undefined; - - return ( -function(moduleArg = {}) { - var moduleRtn; - -var Module=moduleArg;var readyPromiseResolve,readyPromiseReject;var readyPromise=new Promise((resolve,reject)=>{readyPromiseResolve=resolve;readyPromiseReject=reject});var ENVIRONMENT_IS_WEB=true;var ENVIRONMENT_IS_WORKER=false;var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var readAsync,readBinary;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptName){scriptDirectory=_scriptName}if(scriptDirectory.startsWith("blob:")){scriptDirectory=""}else{scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}{readAsync=async url=>{var response=await fetch(url,{credentials:"same-origin"});if(response.ok){return response.arrayBuffer()}throw new Error(response.status+" : "+response.url)}}}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.error.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];var wasmBinary=Module["wasmBinary"];var wasmMemory;var ABORT=false;var EXITSTATUS;var HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateMemoryViews(){var b=wasmMemory.buffer;Module["HEAP8"]=HEAP8=new Int8Array(b);Module["HEAP16"]=HEAP16=new Int16Array(b);Module["HEAPU8"]=HEAPU8=new Uint8Array(b);Module["HEAPU16"]=HEAPU16=new Uint16Array(b);Module["HEAP32"]=HEAP32=new Int32Array(b);Module["HEAPU32"]=HEAPU32=new Uint32Array(b);Module["HEAPF32"]=HEAPF32=new Float32Array(b);Module["HEAPF64"]=HEAPF64=new Float64Array(b)}var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.initialized)FS.init();FS.ignorePermissions=false;TTY.init();callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;Module["monitorRunDependencies"]?.(runDependencies)}function removeRunDependency(id){runDependencies--;Module["monitorRunDependencies"]?.(runDependencies);if(runDependencies==0){if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){Module["onAbort"]?.(what);what="Aborted("+what+")";err(what);ABORT=true;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";var isDataURI=filename=>filename.startsWith(dataURIPrefix);function findWasmBinary(){var f="scichart3d.wasm";if(!isDataURI(f)){return locateFile(f)}return f}var wasmBinaryFile;function getBinarySync(file){if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}throw"both async and sync fetching of the wasm failed"}async function getWasmBinary(binaryFile){if(!wasmBinary){try{var response=await readAsync(binaryFile);return new Uint8Array(response)}catch{}}return getBinarySync(binaryFile)}async function instantiateArrayBuffer(binaryFile,imports){try{var binary=await getWasmBinary(binaryFile);var instance=await WebAssembly.instantiate(binary,imports);return instance}catch(reason){err(`failed to asynchronously prepare wasm: ${reason}`);abort(reason)}}async function instantiateAsync(binary,binaryFile,imports){if(!binary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(binaryFile)&&typeof fetch=="function"){try{var response=fetch(binaryFile,{credentials:"same-origin"});var instantiationResult=await WebAssembly.instantiateStreaming(response,imports);return instantiationResult}catch(reason){err(`wasm streaming compile failed: ${reason}`);err("falling back to ArrayBuffer instantiation")}}return instantiateArrayBuffer(binaryFile,imports)}function getWasmImports(){return{a:wasmImports}}async function createWasm(){function receiveInstance(instance,module){wasmExports=instance.exports;wasmExports=applySignatureConversions(wasmExports);wasmMemory=wasmExports["nb"];updateMemoryViews();wasmTable=wasmExports["sb"];addOnInit(wasmExports["ob"]);removeRunDependency("wasm-instantiate");return wasmExports}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}var info=getWasmImports();if(Module["instantiateWasm"]){try{return Module["instantiateWasm"](info,receiveInstance)}catch(e){err(`Module.instantiateWasm callback failed with error: ${e}`);readyPromiseReject(e)}}wasmBinaryFile??=findWasmBinary();try{var result=await instantiateAsync(wasmBinary,wasmBinaryFile,info);receiveInstantiationResult(result);return result}catch(e){readyPromiseReject(e);return}}var tempDouble;var tempI64;var ASM_CONSTS={514398:()=>Module.getRandomValue(),514434:()=>{if(Module.getRandomValue===undefined){try{var window_="object"===typeof window?window:self;var crypto_=typeof window_.crypto!=="undefined"?window_.crypto:window_.msCrypto;var randomValuesStandard=function(){var buf=new Uint32Array(1);crypto_.getRandomValues(buf);return buf[0]>>>0};randomValuesStandard();Module.getRandomValue=randomValuesStandard}catch(e){try{var max=Math.pow(2,32);var randomValueNodeJS=function(){var r=Math.floor(Math.random()*Math.floor(max));return r>>>0};randomValueNodeJS();Module.getRandomValue=randomValueNodeJS}catch(e){throw"No secure random number generator found"}}}},514478:()=>Module.getRandomValue(),514514:()=>{if(Module.getRandomValue===undefined){try{var window_="object"===typeof window?window:self;var crypto_=typeof window_.crypto!=="undefined"?window_.crypto:window_.msCrypto;var randomValuesStandard=function(){var buf=new Uint32Array(1);crypto_.getRandomValues(buf);return buf[0]>>>0};randomValuesStandard();Module.getRandomValue=randomValuesStandard}catch(e){try{var max=Math.pow(2,32);var randomValueNodeJS=function(){var r=Math.floor(Math.random()*Math.floor(max));return r>>>0};randomValueNodeJS();Module.getRandomValue=randomValueNodeJS}catch(e){throw"No secure random number generator found"}}}}};function get_host(){var host="";if(typeof window!=="undefined"){host=window.location.hostname}else if(typeof process!=="undefined"){host="node"}var lengthBytes=lengthBytesUTF8(host)+1;var stringOnWasmHeap=_malloc(lengthBytes);stringToUTF8(host,stringOnWasmHeap,lengthBytes);return stringOnWasmHeap}class ExitStatus{name="ExitStatus";constructor(status){this.message=`Program terminated with exit(${status})`;this.status=status}}var callRuntimeCallbacks=callbacks=>{while(callbacks.length>0){callbacks.shift()(Module)}};var noExitRuntime=Module["noExitRuntime"]||true;var stackRestore=val=>__emscripten_stack_restore(val);var stackSave=()=>_emscripten_stack_get_current();class ExceptionInfo{constructor(excPtr){this.excPtr=excPtr;this.ptr=excPtr-24}set_type(type){HEAPU32[this.ptr+4>>>2>>>0]=type}get_type(){return HEAPU32[this.ptr+4>>>2>>>0]}set_destructor(destructor){HEAPU32[this.ptr+8>>>2>>>0]=destructor}get_destructor(){return HEAPU32[this.ptr+8>>>2>>>0]}set_caught(caught){caught=caught?1:0;HEAP8[this.ptr+12>>>0]=caught}get_caught(){return HEAP8[this.ptr+12>>>0]!=0}set_rethrown(rethrown){rethrown=rethrown?1:0;HEAP8[this.ptr+13>>>0]=rethrown}get_rethrown(){return HEAP8[this.ptr+13>>>0]!=0}init(type,destructor){this.set_adjusted_ptr(0);this.set_type(type);this.set_destructor(destructor)}set_adjusted_ptr(adjustedPtr){HEAPU32[this.ptr+16>>>2>>>0]=adjustedPtr}get_adjusted_ptr(){return HEAPU32[this.ptr+16>>>2>>>0]}}var exceptionLast=0;var uncaughtExceptionCount=0;var convertI32PairToI53Checked=(lo,hi)=>hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN;function ___cxa_throw(ptr,type,destructor){ptr>>>=0;type>>>=0;destructor>>>=0;var info=new ExceptionInfo(ptr);info.init(type,destructor);exceptionLast=ptr;uncaughtExceptionCount++;throw exceptionLast}var syscallGetVarargI=()=>{var ret=HEAP32[+SYSCALLS.varargs>>>2>>>0];SYSCALLS.varargs+=4;return ret};var syscallGetVarargP=syscallGetVarargI;var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:path=>{if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:(...paths)=>PATH.normalize(paths.join("/")),join2:(l,r)=>PATH.normalize(l+"/"+r)};var initRandomFill=()=>{if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){return view=>crypto.getRandomValues(view)}else abort("initRandomDevice")};var randomFill=view=>(randomFill=initRandomFill())(view);var PATH_FS={resolve:(...args)=>{var resolvedPath="",resolvedAbsolute=false;for(var i=args.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?args[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i{idx>>>=0;var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}var str="";while(idx>10,56320|ch&1023)}}return str};var FS_stdin_getChar_buffer=[];var lengthBytesUTF8=str=>{var len=0;for(var i=0;i=55296&&c<=57343){len+=4;++i}else{len+=3}}return len};var stringToUTF8Array=(str,heap,outIdx,maxBytesToWrite)=>{outIdx>>>=0;if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++>>>0]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++>>>0]=192|u>>6;heap[outIdx++>>>0]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++>>>0]=224|u>>12;heap[outIdx++>>>0]=128|u>>6&63;heap[outIdx++>>>0]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++>>>0]=240|u>>18;heap[outIdx++>>>0]=128|u>>12&63;heap[outIdx++>>>0]=128|u>>6&63;heap[outIdx++>>>0]=128|u&63}}heap[outIdx>>>0]=0;return outIdx-startIdx};function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var FS_stdin_getChar=()=>{if(!FS_stdin_getChar_buffer.length){var result=null;if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else{}if(!result){return null}FS_stdin_getChar_buffer=intArrayFromString(result,true)}return FS_stdin_getChar_buffer.shift()};var TTY={ttys:[],init(){},shutdown(){},register(dev,ops){TTY.ttys[dev]={input:[],output:[],ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close(stream){stream.tty.ops.fsync(stream.tty)},fsync(stream){stream.tty.ops.fsync(stream.tty)},read(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i0){out(UTF8ArrayToString(tty.output));tty.output=[]}},ioctl_tcgets(tty){return{c_iflag:25856,c_oflag:5,c_cflag:191,c_lflag:35387,c_cc:[3,28,127,21,4,0,1,0,17,19,26,0,18,15,23,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}},ioctl_tcsets(tty,optional_actions,data){return 0},ioctl_tiocgwinsz(tty){return[24,80]}},default_tty1_ops:{put_char(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output));tty.output=[]}else{if(val!=0)tty.output.push(val)}},fsync(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output));tty.output=[]}}}};var alignMemory=(size,alignment)=>Math.ceil(size/alignment)*alignment;var mmapAlloc=size=>{abort()};var MEMFS={ops_table:null,mount(mount){return MEMFS.createNode(null,"/",16895,0)},createNode(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}MEMFS.ops_table||={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}};var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.atime=node.mtime=node.ctime=Date.now();if(parent){parent.contents[name]=node;parent.atime=parent.mtime=parent.ctime=node.atime}return node},getFileDataAsTypedArray(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.atime);attr.mtime=new Date(node.mtime);attr.ctime=new Date(node.ctime);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr(node,attr){for(const key of["mode","atime","mtime","ctime"]){if(attr[key]){node[key]=attr[key]}}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup(parent,name){throw MEMFS.doesNotExistError},mknod(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename(old_node,new_dir,new_name){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){if(FS.isDir(old_node.mode)){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}FS.hashRemoveNode(new_node)}delete old_node.parent.contents[old_node.name];new_dir.contents[new_name]=old_node;old_node.name=new_name;new_dir.ctime=new_dir.mtime=old_node.parent.ctime=old_node.parent.mtime=Date.now()},unlink(parent,name){delete parent.contents[name];parent.ctime=parent.mtime=Date.now()},rmdir(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.ctime=parent.mtime=Date.now()},readdir(node){return[".","..",...Object.keys(node.contents)]},symlink(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i0||position+length>>0)}}return{ptr,allocated}},msync(stream,buffer,offset,length,mmapFlags){MEMFS.stream_ops.write(stream,buffer,0,length,offset,false);return 0}}};var asyncLoad=async url=>{var arrayBuffer=await readAsync(url);return new Uint8Array(arrayBuffer)};var FS_createDataFile=(parent,name,fileData,canRead,canWrite,canOwn)=>{FS.createDataFile(parent,name,fileData,canRead,canWrite,canOwn)};var preloadPlugins=Module["preloadPlugins"]||[];var FS_handledByPreloadPlugin=(byteArray,fullname,finish,onerror)=>{if(typeof Browser!="undefined")Browser.init();var handled=false;preloadPlugins.forEach(plugin=>{if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}});return handled};var FS_createPreloadedFile=(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency(`cp ${fullname}`);function processData(byteArray){function finish(byteArray){preFinish?.();if(!dontCreateFile){FS_createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}onload?.();removeRunDependency(dep)}if(FS_handledByPreloadPlugin(byteArray,fullname,finish,()=>{onerror?.();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url).then(processData,onerror)}else{processData(url)}};var FS_modeStringToFlags=str=>{var flagModes={r:0,"r+":2,w:512|64|1,"w+":512|64|2,a:1024|64|1,"a+":1024|64|2};var flags=flagModes[str];if(typeof flags=="undefined"){throw new Error(`Unknown file open mode: ${str}`)}return flags};var FS_getMode=(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:class{name="ErrnoError";constructor(errno){this.errno=errno}},filesystems:null,syncFSRequests:0,readFiles:{},FSStream:class{shared={};get object(){return this.node}set object(val){this.node=val}get isRead(){return(this.flags&2097155)!==1}get isWrite(){return(this.flags&2097155)!==0}get isAppend(){return this.flags&1024}get flags(){return this.shared.flags}set flags(val){this.shared.flags=val}get position(){return this.shared.position}set position(val){this.shared.position=val}},FSNode:class{node_ops={};stream_ops={};readMode=292|73;writeMode=146;mounted=null;constructor(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.rdev=rdev;this.atime=this.mtime=this.ctime=Date.now()}get read(){return(this.mode&this.readMode)===this.readMode}set read(val){val?this.mode|=this.readMode:this.mode&=~this.readMode}get write(){return(this.mode&this.writeMode)===this.writeMode}set write(val){val?this.mode|=this.writeMode:this.mode&=~this.writeMode}get isFolder(){return FS.isDir(this.mode)}get isDevice(){return FS.isChrdev(this.mode)}},lookupPath(path,opts={}){if(!path)return{path:"",node:null};opts.follow_mount??=true;if(!PATH.isAbs(path)){path=FS.cwd()+"/"+path}linkloop:for(var nlinks=0;nlinks<40;nlinks++){var parts=path.split("/").filter(p=>!!p&&p!==".");var current=FS.root;var current_path="/";for(var i=0;i>>0)%FS.nameTable.length},hashAddNode(node){var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode(node){var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode(parent,name){var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode(parent,name,mode,rdev){var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode(node){FS.hashRemoveNode(node)},isRoot(node){return node===node.parent},isMountpoint(node){return!!node.mounted},isFile(mode){return(mode&61440)===32768},isDir(mode){return(mode&61440)===16384},isLink(mode){return(mode&61440)===40960},isChrdev(mode){return(mode&61440)===8192},isBlkdev(mode){return(mode&61440)===24576},isFIFO(mode){return(mode&61440)===4096},isSocket(mode){return(mode&49152)===49152},flagsToPermissionString(flag){var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions(node,perms){if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup(dir){if(!FS.isDir(dir.mode))return 54;var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate(dir,name){if(!FS.isDir(dir.mode)){return 54}try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete(dir,name,isdir){var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen(node,flags){if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd(){for(var fd=0;fd<=FS.MAX_OPEN_FDS;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStreamChecked(fd){var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}return stream},getStream:fd=>FS.streams[fd],createStream(stream,fd=-1){stream=Object.assign(new FS.FSStream,stream);if(fd==-1){fd=FS.nextfd()}stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream(fd){FS.streams[fd]=null},dupStream(origStream,fd=-1){var stream=FS.createStream(origStream,fd);stream.stream_ops?.dup?.(stream);return stream},chrdev_stream_ops:{open(stream){var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;stream.stream_ops.open?.(stream)},llseek(){throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice(dev,ops){FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts(mount){var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push(...m.mounts)}return mounts},syncfs(populate,callback){if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err(`warning: ${FS.syncFSRequests} FS.syncfs operations in flight at once, probably just doing extra work`)}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount(type,opts,mountpoint){var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type,opts,mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount(mountpoint){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup(parent,name){return parent.node_ops.lookup(parent,name)},mknod(path,mode,dev){var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},statfs(path){var rtn={bsize:4096,frsize:4096,blocks:1e6,bfree:5e5,bavail:5e5,files:FS.nextInode,ffree:FS.nextInode-1,fsid:42,flags:2,namelen:255};var parent=FS.lookupPath(path,{follow:true}).node;if(parent?.node_ops.statfs){Object.assign(rtn,parent.node_ops.statfs(parent.mount.opts.root))}return rtn},create(path,mode=438){mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir(path,mode=511){mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree(path,mode){var dirs=path.split("/");var d="";for(var i=0;iFS.currentPath,chdir(path){var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories(){FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices(){FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length,llseek:()=>0});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var randomBuffer=new Uint8Array(1024),randomLeft=0;var randomByte=()=>{if(randomLeft===0){randomLeft=randomFill(randomBuffer).byteLength}return randomBuffer[--randomLeft]};FS.createDevice("/dev","random",randomByte);FS.createDevice("/dev","urandom",randomByte);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories(){FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount(){var node=FS.createNode(proc_self,"fd",16895,73);node.stream_ops={llseek:MEMFS.stream_ops.llseek};node.node_ops={lookup(parent,name){var fd=+name;var stream=FS.getStreamChecked(fd);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path},id:fd+1};ret.parent=ret;return ret},readdir(){return Array.from(FS.streams.entries()).filter(([k,v])=>v).map(([k,v])=>k.toString())}};return node}},{},"/proc/self/fd")},createStandardStreams(input,output,error){if(input){FS.createDevice("/dev","stdin",input)}else{FS.symlink("/dev/tty","/dev/stdin")}if(output){FS.createDevice("/dev","stdout",null,output)}else{FS.symlink("/dev/tty","/dev/stdout")}if(error){FS.createDevice("/dev","stderr",null,error)}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},staticInit(){FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={MEMFS}},init(input,output,error){FS.initialized=true;input??=Module["stdin"];output??=Module["stdout"];error??=Module["stderr"];FS.createStandardStreams(input,output,error)},quit(){FS.initialized=false;for(var i=0;ithis.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]}setDataGetter(getter){this.getter=getter}cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}return intArrayFromString(xhr.responseText||"",true)};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true}get length(){if(!this.lengthKnown){this.cacheLength()}return this._length}get chunkSize(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=(...args)=>{FS.forceLoadFile(node);return fn(...args)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr,allocated:true}};node.stream_ops=stream_ops;return node}};var UTF8ToString=(ptr,maxBytesToRead)=>{ptr>>>=0;return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""};var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=SYSCALLS.getStreamFromFD(dirfd);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return dir+"/"+path},doStat(func,path,buf){var stat=func(path);HEAP32[buf>>>2>>>0]=stat.dev;HEAP32[buf+4>>>2>>>0]=stat.mode;HEAPU32[buf+8>>>2>>>0]=stat.nlink;HEAP32[buf+12>>>2>>>0]=stat.uid;HEAP32[buf+16>>>2>>>0]=stat.gid;HEAP32[buf+20>>>2>>>0]=stat.rdev;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+24>>>2>>>0]=tempI64[0],HEAP32[buf+28>>>2>>>0]=tempI64[1];HEAP32[buf+32>>>2>>>0]=4096;HEAP32[buf+36>>>2>>>0]=stat.blocks;var atime=stat.atime.getTime();var mtime=stat.mtime.getTime();var ctime=stat.ctime.getTime();tempI64=[Math.floor(atime/1e3)>>>0,(tempDouble=Math.floor(atime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>>2>>>0]=tempI64[0],HEAP32[buf+44>>>2>>>0]=tempI64[1];HEAPU32[buf+48>>>2>>>0]=atime%1e3*1e3*1e3;tempI64=[Math.floor(mtime/1e3)>>>0,(tempDouble=Math.floor(mtime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+56>>>2>>>0]=tempI64[0],HEAP32[buf+60>>>2>>>0]=tempI64[1];HEAPU32[buf+64>>>2>>>0]=mtime%1e3*1e3*1e3;tempI64=[Math.floor(ctime/1e3)>>>0,(tempDouble=Math.floor(ctime/1e3),+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+72>>>2>>>0]=tempI64[0],HEAP32[buf+76>>>2>>>0]=tempI64[1];HEAPU32[buf+80>>>2>>>0]=ctime%1e3*1e3*1e3;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+88>>>2>>>0]=tempI64[0],HEAP32[buf+92>>>2>>>0]=tempI64[1];return 0},doMsync(addr,stream,len,flags,offset){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(flags&2){return 0}var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},getStreamFromFD(fd){var stream=FS.getStreamChecked(fd);return stream},varargs:undefined,getStr(ptr){var ret=UTF8ToString(ptr);return ret}};function ___syscall_fcntl64(fd,cmd,varargs){varargs>>>=0;SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=syscallGetVarargI();if(arg<0){return-28}while(FS.streams[arg]){arg++}var newStream;newStream=FS.dupStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=syscallGetVarargI();stream.flags|=arg;return 0}case 12:{var arg=syscallGetVarargP();var offset=0;HEAP16[arg+offset>>>1>>>0]=2;return 0}case 13:case 14:return 0}return-28}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_ioctl(fd,op,varargs){varargs>>>=0;SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:{if(!stream.tty)return-59;return 0}case 21505:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcgets){var termios=stream.tty.ops.ioctl_tcgets(stream);var argp=syscallGetVarargP();HEAP32[argp>>>2>>>0]=termios.c_iflag||0;HEAP32[argp+4>>>2>>>0]=termios.c_oflag||0;HEAP32[argp+8>>>2>>>0]=termios.c_cflag||0;HEAP32[argp+12>>>2>>>0]=termios.c_lflag||0;for(var i=0;i<32;i++){HEAP8[argp+i+17>>>0]=termios.c_cc[i]||0}return 0}return 0}case 21510:case 21511:case 21512:{if(!stream.tty)return-59;return 0}case 21506:case 21507:case 21508:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tcsets){var argp=syscallGetVarargP();var c_iflag=HEAP32[argp>>>2>>>0];var c_oflag=HEAP32[argp+4>>>2>>>0];var c_cflag=HEAP32[argp+8>>>2>>>0];var c_lflag=HEAP32[argp+12>>>2>>>0];var c_cc=[];for(var i=0;i<32;i++){c_cc.push(HEAP8[argp+i+17>>>0])}return stream.tty.ops.ioctl_tcsets(stream.tty,op,{c_iflag,c_oflag,c_cflag,c_lflag,c_cc})}return 0}case 21519:{if(!stream.tty)return-59;var argp=syscallGetVarargP();HEAP32[argp>>>2>>>0]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=syscallGetVarargP();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;if(stream.tty.ops.ioctl_tiocgwinsz){var winsize=stream.tty.ops.ioctl_tiocgwinsz(stream.tty);var argp=syscallGetVarargP();HEAP16[argp>>>1>>>0]=winsize[0];HEAP16[argp+2>>>1>>>0]=winsize[1]}return 0}case 21524:{if(!stream.tty)return-59;return 0}case 21515:{if(!stream.tty)return-59;return 0}default:return-28}}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_openat(dirfd,path,flags,varargs){path>>>=0;varargs>>>=0;SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?syscallGetVarargI():0;return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}function ___syscall_stat64(path,buf){path>>>=0;buf>>>=0;try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return-e.errno}}var __abort_js=()=>abort("");var createNamedFunction=(name,body)=>Object.defineProperty(body,"name",{value:name});var emval_freelist=[];var emval_handles=[];var BindingError;var throwBindingError=message=>{throw new BindingError(message)};var count_emval_handles=()=>emval_handles.length/2-5-emval_freelist.length;var init_emval=()=>{emval_handles.push(0,1,undefined,1,null,1,true,1,false,1);Module["count_emval_handles"]=count_emval_handles};var Emval={toValue:handle=>{if(!handle){throwBindingError("Cannot use deleted val. handle = "+handle)}return emval_handles[handle]},toHandle:value=>{switch(value){case undefined:return 2;case null:return 4;case true:return 6;case false:return 8;default:{const handle=emval_freelist.pop()||emval_handles.length;emval_handles[handle]=value;emval_handles[handle+1]=1;return handle}}}};var extendError=(baseErrorType,errorName)=>{var errorClass=createNamedFunction(errorName,function(message){this.name=errorName;this.message=message;var stack=new Error(message).stack;if(stack!==undefined){this.stack=this.toString()+"\n"+stack.replace(/^Error(:[^\n]*)?\n/,"")}});errorClass.prototype=Object.create(baseErrorType.prototype);errorClass.prototype.constructor=errorClass;errorClass.prototype.toString=function(){if(this.message===undefined){return this.name}else{return`${this.name}: ${this.message}`}};return errorClass};var PureVirtualError;var embind_init_charCodes=()=>{var codes=new Array(256);for(var i=0;i<256;++i){codes[i]=String.fromCharCode(i)}embind_charCodes=codes};var embind_charCodes;var readLatin1String=ptr=>{var ret="";var c=ptr;while(HEAPU8[c>>>0]){ret+=embind_charCodes[HEAPU8[c++>>>0]]}return ret};var registeredInstances={};var getBasestPointer=(class_,ptr)=>{if(ptr===undefined){throwBindingError("ptr should not be undefined")}while(class_.baseClass){ptr=class_.upcast(ptr);class_=class_.baseClass}return ptr};var registerInheritedInstance=(class_,ptr,instance)=>{ptr=getBasestPointer(class_,ptr);if(registeredInstances.hasOwnProperty(ptr)){throwBindingError(`Tried to register registered instance: ${ptr}`)}else{registeredInstances[ptr]=instance}};var registeredTypes={};var getTypeName=type=>{var ptr=___getTypeName(type);var rv=readLatin1String(ptr);_free(ptr);return rv};var requireRegisteredType=(rawType,humanName)=>{var impl=registeredTypes[rawType];if(undefined===impl){throwBindingError(`${humanName} has unknown type ${getTypeName(rawType)}`)}return impl};var unregisterInheritedInstance=(class_,ptr)=>{ptr=getBasestPointer(class_,ptr);if(registeredInstances.hasOwnProperty(ptr)){delete registeredInstances[ptr]}else{throwBindingError(`Tried to unregister unregistered instance: ${ptr}`)}};var detachFinalizer=handle=>{};var finalizationRegistry=false;var runDestructor=$$=>{if($$.smartPtr){$$.smartPtrType.rawDestructor($$.smartPtr)}else{$$.ptrType.registeredClass.rawDestructor($$.ptr)}};var releaseClassHandle=$$=>{$$.count.value-=1;var toDelete=0===$$.count.value;if(toDelete){runDestructor($$)}};var downcastPointer=(ptr,ptrClass,desiredClass)=>{if(ptrClass===desiredClass){return ptr}if(undefined===desiredClass.baseClass){return null}var rv=downcastPointer(ptr,ptrClass,desiredClass.baseClass);if(rv===null){return null}return desiredClass.downcast(rv)};var registeredPointers={};var getInheritedInstance=(class_,ptr)=>{ptr=getBasestPointer(class_,ptr);return registeredInstances[ptr]};var InternalError;var throwInternalError=message=>{throw new InternalError(message)};var makeClassHandle=(prototype,record)=>{if(!record.ptrType||!record.ptr){throwInternalError("makeClassHandle requires ptr and ptrType")}var hasSmartPtrType=!!record.smartPtrType;var hasSmartPtr=!!record.smartPtr;if(hasSmartPtrType!==hasSmartPtr){throwInternalError("Both smartPtrType and smartPtr must be specified")}record.count={value:1};return attachFinalizer(Object.create(prototype,{$$:{value:record,writable:true}}))};function RegisteredPointer_fromWireType(ptr){var rawPointer=this.getPointee(ptr);if(!rawPointer){this.destructor(ptr);return null}var registeredInstance=getInheritedInstance(this.registeredClass,rawPointer);if(undefined!==registeredInstance){if(0===registeredInstance.$$.count.value){registeredInstance.$$.ptr=rawPointer;registeredInstance.$$.smartPtr=ptr;return registeredInstance["clone"]()}else{var rv=registeredInstance["clone"]();this.destructor(ptr);return rv}}function makeDefaultHandle(){if(this.isSmartPointer){return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this.pointeeType,ptr:rawPointer,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(this.registeredClass.instancePrototype,{ptrType:this,ptr})}}var actualType=this.registeredClass.getActualType(rawPointer);var registeredPointerRecord=registeredPointers[actualType];if(!registeredPointerRecord){return makeDefaultHandle.call(this)}var toType;if(this.isConst){toType=registeredPointerRecord.constPointerType}else{toType=registeredPointerRecord.pointerType}var dp=downcastPointer(rawPointer,this.registeredClass,toType.registeredClass);if(dp===null){return makeDefaultHandle.call(this)}if(this.isSmartPointer){return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp,smartPtrType:this,smartPtr:ptr})}else{return makeClassHandle(toType.registeredClass.instancePrototype,{ptrType:toType,ptr:dp})}}var attachFinalizer=handle=>{if("undefined"===typeof FinalizationRegistry){attachFinalizer=handle=>handle;return handle}finalizationRegistry=new FinalizationRegistry(info=>{releaseClassHandle(info.$$)});attachFinalizer=handle=>{var $$=handle.$$;var hasSmartPtr=!!$$.smartPtr;if(hasSmartPtr){var info={$$};finalizationRegistry.register(handle,info,handle)}return handle};detachFinalizer=handle=>finalizationRegistry.unregister(handle);return attachFinalizer(handle)};function __embind_create_inheriting_constructor(constructorName,wrapperType,properties){constructorName>>>=0;wrapperType>>>=0;properties>>>=0;constructorName=readLatin1String(constructorName);wrapperType=requireRegisteredType(wrapperType,"wrapper");properties=Emval.toValue(properties);var registeredClass=wrapperType.registeredClass;var wrapperPrototype=registeredClass.instancePrototype;var baseClass=registeredClass.baseClass;var baseClassPrototype=baseClass.instancePrototype;var baseConstructor=registeredClass.baseClass.constructor;var ctor=createNamedFunction(constructorName,function(...args){registeredClass.baseClass.pureVirtualFunctions.forEach(function(name){if(this[name]===baseClassPrototype[name]){throw new PureVirtualError(`Pure virtual function ${name} must be implemented in JavaScript`)}}.bind(this));Object.defineProperty(this,"__parent",{value:wrapperPrototype});this["__construct"](...args)});wrapperPrototype["__construct"]=function __construct(...args){if(this===wrapperPrototype){throwBindingError("Pass correct 'this' to __construct")}var inner=baseConstructor["implement"](this,...args);detachFinalizer(inner);var $$=inner.$$;inner["notifyOnDestruction"]();$$.preservePointerOnDelete=true;Object.defineProperties(this,{$$:{value:$$}});attachFinalizer(this);registerInheritedInstance(registeredClass,$$.ptr,this)};wrapperPrototype["__destruct"]=function __destruct(){if(this===wrapperPrototype){throwBindingError("Pass correct 'this' to __destruct")}detachFinalizer(this);unregisterInheritedInstance(registeredClass,this.$$.ptr)};ctor.prototype=Object.create(wrapperPrototype);Object.assign(ctor.prototype,properties);return Emval.toHandle(ctor)}function __embind_register_bigint(primitiveType,name,size,minRange,maxRange){primitiveType>>>=0;name>>>=0;size>>>=0}var awaitingDependencies={};var typeDependencies={};var whenDependentTypesAreResolved=(myTypes,dependentTypes,getTypeConverters)=>{myTypes.forEach(type=>typeDependencies[type]=dependentTypes);function onComplete(typeConverters){var myTypeConverters=getTypeConverters(typeConverters);if(myTypeConverters.length!==myTypes.length){throwInternalError("Mismatched type converter count")}for(var i=0;i{if(registeredTypes.hasOwnProperty(dt)){typeConverters[i]=registeredTypes[dt]}else{unregisteredTypes.push(dt);if(!awaitingDependencies.hasOwnProperty(dt)){awaitingDependencies[dt]=[]}awaitingDependencies[dt].push(()=>{typeConverters[i]=registeredTypes[dt];++registered;if(registered===unregisteredTypes.length){onComplete(typeConverters)}})}});if(0===unregisteredTypes.length){onComplete(typeConverters)}};function sharedRegisterType(rawType,registeredInstance,options={}){var name=registeredInstance.name;if(!rawType){throwBindingError(`type "${name}" must have a positive integer typeid pointer`)}if(registeredTypes.hasOwnProperty(rawType)){if(options.ignoreDuplicateRegistrations){return}else{throwBindingError(`Cannot register type '${name}' twice`)}}registeredTypes[rawType]=registeredInstance;delete typeDependencies[rawType];if(awaitingDependencies.hasOwnProperty(rawType)){var callbacks=awaitingDependencies[rawType];delete awaitingDependencies[rawType];callbacks.forEach(cb=>cb())}}function registerType(rawType,registeredInstance,options={}){return sharedRegisterType(rawType,registeredInstance,options)}var GenericWireTypeSize=8;function __embind_register_bool(rawType,name,trueValue,falseValue){rawType>>>=0;name>>>=0;name=readLatin1String(name);registerType(rawType,{name,fromWireType:function(wt){return!!wt},toWireType:function(destructors,o){return o?trueValue:falseValue},argPackAdvance:GenericWireTypeSize,readValueFromPointer:function(pointer){return this["fromWireType"](HEAPU8[pointer>>>0])},destructorFunction:null})}var shallowCopyInternalPointer=o=>({count:o.count,deleteScheduled:o.deleteScheduled,preservePointerOnDelete:o.preservePointerOnDelete,ptr:o.ptr,ptrType:o.ptrType,smartPtr:o.smartPtr,smartPtrType:o.smartPtrType});var throwInstanceAlreadyDeleted=obj=>{function getInstanceTypeName(handle){return handle.$$.ptrType.registeredClass.name}throwBindingError(getInstanceTypeName(obj)+" instance already deleted")};var deletionQueue=[];var flushPendingDeletes=()=>{while(deletionQueue.length){var obj=deletionQueue.pop();obj.$$.deleteScheduled=false;obj["delete"]()}};var delayFunction;var init_ClassHandle=()=>{Object.assign(ClassHandle.prototype,{isAliasOf(other){if(!(this instanceof ClassHandle)){return false}if(!(other instanceof ClassHandle)){return false}var leftClass=this.$$.ptrType.registeredClass;var left=this.$$.ptr;other.$$=other.$$;var rightClass=other.$$.ptrType.registeredClass;var right=other.$$.ptr;while(leftClass.baseClass){left=leftClass.upcast(left);leftClass=leftClass.baseClass}while(rightClass.baseClass){right=rightClass.upcast(right);rightClass=rightClass.baseClass}return leftClass===rightClass&&left===right},clone(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.preservePointerOnDelete){this.$$.count.value+=1;return this}else{var clone=attachFinalizer(Object.create(Object.getPrototypeOf(this),{$$:{value:shallowCopyInternalPointer(this.$$)}}));clone.$$.count.value+=1;clone.$$.deleteScheduled=false;return clone}},delete(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}detachFinalizer(this);releaseClassHandle(this.$$);if(!this.$$.preservePointerOnDelete){this.$$.smartPtr=undefined;this.$$.ptr=undefined}},isDeleted(){return!this.$$.ptr},deleteLater(){if(!this.$$.ptr){throwInstanceAlreadyDeleted(this)}if(this.$$.deleteScheduled&&!this.$$.preservePointerOnDelete){throwBindingError("Object already scheduled for deletion")}deletionQueue.push(this);if(deletionQueue.length===1&&delayFunction){delayFunction(flushPendingDeletes)}this.$$.deleteScheduled=true;return this}})};function ClassHandle(){}var ensureOverloadTable=(proto,methodName,humanName)=>{if(undefined===proto[methodName].overloadTable){var prevFunc=proto[methodName];proto[methodName]=function(...args){if(!proto[methodName].overloadTable.hasOwnProperty(args.length)){throwBindingError(`Function '${humanName}' called with an invalid number of arguments (${args.length}) - expects one of (${proto[methodName].overloadTable})!`)}return proto[methodName].overloadTable[args.length].apply(this,args)};proto[methodName].overloadTable=[];proto[methodName].overloadTable[prevFunc.argCount]=prevFunc}};var exposePublicSymbol=(name,value,numArguments)=>{if(Module.hasOwnProperty(name)){if(undefined===numArguments||undefined!==Module[name].overloadTable&&undefined!==Module[name].overloadTable[numArguments]){throwBindingError(`Cannot register public name '${name}' twice`)}ensureOverloadTable(Module,name,name);if(Module[name].overloadTable.hasOwnProperty(numArguments)){throwBindingError(`Cannot register multiple overloads of a function with the same number of arguments (${numArguments})!`)}Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}};var char_0=48;var char_9=57;var makeLegalFunctionName=name=>{name=name.replace(/[^a-zA-Z0-9_]/g,"$");var f=name.charCodeAt(0);if(f>=char_0&&f<=char_9){return`_${name}`}return name};function RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast){this.name=name;this.constructor=constructor;this.instancePrototype=instancePrototype;this.rawDestructor=rawDestructor;this.baseClass=baseClass;this.getActualType=getActualType;this.upcast=upcast;this.downcast=downcast;this.pureVirtualFunctions=[]}var upcastPointer=(ptr,ptrClass,desiredClass)=>{while(ptrClass!==desiredClass){if(!ptrClass.upcast){throwBindingError(`Expected null or instance of ${desiredClass.name}, got an instance of ${ptrClass.name}`)}ptr=ptrClass.upcast(ptr);ptrClass=ptrClass.baseClass}return ptr};function constNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}return 0}if(!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function genericPointerToWireType(destructors,handle){var ptr;if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}if(this.isSmartPointer){ptr=this.rawConstructor();if(destructors!==null){destructors.push(this.rawDestructor,ptr)}return ptr}else{return 0}}if(!handle||!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}if(!this.isConst&&handle.$$.ptrType.isConst){throwBindingError(`Cannot convert argument of type ${handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name} to parameter type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);if(this.isSmartPointer){if(undefined===handle.$$.smartPtr){throwBindingError("Passing raw pointer to smart pointer is illegal")}switch(this.sharingPolicy){case 0:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{throwBindingError(`Cannot convert argument of type ${handle.$$.smartPtrType?handle.$$.smartPtrType.name:handle.$$.ptrType.name} to parameter type ${this.name}`)}break;case 1:ptr=handle.$$.smartPtr;break;case 2:if(handle.$$.smartPtrType===this){ptr=handle.$$.smartPtr}else{var clonedHandle=handle["clone"]();ptr=this.rawShare(ptr,Emval.toHandle(()=>clonedHandle["delete"]()));if(destructors!==null){destructors.push(this.rawDestructor,ptr)}}break;default:throwBindingError("Unsupporting sharing policy")}}return ptr}function nonConstNoSmartPtrRawPointerToWireType(destructors,handle){if(handle===null){if(this.isReference){throwBindingError(`null is not a valid ${this.name}`)}return 0}if(!handle.$$){throwBindingError(`Cannot pass "${embindRepr(handle)}" as a ${this.name}`)}if(!handle.$$.ptr){throwBindingError(`Cannot pass deleted object as a pointer of type ${this.name}`)}if(handle.$$.ptrType.isConst){throwBindingError(`Cannot convert argument of type ${handle.$$.ptrType.name} to parameter type ${this.name}`)}var handleClass=handle.$$.ptrType.registeredClass;var ptr=upcastPointer(handle.$$.ptr,handleClass,this.registeredClass);return ptr}function readPointer(pointer){return this["fromWireType"](HEAPU32[pointer>>>2>>>0])}var init_RegisteredPointer=()=>{Object.assign(RegisteredPointer.prototype,{getPointee(ptr){if(this.rawGetPointee){ptr=this.rawGetPointee(ptr)}return ptr},destructor(ptr){this.rawDestructor?.(ptr)},argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,fromWireType:RegisteredPointer_fromWireType})};function RegisteredPointer(name,registeredClass,isReference,isConst,isSmartPointer,pointeeType,sharingPolicy,rawGetPointee,rawConstructor,rawShare,rawDestructor){this.name=name;this.registeredClass=registeredClass;this.isReference=isReference;this.isConst=isConst;this.isSmartPointer=isSmartPointer;this.pointeeType=pointeeType;this.sharingPolicy=sharingPolicy;this.rawGetPointee=rawGetPointee;this.rawConstructor=rawConstructor;this.rawShare=rawShare;this.rawDestructor=rawDestructor;if(!isSmartPointer&®isteredClass.baseClass===undefined){if(isConst){this["toWireType"]=constNoSmartPtrRawPointerToWireType;this.destructorFunction=null}else{this["toWireType"]=nonConstNoSmartPtrRawPointerToWireType;this.destructorFunction=null}}else{this["toWireType"]=genericPointerToWireType}}var replacePublicSymbol=(name,value,numArguments)=>{if(!Module.hasOwnProperty(name)){throwInternalError("Replacing nonexistent public symbol")}if(undefined!==Module[name].overloadTable&&undefined!==numArguments){Module[name].overloadTable[numArguments]=value}else{Module[name]=value;Module[name].argCount=numArguments}};var dynCallLegacy=(sig,ptr,args)=>{sig=sig.replace(/p/g,"i");var f=Module["dynCall_"+sig];return f(ptr,...args)};var wasmTable;var getWasmTableEntry=funcPtr=>wasmTable.get(funcPtr);var dynCall=(sig,ptr,args=[])=>{if(sig.includes("j")){return dynCallLegacy(sig,ptr,args)}var rtn=getWasmTableEntry(ptr)(...args);return sig[0]=="p"?rtn>>>0:rtn};var getDynCaller=(sig,ptr)=>(...args)=>dynCall(sig,ptr,args);var embind__requireFunction=(signature,rawFunction)=>{signature=readLatin1String(signature);function makeDynCaller(){if(signature.includes("j")){return getDynCaller(signature,rawFunction)}if(signature.includes("p")){return getDynCaller(signature,rawFunction)}return getWasmTableEntry(rawFunction)}var fp=makeDynCaller();if(typeof fp!="function"){throwBindingError(`unknown function pointer with signature ${signature}: ${rawFunction}`)}return fp};var UnboundTypeError;var throwUnboundTypeError=(message,types)=>{var unboundTypes=[];var seen={};function visit(type){if(seen[type]){return}if(registeredTypes[type]){return}if(typeDependencies[type]){typeDependencies[type].forEach(visit);return}unboundTypes.push(type);seen[type]=true}types.forEach(visit);throw new UnboundTypeError(`${message}: `+unboundTypes.map(getTypeName).join([", "]))};function __embind_register_class(rawType,rawPointerType,rawConstPointerType,baseClassRawType,getActualTypeSignature,getActualType,upcastSignature,upcast,downcastSignature,downcast,name,destructorSignature,rawDestructor){rawType>>>=0;rawPointerType>>>=0;rawConstPointerType>>>=0;baseClassRawType>>>=0;getActualTypeSignature>>>=0;getActualType>>>=0;upcastSignature>>>=0;upcast>>>=0;downcastSignature>>>=0;downcast>>>=0;name>>>=0;destructorSignature>>>=0;rawDestructor>>>=0;name=readLatin1String(name);getActualType=embind__requireFunction(getActualTypeSignature,getActualType);upcast&&=embind__requireFunction(upcastSignature,upcast);downcast&&=embind__requireFunction(downcastSignature,downcast);rawDestructor=embind__requireFunction(destructorSignature,rawDestructor);var legalFunctionName=makeLegalFunctionName(name);exposePublicSymbol(legalFunctionName,function(){throwUnboundTypeError(`Cannot construct ${name} due to unbound types`,[baseClassRawType])});whenDependentTypesAreResolved([rawType,rawPointerType,rawConstPointerType],baseClassRawType?[baseClassRawType]:[],base=>{base=base[0];var baseClass;var basePrototype;if(baseClassRawType){baseClass=base.registeredClass;basePrototype=baseClass.instancePrototype}else{basePrototype=ClassHandle.prototype}var constructor=createNamedFunction(name,function(...args){if(Object.getPrototypeOf(this)!==instancePrototype){throw new BindingError("Use 'new' to construct "+name)}if(undefined===registeredClass.constructor_body){throw new BindingError(name+" has no accessible constructor")}var body=registeredClass.constructor_body[args.length];if(undefined===body){throw new BindingError(`Tried to invoke ctor of ${name} with invalid number of parameters (${args.length}) - expected (${Object.keys(registeredClass.constructor_body).toString()}) parameters instead!`)}return body.apply(this,args)});var instancePrototype=Object.create(basePrototype,{constructor:{value:constructor}});constructor.prototype=instancePrototype;var registeredClass=new RegisteredClass(name,constructor,instancePrototype,rawDestructor,baseClass,getActualType,upcast,downcast);if(registeredClass.baseClass){registeredClass.baseClass.__derivedClasses??=[];registeredClass.baseClass.__derivedClasses.push(registeredClass)}var referenceConverter=new RegisteredPointer(name,registeredClass,true,false,false);var pointerConverter=new RegisteredPointer(name+"*",registeredClass,false,false,false);var constPointerConverter=new RegisteredPointer(name+" const*",registeredClass,false,true,false);registeredPointers[rawType]={pointerType:pointerConverter,constPointerType:constPointerConverter};replacePublicSymbol(legalFunctionName,constructor);return[referenceConverter,pointerConverter,constPointerConverter]})}var runDestructors=destructors=>{while(destructors.length){var ptr=destructors.pop();var del=destructors.pop();del(ptr)}};function usesDestructorStack(argTypes){for(var i=1;i{var array=[];for(var i=0;i>>2>>>0])}return array};var getFunctionName=signature=>{signature=signature.trim();const argsIndex=signature.indexOf("(");if(argsIndex!==-1){return signature.substr(0,argsIndex)}else{return signature}};var __embind_register_class_class_function=function(rawClassType,methodName,argCount,rawArgTypesAddr,invokerSignature,rawInvoker,fn,isAsync,isNonnullReturn){rawClassType>>>=0;methodName>>>=0;rawArgTypesAddr>>>=0;invokerSignature>>>=0;rawInvoker>>>=0;fn>>>=0;var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);methodName=readLatin1String(methodName);methodName=getFunctionName(methodName);rawInvoker=embind__requireFunction(invokerSignature,rawInvoker);whenDependentTypesAreResolved([],[rawClassType],classType=>{classType=classType[0];var humanName=`${classType.name}.${methodName}`;function unboundTypesHandler(){throwUnboundTypeError(`Cannot call ${humanName} due to unbound types`,rawArgTypes)}if(methodName.startsWith("@@")){methodName=Symbol[methodName.substring(2)]}var proto=classType.registeredClass.constructor;if(undefined===proto[methodName]){unboundTypesHandler.argCount=argCount-1;proto[methodName]=unboundTypesHandler}else{ensureOverloadTable(proto,methodName,humanName);proto[methodName].overloadTable[argCount-1]=unboundTypesHandler}whenDependentTypesAreResolved([],rawArgTypes,argTypes=>{var invokerArgsArray=[argTypes[0],null].concat(argTypes.slice(1));var func=craftInvokerFunction(humanName,invokerArgsArray,null,rawInvoker,fn,isAsync);if(undefined===proto[methodName].overloadTable){func.argCount=argCount-1;proto[methodName]=func}else{proto[methodName].overloadTable[argCount-1]=func}if(classType.registeredClass.__derivedClasses){for(const derivedClass of classType.registeredClass.__derivedClasses){if(!derivedClass.constructor.hasOwnProperty(methodName)){derivedClass.constructor[methodName]=func}}}return[]});return[]})};var __embind_register_class_constructor=function(rawClassType,argCount,rawArgTypesAddr,invokerSignature,invoker,rawConstructor){rawClassType>>>=0;rawArgTypesAddr>>>=0;invokerSignature>>>=0;invoker>>>=0;rawConstructor>>>=0;var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);invoker=embind__requireFunction(invokerSignature,invoker);whenDependentTypesAreResolved([],[rawClassType],classType=>{classType=classType[0];var humanName=`constructor ${classType.name}`;if(undefined===classType.registeredClass.constructor_body){classType.registeredClass.constructor_body=[]}if(undefined!==classType.registeredClass.constructor_body[argCount-1]){throw new BindingError(`Cannot register multiple constructors with identical number of parameters (${argCount-1}) for class '${classType.name}'! Overload resolution is currently only performed using the parameter count, not actual type info!`)}classType.registeredClass.constructor_body[argCount-1]=()=>{throwUnboundTypeError(`Cannot construct ${classType.name} due to unbound types`,rawArgTypes)};whenDependentTypesAreResolved([],rawArgTypes,argTypes=>{argTypes.splice(1,0,null);classType.registeredClass.constructor_body[argCount-1]=craftInvokerFunction(humanName,argTypes,null,invoker,rawConstructor);return[]});return[]})};var __embind_register_class_function=function(rawClassType,methodName,argCount,rawArgTypesAddr,invokerSignature,rawInvoker,context,isPureVirtual,isAsync,isNonnullReturn){rawClassType>>>=0;methodName>>>=0;rawArgTypesAddr>>>=0;invokerSignature>>>=0;rawInvoker>>>=0;context>>>=0;var rawArgTypes=heap32VectorToArray(argCount,rawArgTypesAddr);methodName=readLatin1String(methodName);methodName=getFunctionName(methodName);rawInvoker=embind__requireFunction(invokerSignature,rawInvoker);whenDependentTypesAreResolved([],[rawClassType],classType=>{classType=classType[0];var humanName=`${classType.name}.${methodName}`;if(methodName.startsWith("@@")){methodName=Symbol[methodName.substring(2)]}if(isPureVirtual){classType.registeredClass.pureVirtualFunctions.push(methodName)}function unboundTypesHandler(){throwUnboundTypeError(`Cannot call ${humanName} due to unbound types`,rawArgTypes)}var proto=classType.registeredClass.instancePrototype;var method=proto[methodName];if(undefined===method||undefined===method.overloadTable&&method.className!==classType.name&&method.argCount===argCount-2){unboundTypesHandler.argCount=argCount-2;unboundTypesHandler.className=classType.name;proto[methodName]=unboundTypesHandler}else{ensureOverloadTable(proto,methodName,humanName);proto[methodName].overloadTable[argCount-2]=unboundTypesHandler}whenDependentTypesAreResolved([],rawArgTypes,argTypes=>{var memberFunction=craftInvokerFunction(humanName,argTypes,classType,rawInvoker,context,isAsync);if(undefined===proto[methodName].overloadTable){memberFunction.argCount=argCount-2;proto[methodName]=memberFunction}else{proto[methodName].overloadTable[argCount-2]=memberFunction}return[]});return[]})};var validateThis=(this_,classType,humanName)=>{if(!(this_ instanceof Object)){throwBindingError(`${humanName} with invalid "this": ${this_}`)}if(!(this_ instanceof classType.registeredClass.constructor)){throwBindingError(`${humanName} incompatible with "this" of type ${this_.constructor.name}`)}if(!this_.$$.ptr){throwBindingError(`cannot call emscripten binding method ${humanName} on deleted object`)}return upcastPointer(this_.$$.ptr,this_.$$.ptrType.registeredClass,classType.registeredClass)};var __embind_register_class_property=function(classType,fieldName,getterReturnType,getterSignature,getter,getterContext,setterArgumentType,setterSignature,setter,setterContext){classType>>>=0;fieldName>>>=0;getterReturnType>>>=0;getterSignature>>>=0;getter>>>=0;getterContext>>>=0;setterArgumentType>>>=0;setterSignature>>>=0;setter>>>=0;setterContext>>>=0;fieldName=readLatin1String(fieldName);getter=embind__requireFunction(getterSignature,getter);whenDependentTypesAreResolved([],[classType],classType=>{classType=classType[0];var humanName=`${classType.name}.${fieldName}`;var desc={get(){throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`,[getterReturnType,setterArgumentType])},enumerable:true,configurable:true};if(setter){desc.set=()=>throwUnboundTypeError(`Cannot access ${humanName} due to unbound types`,[getterReturnType,setterArgumentType])}else{desc.set=v=>throwBindingError(humanName+" is a read-only property")}Object.defineProperty(classType.registeredClass.instancePrototype,fieldName,desc);whenDependentTypesAreResolved([],setter?[getterReturnType,setterArgumentType]:[getterReturnType],types=>{var getterReturnType=types[0];var desc={get(){var ptr=validateThis(this,classType,humanName+" getter");return getterReturnType["fromWireType"](getter(getterContext,ptr))},enumerable:true};if(setter){setter=embind__requireFunction(setterSignature,setter);var setterArgumentType=types[1];desc.set=function(v){var ptr=validateThis(this,classType,humanName+" setter");var destructors=[];setter(setterContext,ptr,setterArgumentType["toWireType"](destructors,v));runDestructors(destructors)}}Object.defineProperty(classType.registeredClass.instancePrototype,fieldName,desc);return[]});return[]})};function __emval_decref(handle){handle>>>=0;if(handle>9&&0===--emval_handles[handle+1]){emval_handles[handle]=undefined;emval_freelist.push(handle)}}var EmValType={name:"emscripten::val",fromWireType:handle=>{var rv=Emval.toValue(handle);__emval_decref(handle);return rv},toWireType:(destructors,value)=>Emval.toHandle(value),argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,destructorFunction:null};function __embind_register_emval(rawType){rawType>>>=0;return registerType(rawType,EmValType)}var enumReadValueFromPointer=(name,width,signed)=>{switch(width){case 1:return signed?function(pointer){return this["fromWireType"](HEAP8[pointer>>>0])}:function(pointer){return this["fromWireType"](HEAPU8[pointer>>>0])};case 2:return signed?function(pointer){return this["fromWireType"](HEAP16[pointer>>>1>>>0])}:function(pointer){return this["fromWireType"](HEAPU16[pointer>>>1>>>0])};case 4:return signed?function(pointer){return this["fromWireType"](HEAP32[pointer>>>2>>>0])}:function(pointer){return this["fromWireType"](HEAPU32[pointer>>>2>>>0])};default:throw new TypeError(`invalid integer width (${width}): ${name}`)}};function __embind_register_enum(rawType,name,size,isSigned){rawType>>>=0;name>>>=0;size>>>=0;name=readLatin1String(name);function ctor(){}ctor.values={};registerType(rawType,{name,constructor:ctor,fromWireType:function(c){return this.constructor.values[c]},toWireType:(destructors,c)=>c.value,argPackAdvance:GenericWireTypeSize,readValueFromPointer:enumReadValueFromPointer(name,size,isSigned),destructorFunction:null});exposePublicSymbol(name,ctor)}function __embind_register_enum_value(rawEnumType,name,enumValue){rawEnumType>>>=0;name>>>=0;var enumType=requireRegisteredType(rawEnumType,"enum");name=readLatin1String(name);var Enum=enumType.constructor;var Value=Object.create(enumType.constructor.prototype,{value:{value:enumValue},constructor:{value:createNamedFunction(`${enumType.name}_${name}`,function(){})}});Enum.values[enumValue]=Value;Enum[name]=Value}var embindRepr=v=>{if(v===null){return"null"}var t=typeof v;if(t==="object"||t==="array"||t==="function"){return v.toString()}else{return""+v}};var floatReadValueFromPointer=(name,width)=>{switch(width){case 4:return function(pointer){return this["fromWireType"](HEAPF32[pointer>>>2>>>0])};case 8:return function(pointer){return this["fromWireType"](HEAPF64[pointer>>>3>>>0])};default:throw new TypeError(`invalid float width (${width}): ${name}`)}};var __embind_register_float=function(rawType,name,size){rawType>>>=0;name>>>=0;size>>>=0;name=readLatin1String(name);registerType(rawType,{name,fromWireType:value=>value,toWireType:(destructors,value)=>value,argPackAdvance:GenericWireTypeSize,readValueFromPointer:floatReadValueFromPointer(name,size),destructorFunction:null})};function __embind_register_function(name,argCount,rawArgTypesAddr,signature,rawInvoker,fn,isAsync,isNonnullReturn){name>>>=0;rawArgTypesAddr>>>=0;signature>>>=0;rawInvoker>>>=0;fn>>>=0;var argTypes=heap32VectorToArray(argCount,rawArgTypesAddr);name=readLatin1String(name);name=getFunctionName(name);rawInvoker=embind__requireFunction(signature,rawInvoker);exposePublicSymbol(name,function(){throwUnboundTypeError(`Cannot call ${name} due to unbound types`,argTypes)},argCount-1);whenDependentTypesAreResolved([],argTypes,argTypes=>{var invokerArgsArray=[argTypes[0],null].concat(argTypes.slice(1));replacePublicSymbol(name,craftInvokerFunction(name,invokerArgsArray,null,rawInvoker,fn,isAsync),argCount-1);return[]})}var integerReadValueFromPointer=(name,width,signed)=>{switch(width){case 1:return signed?pointer=>HEAP8[pointer>>>0]:pointer=>HEAPU8[pointer>>>0];case 2:return signed?pointer=>HEAP16[pointer>>>1>>>0]:pointer=>HEAPU16[pointer>>>1>>>0];case 4:return signed?pointer=>HEAP32[pointer>>>2>>>0]:pointer=>HEAPU32[pointer>>>2>>>0];default:throw new TypeError(`invalid integer width (${width}): ${name}`)}};function __embind_register_integer(primitiveType,name,size,minRange,maxRange){primitiveType>>>=0;name>>>=0;size>>>=0;name=readLatin1String(name);if(maxRange===-1){maxRange=4294967295}var fromWireType=value=>value;if(minRange===0){var bitshift=32-8*size;fromWireType=value=>value<>>bitshift}var isUnsignedType=name.includes("unsigned");var checkAssertions=(value,toTypeName)=>{};var toWireType;if(isUnsignedType){toWireType=function(destructors,value){checkAssertions(value,this.name);return value>>>0}}else{toWireType=function(destructors,value){checkAssertions(value,this.name);return value}}registerType(primitiveType,{name,fromWireType,toWireType,argPackAdvance:GenericWireTypeSize,readValueFromPointer:integerReadValueFromPointer(name,size,minRange!==0),destructorFunction:null})}function __embind_register_memory_view(rawType,dataTypeIndex,name){rawType>>>=0;name>>>=0;var typeMapping=[Int8Array,Uint8Array,Int16Array,Uint16Array,Int32Array,Uint32Array,Float32Array,Float64Array];var TA=typeMapping[dataTypeIndex];function decodeMemoryView(handle){var size=HEAPU32[handle>>>2>>>0];var data=HEAPU32[handle+4>>>2>>>0];return new TA(HEAP8.buffer,data,size)}name=readLatin1String(name);registerType(rawType,{name,fromWireType:decodeMemoryView,argPackAdvance:GenericWireTypeSize,readValueFromPointer:decodeMemoryView},{ignoreDuplicateRegistrations:true})}var stringToUTF8=(str,outPtr,maxBytesToWrite)=>stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite);function __embind_register_std_string(rawType,name){rawType>>>=0;name>>>=0;name=readLatin1String(name);var stdStringIsUTF8=true;registerType(rawType,{name,fromWireType(value){var length=HEAPU32[value>>>2>>>0];var payload=value+4;var str;if(stdStringIsUTF8){var decodeStartPtr=payload;for(var i=0;i<=length;++i){var currentBytePtr=payload+i;if(i==length||HEAPU8[currentBytePtr>>>0]==0){var maxRead=currentBytePtr-decodeStartPtr;var stringSegment=UTF8ToString(decodeStartPtr,maxRead);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+1}}}else{var a=new Array(length);for(var i=0;i>>0])}str=a.join("")}_free(value);return str},toWireType(destructors,value){if(value instanceof ArrayBuffer){value=new Uint8Array(value)}var length;var valueIsOfTypeString=typeof value=="string";if(!(valueIsOfTypeString||value instanceof Uint8Array||value instanceof Uint8ClampedArray||value instanceof Int8Array)){throwBindingError("Cannot pass non-string to std::string")}if(stdStringIsUTF8&&valueIsOfTypeString){length=lengthBytesUTF8(value)}else{length=value.length}var base=_malloc(4+length+1);var ptr=base+4;HEAPU32[base>>>2>>>0]=length;if(stdStringIsUTF8&&valueIsOfTypeString){stringToUTF8(value,ptr,length+1)}else{if(valueIsOfTypeString){for(var i=0;i255){_free(ptr);throwBindingError("String has UTF-16 code units that do not fit in 8 bits")}HEAPU8[ptr+i>>>0]=charCode}}else{for(var i=0;i>>0]=value[i]}}}if(destructors!==null){destructors.push(_free,base)}return base},argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,destructorFunction(ptr){_free(ptr)}})}var UTF16Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf-16le"):undefined;var UTF16ToString=(ptr,maxBytesToRead)=>{var endPtr=ptr;var idx=endPtr>>1;var maxIdx=idx+maxBytesToRead/2;while(!(idx>=maxIdx)&&HEAPU16[idx>>>0])++idx;endPtr=idx<<1;if(endPtr-ptr>32&&UTF16Decoder)return UTF16Decoder.decode(HEAPU8.subarray(ptr>>>0,endPtr>>>0));var str="";for(var i=0;!(i>=maxBytesToRead/2);++i){var codeUnit=HEAP16[ptr+i*2>>>1>>>0];if(codeUnit==0)break;str+=String.fromCharCode(codeUnit)}return str};var stringToUTF16=(str,outPtr,maxBytesToWrite)=>{maxBytesToWrite??=2147483647;if(maxBytesToWrite<2)return 0;maxBytesToWrite-=2;var startPtr=outPtr;var numCharsToWrite=maxBytesToWrite>>1>>>0]=codeUnit;outPtr+=2}HEAP16[outPtr>>>1>>>0]=0;return outPtr-startPtr};var lengthBytesUTF16=str=>str.length*2;var UTF32ToString=(ptr,maxBytesToRead)=>{var i=0;var str="";while(!(i>=maxBytesToRead/4)){var utf32=HEAP32[ptr+i*4>>>2>>>0];if(utf32==0)break;++i;if(utf32>=65536){var ch=utf32-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}else{str+=String.fromCharCode(utf32)}}return str};var stringToUTF32=(str,outPtr,maxBytesToWrite)=>{outPtr>>>=0;maxBytesToWrite??=2147483647;if(maxBytesToWrite<4)return 0;var startPtr=outPtr;var endPtr=startPtr+maxBytesToWrite-4;for(var i=0;i=55296&&codeUnit<=57343){var trailSurrogate=str.charCodeAt(++i);codeUnit=65536+((codeUnit&1023)<<10)|trailSurrogate&1023}HEAP32[outPtr>>>2>>>0]=codeUnit;outPtr+=4;if(outPtr+4>endPtr)break}HEAP32[outPtr>>>2>>>0]=0;return outPtr-startPtr};var lengthBytesUTF32=str=>{var len=0;for(var i=0;i=55296&&codeUnit<=57343)++i;len+=4}return len};var __embind_register_std_wstring=function(rawType,charSize,name){rawType>>>=0;charSize>>>=0;name>>>=0;name=readLatin1String(name);var decodeString,encodeString,readCharAt,lengthBytesUTF;if(charSize===2){decodeString=UTF16ToString;encodeString=stringToUTF16;lengthBytesUTF=lengthBytesUTF16;readCharAt=pointer=>HEAPU16[pointer>>>1>>>0]}else if(charSize===4){decodeString=UTF32ToString;encodeString=stringToUTF32;lengthBytesUTF=lengthBytesUTF32;readCharAt=pointer=>HEAPU32[pointer>>>2>>>0]}registerType(rawType,{name,fromWireType:value=>{var length=HEAPU32[value>>>2>>>0];var str;var decodeStartPtr=value+4;for(var i=0;i<=length;++i){var currentBytePtr=value+4+i*charSize;if(i==length||readCharAt(currentBytePtr)==0){var maxReadBytes=currentBytePtr-decodeStartPtr;var stringSegment=decodeString(decodeStartPtr,maxReadBytes);if(str===undefined){str=stringSegment}else{str+=String.fromCharCode(0);str+=stringSegment}decodeStartPtr=currentBytePtr+charSize}}_free(value);return str},toWireType:(destructors,value)=>{if(!(typeof value=="string")){throwBindingError(`Cannot pass non-string to C++ string type ${name}`)}var length=lengthBytesUTF(value);var ptr=_malloc(4+length+charSize);HEAPU32[ptr>>>2>>>0]=length/charSize;encodeString(value,ptr+4,length+charSize);if(destructors!==null){destructors.push(_free,ptr)}return ptr},argPackAdvance:GenericWireTypeSize,readValueFromPointer:readPointer,destructorFunction(ptr){_free(ptr)}})};var __embind_register_void=function(rawType,name){rawType>>>=0;name>>>=0;name=readLatin1String(name);registerType(rawType,{isVoid:true,name,argPackAdvance:0,fromWireType:()=>undefined,toWireType:(destructors,o)=>undefined})};function __emscripten_fetch_free(id){if(Fetch.xhrs.has(id)){var xhr=Fetch.xhrs.get(id);Fetch.xhrs.free(id);if(xhr.readyState>0&&xhr.readyState<4){xhr.abort()}}}var __emscripten_throw_longjmp=()=>{throw Infinity};var emval_symbols={};var getStringOrSymbol=address=>{var symbol=emval_symbols[address];if(symbol===undefined){return readLatin1String(address)}return symbol};var emval_methodCallers=[];function __emval_call_method(caller,objHandle,methodName,destructorsRef,args){caller>>>=0;objHandle>>>=0;methodName>>>=0;destructorsRef>>>=0;args>>>=0;caller=emval_methodCallers[caller];objHandle=Emval.toValue(objHandle);methodName=getStringOrSymbol(methodName);return caller(objHandle,objHandle[methodName],destructorsRef,args)}var emval_addMethodCaller=caller=>{var id=emval_methodCallers.length;emval_methodCallers.push(caller);return id};var emval_lookupTypes=(argCount,argTypes)=>{var a=new Array(argCount);for(var i=0;i>>2>>>0],"parameter "+i)}return a};var reflectConstruct=Reflect.construct;var emval_returnValue=(returnType,destructorsRef,handle)=>{var destructors=[];var result=returnType["toWireType"](destructors,handle);if(destructors.length){HEAPU32[destructorsRef>>>2>>>0]=Emval.toHandle(destructors)}return result};var __emval_get_method_caller=function(argCount,argTypes,kind){argTypes>>>=0;var types=emval_lookupTypes(argCount,argTypes);var retType=types.shift();argCount--;var argN=new Array(argCount);var invokerFunction=(obj,func,destructorsRef,args)=>{var offset=0;for(var i=0;it.name).join(", ")}) => ${retType.name}>`;return emval_addMethodCaller(createNamedFunction(functionName,invokerFunction))};function __emval_run_destructors(handle){handle>>>=0;var destructors=Emval.toValue(handle);runDestructors(destructors);__emval_decref(handle)}function __emval_take_value(type,arg){type>>>=0;arg>>>=0;type=requireRegisteredType(type,"_emval_take_value");var v=type["readValueFromPointer"](arg);return Emval.toHandle(v)}var isLeapYear=year=>year%4===0&&(year%100!==0||year%400===0);var MONTH_DAYS_LEAP_CUMULATIVE=[0,31,60,91,121,152,182,213,244,274,305,335];var MONTH_DAYS_REGULAR_CUMULATIVE=[0,31,59,90,120,151,181,212,243,273,304,334];var ydayFromDate=date=>{var leap=isLeapYear(date.getFullYear());var monthDaysCumulative=leap?MONTH_DAYS_LEAP_CUMULATIVE:MONTH_DAYS_REGULAR_CUMULATIVE;var yday=monthDaysCumulative[date.getMonth()]+date.getDate()-1;return yday};function __localtime_js(time_low,time_high,tmPtr){var time=convertI32PairToI53Checked(time_low,time_high);tmPtr>>>=0;var date=new Date(time*1e3);HEAP32[tmPtr>>>2>>>0]=date.getSeconds();HEAP32[tmPtr+4>>>2>>>0]=date.getMinutes();HEAP32[tmPtr+8>>>2>>>0]=date.getHours();HEAP32[tmPtr+12>>>2>>>0]=date.getDate();HEAP32[tmPtr+16>>>2>>>0]=date.getMonth();HEAP32[tmPtr+20>>>2>>>0]=date.getFullYear()-1900;HEAP32[tmPtr+24>>>2>>>0]=date.getDay();var yday=ydayFromDate(date)|0;HEAP32[tmPtr+28>>>2>>>0]=yday;HEAP32[tmPtr+36>>>2>>>0]=-(date.getTimezoneOffset()*60);var start=new Date(date.getFullYear(),0,1);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>>2>>>0]=dst}var __tzset_js=function(timezone,daylight,std_name,dst_name){timezone>>>=0;daylight>>>=0;std_name>>>=0;dst_name>>>=0;var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);var winterOffset=winter.getTimezoneOffset();var summerOffset=summer.getTimezoneOffset();var stdTimezoneOffset=Math.max(winterOffset,summerOffset);HEAPU32[timezone>>>2>>>0]=stdTimezoneOffset*60;HEAP32[daylight>>>2>>>0]=Number(winterOffset!=summerOffset);var extractZone=timezoneOffset=>{var sign=timezoneOffset>=0?"-":"+";var absOffset=Math.abs(timezoneOffset);var hours=String(Math.floor(absOffset/60)).padStart(2,"0");var minutes=String(absOffset%60).padStart(2,"0");return`UTC${sign}${hours}${minutes}`};var winterName=extractZone(winterOffset);var summerName=extractZone(summerOffset);if(summerOffsetperformance.now();var _emscripten_date_now=()=>Date.now();var nowIsMonotonic=1;var checkWasiClock=clock_id=>clock_id>=0&&clock_id<=3;function _clock_time_get(clk_id,ignored_precision_low,ignored_precision_high,ptime){var ignored_precision=convertI32PairToI53Checked(ignored_precision_low,ignored_precision_high);ptime>>>=0;if(!checkWasiClock(clk_id)){return 28}var now;if(clk_id===0){now=_emscripten_date_now()}else if(nowIsMonotonic){now=_emscripten_get_now()}else{return 52}var nsec=Math.round(now*1e3*1e3);tempI64=[nsec>>>0,(tempDouble=nsec,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[ptime>>>2>>>0]=tempI64[0],HEAP32[ptime+4>>>2>>>0]=tempI64[1];return 0}var readEmAsmArgsArray=[];var readEmAsmArgs=(sigPtr,buf)=>{readEmAsmArgsArray.length=0;var ch;while(ch=HEAPU8[sigPtr++>>>0]){var wide=ch!=105;wide&=ch!=112;buf+=wide&&buf%8?4:0;readEmAsmArgsArray.push(ch==112?HEAPU32[buf>>>2>>>0]:ch==105?HEAP32[buf>>>2>>>0]:HEAPF64[buf>>>3>>>0]);buf+=wide?8:4}return readEmAsmArgsArray};var runEmAsmFunction=(code,sigPtr,argbuf)=>{var args=readEmAsmArgs(sigPtr,argbuf);return ASM_CONSTS[code](...args)};function _emscripten_asm_const_int(code,sigPtr,argbuf){code>>>=0;sigPtr>>>=0;argbuf>>>=0;return runEmAsmFunction(code,sigPtr,argbuf)}var handleException=e=>{if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)};var runtimeKeepaliveCounter=0;var keepRuntimeAlive=()=>noExitRuntime||runtimeKeepaliveCounter>0;var _proc_exit=code=>{EXITSTATUS=code;if(!keepRuntimeAlive()){Module["onExit"]?.(code);ABORT=true}quit_(code,new ExitStatus(code))};var exitJS=(status,implicit)=>{EXITSTATUS=status;_proc_exit(status)};var _exit=exitJS;var maybeExit=()=>{if(!keepRuntimeAlive()){try{_exit(EXITSTATUS)}catch(e){handleException(e)}}};var callUserCallback=func=>{if(ABORT){return}try{func();maybeExit()}catch(e){handleException(e)}};var safeSetTimeout=(func,timeout)=>setTimeout(()=>{callUserCallback(func)},timeout);var _emscripten_set_main_loop_timing=(mode,value)=>{MainLoop.timingMode=mode;MainLoop.timingValue=value;if(!MainLoop.func){return 1}if(!MainLoop.running){MainLoop.running=true}if(mode==0){MainLoop.scheduler=function MainLoop_scheduler_setTimeout(){var timeUntilNextTick=Math.max(0,MainLoop.tickStartTime+value-_emscripten_get_now())|0;setTimeout(MainLoop.runner,timeUntilNextTick)};MainLoop.method="timeout"}else if(mode==1){MainLoop.scheduler=function MainLoop_scheduler_rAF(){MainLoop.requestAnimationFrame(MainLoop.runner)};MainLoop.method="rAF"}else if(mode==2){if(typeof MainLoop.setImmediate=="undefined"){if(typeof setImmediate=="undefined"){var setImmediates=[];var emscriptenMainLoopMessageId="setimmediate";var MainLoop_setImmediate_messageHandler=event=>{if(event.data===emscriptenMainLoopMessageId||event.data.target===emscriptenMainLoopMessageId){event.stopPropagation();setImmediates.shift()()}};addEventListener("message",MainLoop_setImmediate_messageHandler,true);MainLoop.setImmediate=func=>{setImmediates.push(func);if(ENVIRONMENT_IS_WORKER){Module["setImmediates"]??=[];Module["setImmediates"].push(func);postMessage({target:emscriptenMainLoopMessageId})}else postMessage(emscriptenMainLoopMessageId,"*")}}else{MainLoop.setImmediate=setImmediate}}MainLoop.scheduler=function MainLoop_scheduler_setImmediate(){MainLoop.setImmediate(MainLoop.runner)};MainLoop.method="immediate"}return 0};var setMainLoop=(iterFunc,fps,simulateInfiniteLoop,arg,noSetTiming)=>{MainLoop.func=iterFunc;MainLoop.arg=arg;var thisMainLoopId=MainLoop.currentlyRunningMainloop;function checkIsRunning(){if(thisMainLoopId0){var start=Date.now();var blocker=MainLoop.queue.shift();blocker.func(blocker.arg);if(MainLoop.remainingBlockers){var remaining=MainLoop.remainingBlockers;var next=remaining%1==0?remaining-1:Math.floor(remaining);if(blocker.counted){MainLoop.remainingBlockers=next}else{next=next+.5;MainLoop.remainingBlockers=(8*remaining+next)/9}}MainLoop.updateStatus();if(!checkIsRunning())return;setTimeout(MainLoop.runner,0);return}if(!checkIsRunning())return;MainLoop.currentFrameNumber=MainLoop.currentFrameNumber+1|0;if(MainLoop.timingMode==1&&MainLoop.timingValue>1&&MainLoop.currentFrameNumber%MainLoop.timingValue!=0){MainLoop.scheduler();return}else if(MainLoop.timingMode==0){MainLoop.tickStartTime=_emscripten_get_now()}MainLoop.runIter(iterFunc);if(!checkIsRunning())return;MainLoop.scheduler()};if(!noSetTiming){if(fps&&fps>0){_emscripten_set_main_loop_timing(0,1e3/fps)}else{_emscripten_set_main_loop_timing(1,1)}MainLoop.scheduler()}if(simulateInfiniteLoop){throw"unwind"}};var MainLoop={running:false,scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],preMainLoop:[],postMainLoop:[],pause(){MainLoop.scheduler=null;MainLoop.currentlyRunningMainloop++},resume(){MainLoop.currentlyRunningMainloop++;var timingMode=MainLoop.timingMode;var timingValue=MainLoop.timingValue;var func=MainLoop.func;MainLoop.func=null;setMainLoop(func,0,false,MainLoop.arg,true);_emscripten_set_main_loop_timing(timingMode,timingValue);MainLoop.scheduler()},updateStatus(){if(Module["setStatus"]){var message=Module["statusMessage"]||"Please wait...";var remaining=MainLoop.remainingBlockers??0;var expected=MainLoop.expectedBlockers??0;if(remaining){if(remaining=MainLoop.nextRAF){MainLoop.nextRAF+=1e3/60}}var delay=Math.max(MainLoop.nextRAF-now,0);setTimeout(func,delay)},requestAnimationFrame(func){if(typeof requestAnimationFrame=="function"){requestAnimationFrame(func);return}var RAF=MainLoop.fakeRequestAnimationFrame;RAF(func)}};var safeRequestAnimationFrame=func=>MainLoop.requestAnimationFrame(()=>{callUserCallback(func)});var _emscripten_async_call=function(func,arg,millis){func>>>=0;arg>>>=0;var wrapper=()=>getWasmTableEntry(func)(arg);if(millis>=0){safeSetTimeout(wrapper,millis)}else{safeRequestAnimationFrame(wrapper)}};var _emscripten_cancel_main_loop=()=>{MainLoop.pause();MainLoop.func=null};var __emscripten_runtime_keepalive_clear=()=>{noExitRuntime=false;runtimeKeepaliveCounter=0};var _emscripten_force_exit=status=>{__emscripten_runtime_keepalive_clear();_exit(status)};var _emscripten_is_main_browser_thread=()=>!ENVIRONMENT_IS_WORKER;var getHeapMax=()=>4294901760;var growMemory=size=>{var b=wasmMemory.buffer;var pages=(size-b.byteLength+65535)/65536|0;try{wasmMemory.grow(pages);updateMemoryViews();return 1}catch(e){}};function _emscripten_resize_heap(requestedSize){requestedSize>>>=0;var oldSize=HEAPU8.length;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignMemory(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=growMemory(newSize);if(replacement){return true}}return false}function _emscripten_set_main_loop(func,fps,simulateInfiniteLoop){func>>>=0;var iterFunc=getWasmTableEntry(func);setMainLoop(iterFunc,fps,simulateInfiniteLoop)}class HandleAllocator{allocated=[undefined];freelist=[];get(id){return this.allocated[id]}has(id){return this.allocated[id]!==undefined}allocate(handle){var id=this.freelist.pop()||this.allocated.length;this.allocated[id]=handle;return id}free(id){this.allocated[id]=undefined;this.freelist.push(id)}}var Fetch={openDatabase(dbname,dbversion,onsuccess,onerror){try{var openRequest=indexedDB.open(dbname,dbversion)}catch(e){return onerror(e)}openRequest.onupgradeneeded=event=>{var db=event.target.result;if(db.objectStoreNames.contains("FILES")){db.deleteObjectStore("FILES")}db.createObjectStore("FILES")};openRequest.onsuccess=event=>onsuccess(event.target.result);openRequest.onerror=onerror},init(){Fetch.xhrs=new HandleAllocator;var onsuccess=db=>{Fetch.dbInstance=db;removeRunDependency("library_fetch_init")};var onerror=()=>{Fetch.dbInstance=false;removeRunDependency("library_fetch_init")};addRunDependency("library_fetch_init");Fetch.openDatabase("emscripten_filesystem",1,onsuccess,onerror)}};function fetchXHR(fetch,onsuccess,onerror,onprogress,onreadystatechange){var url=HEAPU32[fetch+8>>>2>>>0];if(!url){onerror(fetch,0,"no url specified!");return}var url_=UTF8ToString(url);var fetch_attr=fetch+108;var requestMethod=UTF8ToString(fetch_attr+0);requestMethod||="GET";var timeoutMsecs=HEAPU32[fetch_attr+56>>>2>>>0];var userName=HEAPU32[fetch_attr+68>>>2>>>0];var password=HEAPU32[fetch_attr+72>>>2>>>0];var requestHeaders=HEAPU32[fetch_attr+76>>>2>>>0];var overriddenMimeType=HEAPU32[fetch_attr+80>>>2>>>0];var dataPtr=HEAPU32[fetch_attr+84>>>2>>>0];var dataLength=HEAPU32[fetch_attr+88>>>2>>>0];var fetchAttributes=HEAPU32[fetch_attr+52>>>2>>>0];var fetchAttrLoadToMemory=!!(fetchAttributes&1);var fetchAttrStreamData=!!(fetchAttributes&2);var fetchAttrSynchronous=!!(fetchAttributes&64);var userNameStr=userName?UTF8ToString(userName):undefined;var passwordStr=password?UTF8ToString(password):undefined;var xhr=new XMLHttpRequest;xhr.withCredentials=!!HEAPU8[fetch_attr+60>>>0];xhr.open(requestMethod,url_,!fetchAttrSynchronous,userNameStr,passwordStr);if(!fetchAttrSynchronous)xhr.timeout=timeoutMsecs;xhr.url_=url_;xhr.responseType="arraybuffer";if(overriddenMimeType){var overriddenMimeTypeStr=UTF8ToString(overriddenMimeType);xhr.overrideMimeType(overriddenMimeTypeStr)}if(requestHeaders){for(;;){var key=HEAPU32[requestHeaders>>>2>>>0];if(!key)break;var value=HEAPU32[requestHeaders+4>>>2>>>0];if(!value)break;requestHeaders+=8;var keyStr=UTF8ToString(key);var valueStr=UTF8ToString(value);xhr.setRequestHeader(keyStr,valueStr)}}var id=Fetch.xhrs.allocate(xhr);HEAPU32[fetch>>>2>>>0]=id;var data=dataPtr&&dataLength?HEAPU8.slice(dataPtr,dataPtr+dataLength):null;function saveResponseAndStatus(){var ptr=0;var ptrLen=0;if(xhr.response&&fetchAttrLoadToMemory&&HEAPU32[fetch+12>>>2>>>0]===0){ptrLen=xhr.response.byteLength}if(ptrLen>0){ptr=_malloc(ptrLen);HEAPU8.set(new Uint8Array(xhr.response),ptr>>>0)}HEAPU32[fetch+12>>>2>>>0]=ptr;writeI53ToI64(fetch+16,ptrLen);writeI53ToI64(fetch+24,0);var len=xhr.response?xhr.response.byteLength:0;if(len){writeI53ToI64(fetch+32,len)}HEAP16[fetch+40>>>1>>>0]=xhr.readyState;HEAP16[fetch+42>>>1>>>0]=xhr.status;if(xhr.statusText)stringToUTF8(xhr.statusText,fetch+44,64)}xhr.onload=e=>{if(!Fetch.xhrs.has(id)){return}saveResponseAndStatus();if(xhr.status>=200&&xhr.status<300){onsuccess?.(fetch,xhr,e)}else{onerror?.(fetch,xhr,e)}};xhr.onerror=e=>{if(!Fetch.xhrs.has(id)){return}saveResponseAndStatus();onerror?.(fetch,xhr,e)};xhr.ontimeout=e=>{if(!Fetch.xhrs.has(id)){return}onerror?.(fetch,xhr,e)};xhr.onprogress=e=>{if(!Fetch.xhrs.has(id)){return}var ptrLen=fetchAttrLoadToMemory&&fetchAttrStreamData&&xhr.response?xhr.response.byteLength:0;var ptr=0;if(ptrLen>0&&fetchAttrLoadToMemory&&fetchAttrStreamData){ptr=_malloc(ptrLen);HEAPU8.set(new Uint8Array(xhr.response),ptr>>>0)}HEAPU32[fetch+12>>>2>>>0]=ptr;writeI53ToI64(fetch+16,ptrLen);writeI53ToI64(fetch+24,e.loaded-ptrLen);writeI53ToI64(fetch+32,e.total);HEAP16[fetch+40>>>1>>>0]=xhr.readyState;if(xhr.readyState>=3&&xhr.status===0&&e.loaded>0)xhr.status=200;HEAP16[fetch+42>>>1>>>0]=xhr.status;if(xhr.statusText)stringToUTF8(xhr.statusText,fetch+44,64);onprogress?.(fetch,xhr,e);if(ptr){_free(ptr)}};xhr.onreadystatechange=e=>{if(!Fetch.xhrs.has(id)){return}HEAP16[fetch+40>>>1>>>0]=xhr.readyState;if(xhr.readyState>=2){HEAP16[fetch+42>>>1>>>0]=xhr.status}onreadystatechange?.(fetch,xhr,e)};try{xhr.send(data)}catch(e){onerror?.(fetch,xhr,e)}}var writeI53ToI64=(ptr,num)=>{HEAPU32[ptr>>>2>>>0]=num;var lower=HEAPU32[ptr>>>2>>>0];HEAPU32[ptr+4>>>2>>>0]=(num-lower)/4294967296};function fetchCacheData(db,fetch,data,onsuccess,onerror){if(!db){onerror(fetch,0,"IndexedDB not available!");return}var fetch_attr=fetch+108;var destinationPath=HEAPU32[fetch_attr+64>>>2>>>0];destinationPath||=HEAPU32[fetch+8>>>2>>>0];var destinationPathStr=UTF8ToString(destinationPath);try{var transaction=db.transaction(["FILES"],"readwrite");var packages=transaction.objectStore("FILES");var putRequest=packages.put(data,destinationPathStr);putRequest.onsuccess=event=>{HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=200;stringToUTF8("OK",fetch+44,64);onsuccess(fetch,0,destinationPathStr)};putRequest.onerror=error=>{HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=413;stringToUTF8("Payload Too Large",fetch+44,64);onerror(fetch,0,error)}}catch(e){onerror(fetch,0,e)}}function fetchLoadCachedData(db,fetch,onsuccess,onerror){if(!db){onerror(fetch,0,"IndexedDB not available!");return}var fetch_attr=fetch+108;var path=HEAPU32[fetch_attr+64>>>2>>>0];path||=HEAPU32[fetch+8>>>2>>>0];var pathStr=UTF8ToString(path);try{var transaction=db.transaction(["FILES"],"readonly");var packages=transaction.objectStore("FILES");var getRequest=packages.get(pathStr);getRequest.onsuccess=event=>{if(event.target.result){var value=event.target.result;var len=value.byteLength||value.length;var ptr=_malloc(len);HEAPU8.set(new Uint8Array(value),ptr>>>0);HEAPU32[fetch+12>>>2>>>0]=ptr;writeI53ToI64(fetch+16,len);writeI53ToI64(fetch+24,0);writeI53ToI64(fetch+32,len);HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=200;stringToUTF8("OK",fetch+44,64);onsuccess(fetch,0,value)}else{HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=404;stringToUTF8("Not Found",fetch+44,64);onerror(fetch,0,"no data")}};getRequest.onerror=error=>{HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=404;stringToUTF8("Not Found",fetch+44,64);onerror(fetch,0,error)}}catch(e){onerror(fetch,0,e)}}function fetchDeleteCachedData(db,fetch,onsuccess,onerror){if(!db){onerror(fetch,0,"IndexedDB not available!");return}var fetch_attr=fetch+108;var path=HEAPU32[fetch_attr+64>>>2>>>0];path||=HEAPU32[fetch+8>>>2>>>0];var pathStr=UTF8ToString(path);try{var transaction=db.transaction(["FILES"],"readwrite");var packages=transaction.objectStore("FILES");var request=packages.delete(pathStr);request.onsuccess=event=>{var value=event.target.result;HEAPU32[fetch+12>>>2>>>0]=0;writeI53ToI64(fetch+16,0);writeI53ToI64(fetch+24,0);writeI53ToI64(fetch+32,0);HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=200;stringToUTF8("OK",fetch+44,64);onsuccess(fetch,0,value)};request.onerror=error=>{HEAP16[fetch+40>>>1>>>0]=4;HEAP16[fetch+42>>>1>>>0]=404;stringToUTF8("Not Found",fetch+44,64);onerror(fetch,0,error)}}catch(e){onerror(fetch,0,e)}}function _emscripten_start_fetch(fetch,successcb,errorcb,progresscb,readystatechangecb){fetch>>>=0;var fetch_attr=fetch+108;var onsuccess=HEAPU32[fetch_attr+36>>>2>>>0];var onerror=HEAPU32[fetch_attr+40>>>2>>>0];var onprogress=HEAPU32[fetch_attr+44>>>2>>>0];var onreadystatechange=HEAPU32[fetch_attr+48>>>2>>>0];var fetchAttributes=HEAPU32[fetch_attr+52>>>2>>>0];var fetchAttrSynchronous=!!(fetchAttributes&64);function doCallback(f){if(fetchAttrSynchronous){f()}else{callUserCallback(f)}}var reportSuccess=(fetch,xhr,e)=>{doCallback(()=>{if(onsuccess)getWasmTableEntry(onsuccess)(fetch);else successcb?.(fetch)})};var reportProgress=(fetch,xhr,e)=>{doCallback(()=>{if(onprogress)getWasmTableEntry(onprogress)(fetch);else progresscb?.(fetch)})};var reportError=(fetch,xhr,e)=>{doCallback(()=>{if(onerror)getWasmTableEntry(onerror)(fetch);else errorcb?.(fetch)})};var reportReadyStateChange=(fetch,xhr,e)=>{doCallback(()=>{if(onreadystatechange)getWasmTableEntry(onreadystatechange)(fetch);else readystatechangecb?.(fetch)})};var performUncachedXhr=(fetch,xhr,e)=>{fetchXHR(fetch,reportSuccess,reportError,reportProgress,reportReadyStateChange)};var cacheResultAndReportSuccess=(fetch,xhr,e)=>{var storeSuccess=(fetch,xhr,e)=>{doCallback(()=>{if(onsuccess)getWasmTableEntry(onsuccess)(fetch);else successcb?.(fetch)})};var storeError=(fetch,xhr,e)=>{doCallback(()=>{if(onsuccess)getWasmTableEntry(onsuccess)(fetch);else successcb?.(fetch)})};fetchCacheData(Fetch.dbInstance,fetch,xhr.response,storeSuccess,storeError)};var performCachedXhr=(fetch,xhr,e)=>{fetchXHR(fetch,cacheResultAndReportSuccess,reportError,reportProgress,reportReadyStateChange)};var requestMethod=UTF8ToString(fetch_attr+0);var fetchAttrReplace=!!(fetchAttributes&16);var fetchAttrPersistFile=!!(fetchAttributes&4);var fetchAttrNoDownload=!!(fetchAttributes&32);if(requestMethod==="EM_IDB_STORE"){var ptr=HEAPU32[fetch_attr+84>>>2>>>0];var size=HEAPU32[fetch_attr+88>>>2>>>0];fetchCacheData(Fetch.dbInstance,fetch,HEAPU8.slice(ptr,ptr+size),reportSuccess,reportError)}else if(requestMethod==="EM_IDB_DELETE"){fetchDeleteCachedData(Fetch.dbInstance,fetch,reportSuccess,reportError)}else if(!fetchAttrReplace){fetchLoadCachedData(Fetch.dbInstance,fetch,reportSuccess,fetchAttrNoDownload?reportError:fetchAttrPersistFile?performCachedXhr:performUncachedXhr)}else if(!fetchAttrNoDownload){fetchXHR(fetch,fetchAttrPersistFile?cacheResultAndReportSuccess:reportSuccess,reportError,reportProgress,reportReadyStateChange)}else{return 0}return fetch}var GLctx;var webgl_enable_ANGLE_instanced_arrays=ctx=>{var ext=ctx.getExtension("ANGLE_instanced_arrays");if(ext){ctx["vertexAttribDivisor"]=(index,divisor)=>ext["vertexAttribDivisorANGLE"](index,divisor);ctx["drawArraysInstanced"]=(mode,first,count,primcount)=>ext["drawArraysInstancedANGLE"](mode,first,count,primcount);ctx["drawElementsInstanced"]=(mode,count,type,indices,primcount)=>ext["drawElementsInstancedANGLE"](mode,count,type,indices,primcount);return 1}};var webgl_enable_OES_vertex_array_object=ctx=>{var ext=ctx.getExtension("OES_vertex_array_object");if(ext){ctx["createVertexArray"]=()=>ext["createVertexArrayOES"]();ctx["deleteVertexArray"]=vao=>ext["deleteVertexArrayOES"](vao);ctx["bindVertexArray"]=vao=>ext["bindVertexArrayOES"](vao);ctx["isVertexArray"]=vao=>ext["isVertexArrayOES"](vao);return 1}};var webgl_enable_WEBGL_draw_buffers=ctx=>{var ext=ctx.getExtension("WEBGL_draw_buffers");if(ext){ctx["drawBuffers"]=(n,bufs)=>ext["drawBuffersWEBGL"](n,bufs);return 1}};var webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance=ctx=>!!(ctx.dibvbi=ctx.getExtension("WEBGL_draw_instanced_base_vertex_base_instance"));var webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance=ctx=>!!(ctx.mdibvbi=ctx.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance"));var webgl_enable_EXT_polygon_offset_clamp=ctx=>!!(ctx.extPolygonOffsetClamp=ctx.getExtension("EXT_polygon_offset_clamp"));var webgl_enable_EXT_clip_control=ctx=>!!(ctx.extClipControl=ctx.getExtension("EXT_clip_control"));var webgl_enable_WEBGL_polygon_mode=ctx=>!!(ctx.webglPolygonMode=ctx.getExtension("WEBGL_polygon_mode"));var webgl_enable_WEBGL_multi_draw=ctx=>!!(ctx.multiDrawWebgl=ctx.getExtension("WEBGL_multi_draw"));var getEmscriptenSupportedExtensions=ctx=>{var supportedExtensions=["ANGLE_instanced_arrays","EXT_blend_minmax","EXT_disjoint_timer_query","EXT_frag_depth","EXT_shader_texture_lod","EXT_sRGB","OES_element_index_uint","OES_fbo_render_mipmap","OES_standard_derivatives","OES_texture_float","OES_texture_half_float","OES_texture_half_float_linear","OES_vertex_array_object","WEBGL_color_buffer_float","WEBGL_depth_texture","WEBGL_draw_buffers","EXT_color_buffer_float","EXT_conservative_depth","EXT_disjoint_timer_query_webgl2","EXT_texture_norm16","NV_shader_noperspective_interpolation","WEBGL_clip_cull_distance","EXT_clip_control","EXT_color_buffer_half_float","EXT_depth_clamp","EXT_float_blend","EXT_polygon_offset_clamp","EXT_texture_compression_bptc","EXT_texture_compression_rgtc","EXT_texture_filter_anisotropic","KHR_parallel_shader_compile","OES_texture_float_linear","WEBGL_blend_func_extended","WEBGL_compressed_texture_astc","WEBGL_compressed_texture_etc","WEBGL_compressed_texture_etc1","WEBGL_compressed_texture_s3tc","WEBGL_compressed_texture_s3tc_srgb","WEBGL_debug_renderer_info","WEBGL_debug_shaders","WEBGL_lose_context","WEBGL_multi_draw","WEBGL_polygon_mode"];return(ctx.getSupportedExtensions()||[]).filter(ext=>supportedExtensions.includes(ext))};var GL={counter:1,buffers:[],programs:[],framebuffers:[],renderbuffers:[],textures:[],shaders:[],vaos:[],contexts:[],offscreenCanvases:{},queries:[],samplers:[],transformFeedbacks:[],syncs:[],stringCache:{},stringiCache:{},unpackAlignment:4,unpackRowLength:0,recordError:errorCode=>{if(!GL.lastError){GL.lastError=errorCode}},getNewId:table=>{var ret=GL.counter++;for(var i=table.length;i{for(var i=0;i>>2>>>0]=id}},getSource:(shader,count,string,length)=>{var source="";for(var i=0;i>>2>>>0]:undefined;source+=UTF8ToString(HEAPU32[string+i*4>>>2>>>0],len)}return source},createContext:(canvas,webGLContextAttributes)=>{var ctx=webGLContextAttributes.majorVersion>1?canvas.getContext("webgl2",webGLContextAttributes):canvas.getContext("webgl",webGLContextAttributes);if(!ctx)return 0;var handle=GL.registerContext(ctx,webGLContextAttributes);return handle},registerContext:(ctx,webGLContextAttributes)=>{var handle=GL.getNewId(GL.contexts);var context={handle,attributes:webGLContextAttributes,version:webGLContextAttributes.majorVersion,GLctx:ctx};if(ctx.canvas)ctx.canvas.GLctxObject=context;GL.contexts[handle]=context;if(typeof webGLContextAttributes.enableExtensionsByDefault=="undefined"||webGLContextAttributes.enableExtensionsByDefault){GL.initExtensions(context)}return handle},makeContextCurrent:contextHandle=>{GL.currentContext=GL.contexts[contextHandle];Module["ctx"]=GLctx=GL.currentContext?.GLctx;return!(contextHandle&&!GLctx)},getContext:contextHandle=>GL.contexts[contextHandle],deleteContext:contextHandle=>{if(GL.currentContext===GL.contexts[contextHandle]){GL.currentContext=null}if(typeof JSEvents=="object"){JSEvents.removeAllHandlersOnTarget(GL.contexts[contextHandle].GLctx.canvas)}if(GL.contexts[contextHandle]&&GL.contexts[contextHandle].GLctx.canvas){GL.contexts[contextHandle].GLctx.canvas.GLctxObject=undefined}GL.contexts[contextHandle]=null},initExtensions:context=>{context||=GL.currentContext;if(context.initExtensionsDone)return;context.initExtensionsDone=true;var GLctx=context.GLctx;webgl_enable_WEBGL_multi_draw(GLctx);webgl_enable_EXT_polygon_offset_clamp(GLctx);webgl_enable_EXT_clip_control(GLctx);webgl_enable_WEBGL_polygon_mode(GLctx);webgl_enable_ANGLE_instanced_arrays(GLctx);webgl_enable_OES_vertex_array_object(GLctx);webgl_enable_WEBGL_draw_buffers(GLctx);webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx);webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx);if(context.version>=2){GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query_webgl2")}if(context.version<2||!GLctx.disjointTimerQueryExt){GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query")}getEmscriptenSupportedExtensions(GLctx).forEach(ext=>{if(!ext.includes("lose_context")&&!ext.includes("debug")){GLctx.getExtension(ext)}})}};var JSEvents={memcpy(target,src,size){HEAP8.set(HEAP8.subarray(src>>>0,src+size>>>0),target>>>0)},removeAllEventListeners(){while(JSEvents.eventHandlers.length){JSEvents._removeHandler(JSEvents.eventHandlers.length-1)}JSEvents.deferredCalls=[]},inEventHandler:0,deferredCalls:[],deferCall(targetFunction,precedence,argsList){function arraysHaveEqualContent(arrA,arrB){if(arrA.length!=arrB.length)return false;for(var i in arrA){if(arrA[i]!=arrB[i])return false}return true}for(var call of JSEvents.deferredCalls){if(call.targetFunction==targetFunction&&arraysHaveEqualContent(call.argsList,argsList)){return}}JSEvents.deferredCalls.push({targetFunction,precedence,argsList});JSEvents.deferredCalls.sort((x,y)=>x.precedencecall.targetFunction!=targetFunction)},canPerformEventHandlerRequests(){if(navigator.userActivation){return navigator.userActivation.isActive}return JSEvents.inEventHandler&&JSEvents.currentEventHandler.allowsDeferredCalls},runDeferredCalls(){if(!JSEvents.canPerformEventHandlerRequests()){return}var deferredCalls=JSEvents.deferredCalls;JSEvents.deferredCalls=[];for(var call of deferredCalls){call.targetFunction(...call.argsList)}},eventHandlers:[],removeAllHandlersOnTarget:(target,eventTypeString)=>{for(var i=0;icString>2?UTF8ToString(cString):cString;var specialHTMLTargets=[0,document,window];var findEventTarget=target=>{target=maybeCStringToJsString(target);var domElement=specialHTMLTargets[target]||document.querySelector(target);return domElement};var findCanvasEventTarget=findEventTarget;function _emscripten_webgl_do_create_context(target,attributes){target>>>=0;attributes>>>=0;var attr32=attributes>>>2;var powerPreference=HEAP32[attr32+(8>>2)>>>0];var contextAttributes={alpha:!!HEAP8[attributes+0>>>0],depth:!!HEAP8[attributes+1>>>0],stencil:!!HEAP8[attributes+2>>>0],antialias:!!HEAP8[attributes+3>>>0],premultipliedAlpha:!!HEAP8[attributes+4>>>0],preserveDrawingBuffer:!!HEAP8[attributes+5>>>0],powerPreference:webglPowerPreferences[powerPreference],failIfMajorPerformanceCaveat:!!HEAP8[attributes+12>>>0],majorVersion:HEAP32[attr32+(16>>2)>>>0],minorVersion:HEAP32[attr32+(20>>2)>>>0],enableExtensionsByDefault:HEAP8[attributes+24>>>0],explicitSwapControl:HEAP8[attributes+25>>>0],proxyContextToMainThread:HEAP32[attr32+(28>>2)>>>0],renderViaOffscreenBackBuffer:HEAP8[attributes+32>>>0]};var canvas=findCanvasEventTarget(target);if(!canvas){return 0}if(contextAttributes.explicitSwapControl){return 0}var contextHandle=GL.createContext(canvas,contextAttributes);return contextHandle}var _emscripten_webgl_create_context=_emscripten_webgl_do_create_context;function _emscripten_webgl_do_get_current_context(){return GL.currentContext?GL.currentContext.handle:0}var _emscripten_webgl_get_current_context=_emscripten_webgl_do_get_current_context;function _emscripten_webgl_make_context_current(contextHandle){contextHandle>>>=0;var success=GL.makeContextCurrent(contextHandle);return success?0:-5}var ENV={};var getExecutableName=()=>thisProgram||"./this.program";var getEnvStrings=()=>{if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={USER:"web_user",LOGNAME:"web_user",PATH:"/",PWD:"/",HOME:"/home/web_user",LANG:lang,_:getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(`${x}=${env[x]}`)}getEnvStrings.strings=strings}return getEnvStrings.strings};var stringToAscii=(str,buffer)=>{for(var i=0;i>>0]=str.charCodeAt(i)}HEAP8[buffer>>>0]=0};var _environ_get=function(__environ,environ_buf){__environ>>>=0;environ_buf>>>=0;var bufSize=0;getEnvStrings().forEach((string,i)=>{var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>>2>>>0]=ptr;stringToAscii(string,ptr);bufSize+=string.length+1});return 0};var _environ_sizes_get=function(penviron_count,penviron_buf_size){penviron_count>>>=0;penviron_buf_size>>>=0;var strings=getEnvStrings();HEAPU32[penviron_count>>>2>>>0]=strings.length;var bufSize=0;strings.forEach(string=>bufSize+=string.length+1);HEAPU32[penviron_buf_size>>>2>>>0]=bufSize;return 0};function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doReadv=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>>2>>>0];var len=HEAPU32[iov+4>>>2>>>0];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>>=0;iovcnt>>>=0;pnum>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doReadv(stream,iov,iovcnt);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){var offset=convertI32PairToI53Checked(offset_low,offset_high);newOffset>>>=0;try{if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?+Math.floor(tempDouble/4294967296)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>>2>>>0]=tempI64[0],HEAP32[newOffset+4>>>2>>>0]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var doWritev=(stream,iov,iovcnt,offset)=>{var ret=0;for(var i=0;i>>2>>>0];var len=HEAPU32[iov+4>>>2>>>0];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr>>=0;iovcnt>>>=0;pnum>>>=0;try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>>2>>>0]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e.name==="ErrnoError"))throw e;return e.errno}}var _glActiveTexture=x0=>GLctx.activeTexture(x0);var _glAttachShader=(program,shader)=>{GLctx.attachShader(GL.programs[program],GL.shaders[shader])};function _glBindAttribLocation(program,index,name){name>>>=0;GLctx.bindAttribLocation(GL.programs[program],index,UTF8ToString(name))}var _glBindBuffer=(target,buffer)=>{if(target==35051){GLctx.currentPixelPackBufferBinding=buffer}else if(target==35052){GLctx.currentPixelUnpackBufferBinding=buffer}GLctx.bindBuffer(target,GL.buffers[buffer])};var _glBindBufferBase=(target,index,buffer)=>{GLctx.bindBufferBase(target,index,GL.buffers[buffer])};var _glBindFramebuffer=(target,framebuffer)=>{GLctx.bindFramebuffer(target,GL.framebuffers[framebuffer])};var _glBindTexture=(target,texture)=>{GLctx.bindTexture(target,GL.textures[texture])};var _glBlendColor=(x0,x1,x2,x3)=>GLctx.blendColor(x0,x1,x2,x3);var _glBlendEquation=x0=>GLctx.blendEquation(x0);var _glBlendFuncSeparate=(x0,x1,x2,x3)=>GLctx.blendFuncSeparate(x0,x1,x2,x3);function _glBufferData(target,size,data,usage){size>>>=0;data>>>=0;GLctx.bufferData(target,data?HEAPU8.subarray(data>>>0,data+size>>>0):size,usage)}function _glBufferSubData(target,offset,size,data){offset>>>=0;size>>>=0;data>>>=0;GLctx.bufferSubData(target,offset,HEAPU8.subarray(data>>>0,data+size>>>0))}var _glCheckFramebufferStatus=x0=>GLctx.checkFramebufferStatus(x0);var _glClear=x0=>GLctx.clear(x0);var _glClearColor=(x0,x1,x2,x3)=>GLctx.clearColor(x0,x1,x2,x3);var _glColorMask=(red,green,blue,alpha)=>{GLctx.colorMask(!!red,!!green,!!blue,!!alpha)};var _glCompileShader=shader=>{GLctx.compileShader(GL.shaders[shader])};function _glCompressedTexImage2D(target,level,internalFormat,width,height,border,imageSize,data){data>>>=0;if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding||!imageSize){GLctx.compressedTexImage2D(target,level,internalFormat,width,height,border,imageSize,data);return}}GLctx.compressedTexImage2D(target,level,internalFormat,width,height,border,HEAPU8.subarray(data>>>0,data+imageSize>>>0))}var _glCreateProgram=()=>{var id=GL.getNewId(GL.programs);var program=GLctx.createProgram();program.name=id;program.maxUniformLength=program.maxAttributeLength=program.maxUniformBlockNameLength=0;program.uniformIdCounter=1;GL.programs[id]=program;return id};var _glCreateShader=shaderType=>{var id=GL.getNewId(GL.shaders);GL.shaders[id]=GLctx.createShader(shaderType);return id};var _glCullFace=x0=>GLctx.cullFace(x0);function _glDeleteBuffers(n,buffers){buffers>>>=0;for(var i=0;i>>2>>>0];var buffer=GL.buffers[id];if(!buffer)continue;GLctx.deleteBuffer(buffer);buffer.name=0;GL.buffers[id]=null;if(id==GLctx.currentPixelPackBufferBinding)GLctx.currentPixelPackBufferBinding=0;if(id==GLctx.currentPixelUnpackBufferBinding)GLctx.currentPixelUnpackBufferBinding=0}}function _glDeleteFramebuffers(n,framebuffers){framebuffers>>>=0;for(var i=0;i>>2>>>0];var framebuffer=GL.framebuffers[id];if(!framebuffer)continue;GLctx.deleteFramebuffer(framebuffer);framebuffer.name=0;GL.framebuffers[id]=null}}var _glDeleteProgram=id=>{if(!id)return;var program=GL.programs[id];if(!program){GL.recordError(1281);return}GLctx.deleteProgram(program);program.name=0;GL.programs[id]=null};function _glDeleteRenderbuffers(n,renderbuffers){renderbuffers>>>=0;for(var i=0;i>>2>>>0];var renderbuffer=GL.renderbuffers[id];if(!renderbuffer)continue;GLctx.deleteRenderbuffer(renderbuffer);renderbuffer.name=0;GL.renderbuffers[id]=null}}var _glDeleteShader=id=>{if(!id)return;var shader=GL.shaders[id];if(!shader){GL.recordError(1281);return}GLctx.deleteShader(shader);GL.shaders[id]=null};function _glDeleteTextures(n,textures){textures>>>=0;for(var i=0;i>>2>>>0];var texture=GL.textures[id];if(!texture)continue;GLctx.deleteTexture(texture);texture.name=0;GL.textures[id]=null}}var _glDepthFunc=x0=>GLctx.depthFunc(x0);var _glDepthMask=flag=>{GLctx.depthMask(!!flag)};var _glDetachShader=(program,shader)=>{GLctx.detachShader(GL.programs[program],GL.shaders[shader])};var _glDisable=x0=>GLctx.disable(x0);var _glDisableVertexAttribArray=index=>{GLctx.disableVertexAttribArray(index)};var _glDrawArrays=(mode,first,count)=>{GLctx.drawArrays(mode,first,count)};function _glDrawElements(mode,count,type,indices){indices>>>=0;GLctx.drawElements(mode,count,type,indices)}function _glDrawElementsInstanced(mode,count,type,indices,primcount){indices>>>=0;GLctx.drawElementsInstanced(mode,count,type,indices,primcount)}var _glEnable=x0=>GLctx.enable(x0);var _glEnableVertexAttribArray=index=>{GLctx.enableVertexAttribArray(index)};var _glFramebufferTexture2D=(target,attachment,textarget,texture,level)=>{GLctx.framebufferTexture2D(target,attachment,textarget,GL.textures[texture],level)};var _glFrontFace=x0=>GLctx.frontFace(x0);function _glGenBuffers(n,buffers){buffers>>>=0;GL.genObject(n,buffers,"createBuffer",GL.buffers)}function _glGenFramebuffers(n,ids){ids>>>=0;GL.genObject(n,ids,"createFramebuffer",GL.framebuffers)}function _glGenTextures(n,textures){textures>>>=0;GL.genObject(n,textures,"createTexture",GL.textures)}var _glGenerateMipmap=x0=>GLctx.generateMipmap(x0);var __glGetActiveAttribOrUniform=(funcName,program,index,bufSize,length,size,type,name)=>{program=GL.programs[program];var info=GLctx[funcName](program,index);if(info){var numBytesWrittenExclNull=name&&stringToUTF8(info.name,name,bufSize);if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull;if(size)HEAP32[size>>>2>>>0]=info.size;if(type)HEAP32[type>>>2>>>0]=info.type}};function _glGetActiveUniform(program,index,bufSize,length,size,type,name){length>>>=0;size>>>=0;type>>>=0;name>>>=0;return __glGetActiveAttribOrUniform("getActiveUniform",program,index,bufSize,length,size,type,name)}var webglGetExtensions=()=>{var exts=getEmscriptenSupportedExtensions(GLctx);exts=exts.concat(exts.map(e=>"GL_"+e));return exts};var emscriptenWebGLGet=(name_,p,type)=>{if(!p){GL.recordError(1281);return}var ret=undefined;switch(name_){case 36346:ret=1;break;case 36344:if(type!=0&&type!=1){GL.recordError(1280)}return;case 34814:case 36345:ret=0;break;case 34466:var formats=GLctx.getParameter(34467);ret=formats?formats.length:0;break;case 33309:if(GL.currentContext.version<2){GL.recordError(1282);return}ret=webglGetExtensions().length;break;case 33307:case 33308:if(GL.currentContext.version<2){GL.recordError(1280);return}ret=name_==33307?3:0;break}if(ret===undefined){var result=GLctx.getParameter(name_);switch(typeof result){case"number":ret=result;break;case"boolean":ret=result?1:0;break;case"string":GL.recordError(1280);return;case"object":if(result===null){switch(name_){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 36662:case 36663:case 35053:case 35055:case 36010:case 35097:case 35869:case 32874:case 36389:case 35983:case 35368:case 34068:{ret=0;break}default:{GL.recordError(1280);return}}}else if(result instanceof Float32Array||result instanceof Uint32Array||result instanceof Int32Array||result instanceof Array){for(var i=0;i>>2>>>0]=result[i];break;case 2:HEAPF32[p+i*4>>>2>>>0]=result[i];break;case 4:HEAP8[p+i>>>0]=result[i]?1:0;break}}return}else{try{ret=result.name|0}catch(e){GL.recordError(1280);err(`GL_INVALID_ENUM in glGet${type}v: Unknown object returned from WebGL getParameter(${name_})! (error: ${e})`);return}}break;default:GL.recordError(1280);err(`GL_INVALID_ENUM in glGet${type}v: Native code calling glGet${type}v(${name_}) and it returns ${result} of type ${typeof result}!`);return}}switch(type){case 1:writeI53ToI64(p,ret);break;case 0:HEAP32[p>>>2>>>0]=ret;break;case 2:HEAPF32[p>>>2>>>0]=ret;break;case 4:HEAP8[p>>>0]=ret?1:0;break}};function _glGetIntegerv(name_,p){p>>>=0;return emscriptenWebGLGet(name_,p,0)}function _glGetProgramInfoLog(program,maxLength,length,infoLog){length>>>=0;infoLog>>>=0;var log=GLctx.getProgramInfoLog(GL.programs[program]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}function _glGetProgramiv(program,pname,p){p>>>=0;if(!p){GL.recordError(1281);return}if(program>=GL.counter){GL.recordError(1281);return}program=GL.programs[program];if(pname==35716){var log=GLctx.getProgramInfoLog(program);if(log===null)log="(unknown error)";HEAP32[p>>>2>>>0]=log.length+1}else if(pname==35719){if(!program.maxUniformLength){var numActiveUniforms=GLctx.getProgramParameter(program,35718);for(var i=0;i>>2>>>0]=program.maxUniformLength}else if(pname==35722){if(!program.maxAttributeLength){var numActiveAttributes=GLctx.getProgramParameter(program,35721);for(var i=0;i>>2>>>0]=program.maxAttributeLength}else if(pname==35381){if(!program.maxUniformBlockNameLength){var numActiveUniformBlocks=GLctx.getProgramParameter(program,35382);for(var i=0;i>>2>>>0]=program.maxUniformBlockNameLength}else{HEAP32[p>>>2>>>0]=GLctx.getProgramParameter(program,pname)}}function _glGetShaderInfoLog(shader,maxLength,length,infoLog){length>>>=0;infoLog>>>=0;var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>>2>>>0]=numBytesWrittenExclNull}function _glGetShaderiv(shader,pname,p){p>>>=0;if(!p){GL.recordError(1281);return}if(pname==35716){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var logLength=log?log.length+1:0;HEAP32[p>>>2>>>0]=logLength}else if(pname==35720){var source=GLctx.getShaderSource(GL.shaders[shader]);var sourceLength=source?source.length+1:0;HEAP32[p>>>2>>>0]=sourceLength}else{HEAP32[p>>>2>>>0]=GLctx.getShaderParameter(GL.shaders[shader],pname)}}var stringToNewUTF8=str=>{var size=lengthBytesUTF8(str)+1;var ret=_malloc(size);if(ret)stringToUTF8(str,ret,size);return ret};function _glGetString(name_){var ret=GL.stringCache[name_];if(!ret){switch(name_){case 7939:ret=stringToNewUTF8(webglGetExtensions().join(" "));break;case 7936:case 7937:case 37445:case 37446:var s=GLctx.getParameter(name_);if(!s){GL.recordError(1280)}ret=s?stringToNewUTF8(s):0;break;case 7938:var webGLVersion=GLctx.getParameter(7938);var glVersion=`OpenGL ES 2.0 (${webGLVersion})`;if(GL.currentContext.version>=2)glVersion=`OpenGL ES 3.0 (${webGLVersion})`;ret=stringToNewUTF8(glVersion);break;case 35724:var glslVersion=GLctx.getParameter(35724);var ver_re=/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/;var ver_num=glslVersion.match(ver_re);if(ver_num!==null){if(ver_num[1].length==3)ver_num[1]=ver_num[1]+"0";glslVersion=`OpenGL ES GLSL ES ${ver_num[1]} (${glslVersion})`}ret=stringToNewUTF8(glslVersion);break;default:GL.recordError(1280)}GL.stringCache[name_]=ret}return ret}function _glGetUniformBlockIndex(program,uniformBlockName){uniformBlockName>>>=0;return GLctx.getUniformBlockIndex(GL.programs[program],UTF8ToString(uniformBlockName))}var jstoi_q=str=>parseInt(str);var webglGetLeftBracePos=name=>name.slice(-1)=="]"&&name.lastIndexOf("[");var webglPrepareUniformLocationsBeforeFirstUse=program=>{var uniformLocsById=program.uniformLocsById,uniformSizeAndIdsByName=program.uniformSizeAndIdsByName,i,j;if(!uniformLocsById){program.uniformLocsById=uniformLocsById={};program.uniformArrayNamesById={};var numActiveUniforms=GLctx.getProgramParameter(program,35718);for(i=0;i0?nm.slice(0,lb):nm;var id=program.uniformIdCounter;program.uniformIdCounter+=sz;uniformSizeAndIdsByName[arrayName]=[sz,id];for(j=0;j>>=0;name=UTF8ToString(name);if(program=GL.programs[program]){webglPrepareUniformLocationsBeforeFirstUse(program);var uniformLocsById=program.uniformLocsById;var arrayIndex=0;var uniformBaseName=name;var leftBrace=webglGetLeftBracePos(name);if(leftBrace>0){arrayIndex=jstoi_q(name.slice(leftBrace+1))>>>0;uniformBaseName=name.slice(0,leftBrace)}var sizeAndId=program.uniformSizeAndIdsByName[uniformBaseName];if(sizeAndId&&arrayIndex{program=GL.programs[program];GLctx.linkProgram(program);program.uniformLocsById=0;program.uniformSizeAndIdsByName={}};var _glPixelStorei=(pname,param)=>{if(pname==3317){GL.unpackAlignment=param}else if(pname==3314){GL.unpackRowLength=param}GLctx.pixelStorei(pname,param)};var computeUnpackAlignedImageSize=(width,height,sizePerPixel)=>{function roundedToNextMultipleOf(x,y){return x+y-1&-y}var plainRowSize=(GL.unpackRowLength||width)*sizePerPixel;var alignedRowSize=roundedToNextMultipleOf(plainRowSize,GL.unpackAlignment);return height*alignedRowSize};var colorChannelsInGlTextureFormat=format=>{var colorChannels={5:3,6:4,8:2,29502:3,29504:4,26917:2,26918:2,29846:3,29847:4};return colorChannels[format-6402]||1};var heapObjectForWebGLType=type=>{type-=5120;if(type==0)return HEAP8;if(type==1)return HEAPU8;if(type==2)return HEAP16;if(type==4)return HEAP32;if(type==6)return HEAPF32;if(type==5||type==28922||type==28520||type==30779||type==30782)return HEAPU32;return HEAPU16};var toTypedArrayIndex=(pointer,heap)=>pointer>>>31-Math.clz32(heap.BYTES_PER_ELEMENT);var emscriptenWebGLGetTexPixelData=(type,format,width,height,pixels,internalFormat)=>{var heap=heapObjectForWebGLType(type);var sizePerPixel=colorChannelsInGlTextureFormat(format)*heap.BYTES_PER_ELEMENT;var bytes=computeUnpackAlignedImageSize(width,height,sizePerPixel);return heap.subarray(toTypedArrayIndex(pixels,heap)>>>0,toTypedArrayIndex(pixels+bytes,heap)>>>0)};function _glReadPixels(x,y,width,height,format,type,pixels){pixels>>>=0;if(GL.currentContext.version>=2){if(GLctx.currentPixelPackBufferBinding){GLctx.readPixels(x,y,width,height,format,type,pixels);return}}var pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,format);if(!pixelData){GL.recordError(1280);return}GLctx.readPixels(x,y,width,height,format,type,pixelData)}var _glScissor=(x0,x1,x2,x3)=>GLctx.scissor(x0,x1,x2,x3);function _glShaderSource(shader,count,string,length){string>>>=0;length>>>=0;var source=GL.getSource(shader,count,string,length);GLctx.shaderSource(GL.shaders[shader],source)}function _glTexImage2D(target,level,internalFormat,width,height,border,format,type,pixels){pixels>>>=0;if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels);return}}var pixelData=pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat):null;GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixelData)}var _glTexParameteri=(x0,x1,x2)=>GLctx.texParameteri(x0,x1,x2);var webglGetUniformLocation=location=>{var p=GLctx.currentProgram;if(p){var webglLoc=p.uniformLocsById[location];if(typeof webglLoc=="number"){p.uniformLocsById[location]=webglLoc=GLctx.getUniformLocation(p,p.uniformArrayNamesById[location]+(webglLoc>0?`[${webglLoc}]`:""))}return webglLoc}else{GL.recordError(1282)}};var _glUniform1i=(location,v0)=>{GLctx.uniform1i(webglGetUniformLocation(location),v0)};var _glUniformBlockBinding=(program,uniformBlockIndex,uniformBlockBinding)=>{program=GL.programs[program];GLctx.uniformBlockBinding(program,uniformBlockIndex,uniformBlockBinding)};var _glUseProgram=program=>{program=GL.programs[program];GLctx.useProgram(program);GLctx.currentProgram=program};var _glVertexAttribDivisor=(index,divisor)=>{GLctx.vertexAttribDivisor(index,divisor)};function _glVertexAttribPointer(index,size,type,normalized,stride,ptr){ptr>>>=0;GLctx.vertexAttribPointer(index,size,type,!!normalized,stride,ptr)}var _glViewport=(x0,x1,x2,x3)=>GLctx.viewport(x0,x1,x2,x3);var stackAlloc=sz=>__emscripten_stack_alloc(sz);var stringToUTF8OnStack=str=>{var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8(str,ret,size);return ret};var getCFunc=ident=>{var func=Module["_"+ident];return func};var writeArrayToMemory=(array,buffer)=>{HEAP8.set(array,buffer>>>0)};var ccall=(ident,returnType,argTypes,args,opts)=>{var toC={string:str=>{var ret=0;if(str!==null&&str!==undefined&&str!==0){ret=stringToUTF8OnStack(str)}return ret},array:arr=>{var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i{var numericArgs=!argTypes||argTypes.every(type=>type==="number"||type==="boolean");var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return(...args)=>ccall(ident,returnType,argTypes,args,opts)};FS.createPreloadedFile=FS_createPreloadedFile;FS.staticInit();MEMFS.doesNotExistError=new FS.ErrnoError(44);MEMFS.doesNotExistError.stack="";BindingError=Module["BindingError"]=class BindingError extends Error{constructor(message){super(message);this.name="BindingError"}};init_emval();PureVirtualError=Module["PureVirtualError"]=extendError(Error,"PureVirtualError");embind_init_charCodes();InternalError=Module["InternalError"]=class InternalError extends Error{constructor(message){super(message);this.name="InternalError"}};init_ClassHandle();init_RegisteredPointer();UnboundTypeError=Module["UnboundTypeError"]=extendError(Error,"UnboundTypeError");Module["requestAnimationFrame"]=MainLoop.requestAnimationFrame;Module["pauseMainLoop"]=MainLoop.pause;Module["resumeMainLoop"]=MainLoop.resume;MainLoop.init();Fetch.init();var wasmImports={f:___cxa_throw,U:___syscall_fcntl64,ib:___syscall_ioctl,jb:___syscall_openat,gb:___syscall_stat64,lb:__abort_js,_:__embind_create_inheriting_constructor,Za:__embind_register_bigint,Y:__embind_register_bool,d:__embind_register_class,e:__embind_register_class_class_function,g:__embind_register_class_constructor,a:__embind_register_class_function,c:__embind_register_class_property,W:__embind_register_emval,h:__embind_register_enum,b:__embind_register_enum_value,H:__embind_register_float,j:__embind_register_function,o:__embind_register_integer,k:__embind_register_memory_view,X:__embind_register_std_string,D:__embind_register_std_wstring,Z:__embind_register_void,Ca:__emscripten_fetch_free,bb:__emscripten_throw_longjmp,t:__emval_call_method,aa:__emval_decref,s:__emval_get_method_caller,$:__emval_run_destructors,v:__emval_take_value,Wa:__localtime_js,db:__tzset_js,Ya:_clock_time_get,K:_emscripten_asm_const_int,ba:_emscripten_async_call,wa:_emscripten_cancel_main_loop,kb:_emscripten_date_now,mb:_emscripten_force_exit,Sa:_emscripten_is_main_browser_thread,cb:_emscripten_resize_heap,na:_emscripten_set_main_loop,La:_emscripten_start_fetch,J:_emscripten_webgl_create_context,ha:_emscripten_webgl_get_current_context,I:_emscripten_webgl_make_context_current,eb:_environ_get,fb:_environ_sizes_get,V:_fd_close,hb:_fd_read,Xa:_fd_seek,T:_fd_write,ca:get_host,ra:_glActiveTexture,P:_glAttachShader,l:_glBindAttribLocation,m:_glBindBuffer,ua:_glBindBufferBase,r:_glBindFramebuffer,q:_glBindTexture,Ka:_glBlendColor,Ja:_glBlendEquation,Ma:_glBlendFuncSeparate,w:_glBufferData,da:_glBufferSubData,L:_glCheckFramebufferStatus,Ta:_glClear,Ua:_glClearColor,Ga:_glColorMask,oa:_glCompileShader,B:_glCompressedTexImage2D,Ba:_glCreateProgram,qa:_glCreateShader,Qa:_glCullFace,S:_glDeleteBuffers,Ea:_glDeleteFramebuffers,Q:_glDeleteProgram,Da:_glDeleteRenderbuffers,O:_glDeleteShader,Fa:_glDeleteTextures,Na:_glDepthFunc,Oa:_glDepthMask,R:_glDetachShader,z:_glDisable,Ra:_glDisableVertexAttribArray,fa:_glDrawArrays,ga:_glDrawElements,ea:_glDrawElementsInstanced,y:_glEnable,ka:_glEnableVertexAttribArray,E:_glFramebufferTexture2D,Pa:_glFrontFace,x:_glGenBuffers,M:_glGenFramebuffers,C:_glGenTextures,Va:_glGenerateMipmap,xa:_glGetActiveUniform,p:_glGetIntegerv,za:_glGetProgramInfoLog,F:_glGetProgramiv,ma:_glGetShaderInfoLog,N:_glGetShaderiv,u:_glGetString,ya:_glGetUniformBlockIndex,va:_glGetUniformLocation,Aa:_glLinkProgram,la:_glPixelStorei,Ia:_glReadPixels,Ha:_glScissor,pa:_glShaderSource,n:_glTexImage2D,i:_glTexParameteri,sa:_glUniform1i,ta:_glUniformBlockBinding,G:_glUseProgram,ia:_glVertexAttribDivisor,ja:_glVertexAttribPointer,A:_glViewport,$a:invoke_iii,ab:invoke_iiii,_a:invoke_iiiii};var wasmExports;createWasm();var ___wasm_call_ctors=()=>(___wasm_call_ctors=wasmExports["ob"])();var ___getTypeName=a0=>(___getTypeName=wasmExports["pb"])(a0);var _free=Module["_free"]=a0=>(_free=Module["_free"]=wasmExports["qb"])(a0);var _malloc=Module["_malloc"]=a0=>(_malloc=Module["_malloc"]=wasmExports["rb"])(a0);var _SCRTFillActiveTextureCharArray=Module["_SCRTFillActiveTextureCharArray"]=(a0,a1,a2)=>(_SCRTFillActiveTextureCharArray=Module["_SCRTFillActiveTextureCharArray"]=wasmExports["tb"])(a0,a1,a2);var _main=Module["_main"]=(a0,a1)=>(_main=Module["_main"]=wasmExports["ub"])(a0,a1);var _setThrew=Module["_setThrew"]=(a0,a1)=>(_setThrew=Module["_setThrew"]=wasmExports["vb"])(a0,a1);var __emscripten_stack_restore=a0=>(__emscripten_stack_restore=wasmExports["wb"])(a0);var __emscripten_stack_alloc=a0=>(__emscripten_stack_alloc=wasmExports["xb"])(a0);var _emscripten_stack_get_current=()=>(_emscripten_stack_get_current=wasmExports["yb"])();var dynCall_jiji=Module["dynCall_jiji"]=(a0,a1,a2,a3,a4)=>(dynCall_jiji=Module["dynCall_jiji"]=wasmExports["zb"])(a0,a1,a2,a3,a4);var dynCall_viijii=Module["dynCall_viijii"]=(a0,a1,a2,a3,a4,a5,a6)=>(dynCall_viijii=Module["dynCall_viijii"]=wasmExports["Ab"])(a0,a1,a2,a3,a4,a5,a6);var dynCall_iiiiij=Module["dynCall_iiiiij"]=(a0,a1,a2,a3,a4,a5,a6)=>(dynCall_iiiiij=Module["dynCall_iiiiij"]=wasmExports["Bb"])(a0,a1,a2,a3,a4,a5,a6);var dynCall_iiiiijj=Module["dynCall_iiiiijj"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8)=>(dynCall_iiiiijj=Module["dynCall_iiiiijj"]=wasmExports["Cb"])(a0,a1,a2,a3,a4,a5,a6,a7,a8);var dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9)=>(dynCall_iiiiiijj=Module["dynCall_iiiiiijj"]=wasmExports["Db"])(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9);function invoke_iiii(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iii(index,a1,a2){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiii(index,a1,a2,a3,a4){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function applySignatureConversions(wasmExports){wasmExports=Object.assign({},wasmExports);var makeWrapper_pp=f=>a0=>f(a0)>>>0;var makeWrapper_p=f=>()=>f()>>>0;wasmExports["pb"]=makeWrapper_pp(wasmExports["pb"]);wasmExports["rb"]=makeWrapper_pp(wasmExports["rb"]);wasmExports["xb"]=makeWrapper_pp(wasmExports["xb"]);wasmExports["yb"]=makeWrapper_p(wasmExports["yb"]);return wasmExports}Module["callMain"]=callMain;Module["ccall"]=ccall;Module["cwrap"]=cwrap;Module["UTF8ToString"]=UTF8ToString;Module["stringToUTF8"]=stringToUTF8;Module["lengthBytesUTF8"]=lengthBytesUTF8;Module["specialHTMLTargets"]=specialHTMLTargets;var calledRun;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function callMain(args=[]){var entryFunction=_main;args.unshift(thisProgram);var argc=args.length;var argv=stackAlloc((argc+1)*4);var argv_ptr=argv;args.forEach(arg=>{HEAPU32[argv_ptr>>>2>>>0]=stringToUTF8OnStack(arg);argv_ptr+=4});HEAPU32[argv_ptr>>>2>>>0]=0;try{var ret=entryFunction(argc,argv);exitJS(ret,true);return ret}catch(e){return handleException(e)}}function run(args=arguments_){if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);Module["onRuntimeInitialized"]?.();if(shouldRunNow)callMain(args);postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(()=>{setTimeout(()=>Module["setStatus"](""),1);doRun()},1)}else{doRun()}}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}var shouldRunNow=true;if(Module["noInitialRun"])shouldRunNow=false;run();if(GL){GL.getNewId=function(table){GL.counter++;var len=table.length;if(len===0){return 1}for(var i=1;i Module); diff --git a/frontend/public/scichart/scichart3d.wasm b/frontend/public/scichart/scichart3d.wasm deleted file mode 100644 index f8380f45..00000000 Binary files a/frontend/public/scichart/scichart3d.wasm and /dev/null differ diff --git a/frontend/src/app.css b/frontend/src/app.css new file mode 100644 index 00000000..b72d7838 --- /dev/null +++ b/frontend/src/app.css @@ -0,0 +1,32 @@ +@import "tailwindcss"; +@import "tw-animate-css"; + +:root { + --acc: #e8a33d; + --scan: 0.5; + --up: #9cc06e; + --down: #d5786a; + --info: #7fbacb; + --warn: #e8a33d; + --bg: #0e0c0a; + --surface: #17140f; + --raised: #1f1a14; + --sunken: #0a0907; + --line: #2b251e; + --line2: #3a342b; + --f1: #f4efe5; + --f2: #cbc2b4; + --f3: #938a7e; + --f4: #5f584e; +} + +@keyframes symFade { + from { + opacity: 0; + transform: translateY(3px); + } + to { + opacity: 1; + transform: none; + } +} diff --git a/frontend/src/collections/actions.ts b/frontend/src/collections/actions.ts new file mode 100644 index 00000000..c98f92fc --- /dev/null +++ b/frontend/src/collections/actions.ts @@ -0,0 +1,55 @@ +import { createStore } from "@tanstack/react-store"; +import { Circular } from "./circular"; + +export type Action = { + id: string; + tick: number; + symbol: string; + type: string; + side: string; + verdict: string; + reason: string; + score: number; + entryLine: number; + entryScore: number; + entryConfidence: number; + fraction: number; + price: number; + branchKey: string; + reasonSource: string; + reasonCategory: string; + decisionAt: string; +}; + +/* +actionStore is the single source of truth for all signal data. +Every Action from the backend WebSocket is routed here, +indexed by symbol. +*/ +export const actionStore = createStore( + { + actions: {} as Record>>, + }, + ({ setState }) => ({ + updateFrame: (frames: Action[]) => + setState((prev) => { + const actions = { ...prev.actions }; + + for (const frame of frames) { + if (!actions[frame.symbol]) { + actions[frame.symbol] = Circular(50); + } + + actions[frame.symbol].push(frame); + } + + return { + actions, + }; + }), + reset: () => + setState(() => ({ + actions: {}, + })), + }), +); diff --git a/frontend/src/collections/app.ts b/frontend/src/collections/app.ts index a519da0f..c5266501 100644 --- a/frontend/src/collections/app.ts +++ b/frontend/src/collections/app.ts @@ -1,41 +1,27 @@ import { createStore } from "@tanstack/react-store"; -type DashboardFrameUpdater = (frame: Record) => void; - -const replayDashboardFrame = ( - updater: DashboardFrameUpdater | null, - frame: Record | null, -) => { - if (updater !== null && frame !== null) { - updater(frame); - } -}; +export const DEFAULT_KERNELS = [ + "correlation", + "cvd", + "depthflow", + "exhaustion", + "fluid", + "hawkes", + "leadlag", + "liquidity", + "pumpdump", + "sentiment", + "toxicity", +]; export const appStore = createStore( { online: false, - showPositions: false, - playbookEvaluations: 0, - storyTicks: 0, - lastRegimeFrame: null as Record | null, - lastManifoldFrame: null as Record | null, - lastResonanceFrame: null as Record | null, - lastGaugeFrames: {} as Record>, - candleUpdaters: {} as Record, - gaugeUpdaters: {} as Record, - regimeUpdater: null as DashboardFrameUpdater | null, - fluidUpdater: null as DashboardFrameUpdater | null, - manifoldUpdater: null as DashboardFrameUpdater | null, - resonanceUpdater: null as DashboardFrameUpdater | null, - predictionUpdater: null as - | ((frame: Record) => void) - | null, - confidenceHeatmapUpdater: null as - | ((frame: Record) => void) - | null, - surpriseHeatmapUpdater: null as - | ((frame: Record) => void) - | null, + error: null as Record | null, + focusSymbol: "BTC/USD", + query: "", + kernels: DEFAULT_KERNELS, + observedSources: new Set(), }, ({ setState }) => ({ updateOnline: (online: boolean) => @@ -43,171 +29,48 @@ export const appStore = createStore( ...prev, online: online, })), - updateShowPositions: (showPositions: boolean) => + updateError: (err: Record) => setState((prev) => ({ ...prev, - showPositions: showPositions, + error: err, })), - updatePlaybookEvaluations: (playbookEvaluations: number) => + updateFocusSymbol: (symbol: string) => setState((prev) => ({ ...prev, - playbookEvaluations: playbookEvaluations, + focusSymbol: symbol, })), - updateStoryTicks: (storyTicks: number) => + updateQuery: (query: string) => setState((prev) => ({ ...prev, - storyTicks: storyTicks, + query: query, })), - updateCandleUpdater: ( - symbol: string, - candleUpdater: DashboardFrameUpdater | null, - ) => + observeSources: (sources: Set) => setState((prev) => { - const candleUpdaters = { ...prev.candleUpdaters }; - const normalized = symbol.trim().toUpperCase(); - - if (normalized === "") { + if (sources.size === 0) { return prev; } - if (candleUpdater === null) { - delete candleUpdaters[normalized]; - - return { - ...prev, - candleUpdaters: candleUpdaters, - }; - } - - candleUpdaters[normalized] = candleUpdater; + const merged = new Set(prev.observedSources); + let changed = false; - return { - ...prev, - candleUpdaters: candleUpdaters, - }; - }), - updateGaugeUpdater: ( - source: string, - gaugeUpdater: ((frame: Record) => void) | null, - ) => - setState((prev) => { - const gaugeUpdaters = { ...prev.gaugeUpdaters }; - - if (gaugeUpdater === null) { - delete gaugeUpdaters[source]; - } else { - gaugeUpdaters[source] = gaugeUpdater; - const lastFrame = prev.lastGaugeFrames[source]; - - if (lastFrame !== undefined) { - gaugeUpdater(lastFrame); + for (const source of sources) { + if (!merged.has(source)) { + merged.add(source); + changed = true; } } - return { - ...prev, - gaugeUpdaters: gaugeUpdaters, - }; - }), - stashGaugeFrame: (source: string, frame: Record) => - setState((prev) => { - if (source === "") { + if (!changed) { return prev; } - const lastGaugeFrames = { - ...prev.lastGaugeFrames, - [source]: frame, - }; - - prev.gaugeUpdaters[source]?.(frame); + const kernels = [...new Set([...DEFAULT_KERNELS, ...merged])]; return { ...prev, - lastGaugeFrames: lastGaugeFrames, + observedSources: merged, + kernels, }; }), - stashRegimeFrame: (frame: Record) => - setState((prev) => { - replayDashboardFrame(prev.regimeUpdater, frame); - - return { - ...prev, - lastRegimeFrame: frame, - }; - }), - stashManifoldFrame: (frame: Record) => - setState((prev) => { - replayDashboardFrame(prev.manifoldUpdater, frame); - - return { - ...prev, - lastManifoldFrame: frame, - }; - }), - updateRegimeUpdater: (regimeUpdater: DashboardFrameUpdater | null) => - setState((prev) => { - replayDashboardFrame(regimeUpdater, prev.lastRegimeFrame); - - return { - ...prev, - regimeUpdater: regimeUpdater, - }; - }), - updateFluidUpdater: (fluidUpdater: DashboardFrameUpdater | null) => - setState((prev) => ({ - ...prev, - fluidUpdater: fluidUpdater, - })), - updateManifoldUpdater: (manifoldUpdater: DashboardFrameUpdater | null) => - setState((prev) => { - replayDashboardFrame(manifoldUpdater, prev.lastManifoldFrame); - - return { - ...prev, - manifoldUpdater: manifoldUpdater, - }; - }), - stashResonanceFrame: (frame: Record) => - setState((prev) => { - replayDashboardFrame(prev.resonanceUpdater, frame); - - return { - ...prev, - lastResonanceFrame: frame, - }; - }), - updateResonanceUpdater: (resonanceUpdater: DashboardFrameUpdater | null) => - setState((prev) => { - replayDashboardFrame(resonanceUpdater, prev.lastResonanceFrame); - - return { - ...prev, - resonanceUpdater: resonanceUpdater, - }; - }), - updatePredictionUpdater: ( - predictionUpdater: ((frame: Record) => void) | null, - ) => - setState((prev) => ({ - ...prev, - predictionUpdater: predictionUpdater, - })), - updateConfidenceHeatmapUpdater: ( - confidenceHeatmapUpdater: - | ((frame: Record) => void) - | null, - ) => - setState((prev) => ({ - ...prev, - confidenceHeatmapUpdater: confidenceHeatmapUpdater, - })), - updateSurpriseHeatmapUpdater: ( - surpriseHeatmapUpdater: ((frame: Record) => void) | null, - ) => - setState((prev) => ({ - ...prev, - surpriseHeatmapUpdater: surpriseHeatmapUpdater, - })), }), ); diff --git a/frontend/src/collections/balance.ts b/frontend/src/collections/balance.ts deleted file mode 100644 index 025a87b4..00000000 --- a/frontend/src/collections/balance.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { createStore } from "@tanstack/react-store"; - -export const balanceStore = createStore( - { - assets: {} as Record, - balanceLabel: "Balance", - symbol: "$", - openPositions: 0, - pricedPositions: 0, - liquidationBalance: 0, - liquidationComplete: true, - exitBalance: 0, - inProfit: false, - }, - ({ setState }) => ({ - updateOpenPositions: (openPositions: number) => - setState((state) => ({ - ...state, - openPositions: openPositions, - })), - updatePricedPositions: (pricedPositions: number) => - setState((state) => ({ - ...state, - pricedPositions: pricedPositions, - })), - updateLiquidationBalance: (liquidationBalance: number) => - setState((state) => ({ - ...state, - liquidationBalance: liquidationBalance, - })), - updateLiquidationComplete: (liquidationComplete: boolean) => - setState((state) => ({ - ...state, - liquidationComplete: liquidationComplete, - })), - updateExitBalance: (exitBalance: number) => - setState((state) => ({ - ...state, - exitBalance: exitBalance, - })), - updateInProfit: (inProfit: boolean) => - setState((state) => ({ - ...state, - inProfit: inProfit, - })), - updateAssets: (assets: Record) => - setState((state) => { - const assetRows = Array.isArray(assets.asset) - ? (assets.asset as Record[]) - : []; - const primaryAsset = - assetRows.find( - (row) => row.asset === "ZUSD" || row.asset === "USD", - ) ?? assetRows[0]; - const balanceAmount = - typeof primaryAsset?.balance === "number" - ? primaryAsset.balance - : null; - const assetCode = - typeof primaryAsset?.asset === "string" ? primaryAsset.asset : ""; - const isUsd = assetCode === "ZUSD" || assetCode === "USD"; - - return { - ...state, - assets: { ...state.assets, ...assets }, - balanceLabel: - balanceAmount !== null - ? `${isUsd ? "$" : ""}${balanceAmount.toFixed(2)}${isUsd ? "" : ` ${assetCode}`}` - : state.balanceLabel, - symbol: isUsd ? "$" : assetCode || state.symbol, - }; - }), - }), -); diff --git a/frontend/src/collections/balances.ts b/frontend/src/collections/balances.ts new file mode 100644 index 00000000..fd5afd97 --- /dev/null +++ b/frontend/src/collections/balances.ts @@ -0,0 +1,22 @@ +import { createStore } from "@tanstack/react-store"; + +export type Balance = Record & { + asset: string; + balance: number; + available?: number; + reserved?: number; +}; + +export const balancesStore = createStore( + { + balances: [] as Balance[], + observed: false, + }, + ({ setState }) => ({ + updateFrame: (balances: Balance[]) => + setState(() => ({ + balances, + observed: true, + })), + }), +); diff --git a/frontend/src/collections/causal.ts b/frontend/src/collections/causal.ts new file mode 100644 index 00000000..e6d8fd97 --- /dev/null +++ b/frontend/src/collections/causal.ts @@ -0,0 +1,32 @@ +import { createStore } from "@tanstack/react-store"; +import { Circular, type CircularBuffer } from "./circular"; + +export type CausalFrame = Record & { + source: string; + symbol: string; + at: string; +}; + +export const causalStore = createStore( + { + causal: {} as Record>, + }, + ({ setState }) => ({ + updateFrame: (frames: CausalFrame[]) => + setState((prev) => { + const causal = { ...prev.causal }; + + for (const frame of frames) { + if (!causal[frame.symbol]) { + causal[frame.symbol] = Circular(50); + } + + causal[frame.symbol].push(frame); + } + + return { + causal, + }; + }), + }), +); diff --git a/frontend/src/collections/circular.ts b/frontend/src/collections/circular.ts new file mode 100644 index 00000000..08123ade --- /dev/null +++ b/frontend/src/collections/circular.ts @@ -0,0 +1,41 @@ +export type CircularBuffer = { + push: (value: T) => void; + values: () => T[]; + length: () => number; +}; + +export const Circular = (positions: number): CircularBuffer => { + const buffer = new Array(positions); + let start = 0; + let count = 0; + + const push = (value: T) => { + if (positions <= 0) return; + + const index = (start + count) % positions; + + if (count < positions) { + buffer[index] = value; + count++; + } else { + buffer[start] = value; + start = (start + 1) % positions; + } + }; + + const length = () => { + return count; + }; + + const values = () => { + const result: T[] = []; + + for (let i = 0; i < count; i++) { + result.push(buffer[(start + i) % positions]); + } + + return result; + }; + + return { push, values, length }; +}; diff --git a/frontend/src/collections/cognitive.test.ts b/frontend/src/collections/cognitive.test.ts deleted file mode 100644 index 1306f165..00000000 --- a/frontend/src/collections/cognitive.test.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { beforeEach, describe, expect, it } from "vitest"; - -import { - cognitiveScopes, - cognitiveStore, - parseCognitiveFrame, - selectedCognitiveReading, - type CognitiveReading, -} from "#/collections/cognitive"; - -const sampleReading = (): CognitiveReading => ({ - scope: "BTC/USD", - sequence: "measurement/BTC/USD/fluid", - regimePrefix: "regime/BTC", - regimeCohort: 2, - ambiguous: true, - sideline: true, - entropyBits: 1.5, - entropyThreshold: 2, - classConfidence: 0.82, - contrastEvidence: 0.41, - lookaheadScore: 0.67, - lookaheadPaths: 3, - winnerClass: "laminar", - prewarmPaths: null, - prewarmScore: null, - updatedAt: Date.now(), -}); - -describe("parseCognitiveFrame", () => { - it("returns null when scope is missing", () => { - expect(parseCognitiveFrame({ type: "cognitive" })).toBeNull(); - expect(parseCognitiveFrame({ scope: "" })).toBeNull(); - expect(parseCognitiveFrame({ scope: " " })).toBeNull(); - }); - - it("normalizes cognitive websocket payloads", () => { - const reading = parseCognitiveFrame({ - type: "cognitive", - scope: "BTC/USD", - sequence: "measurement/BTC/USD/fluid", - regime_prefix: "regime/BTC", - regime_cohort: 2, - ambiguous: true, - sideline: true, - entropy_bits: 1.5, - entropy_threshold: 2, - class_confidence: 0.82, - contrast_evidence: 0.41, - lookahead_score: 0.67, - lookahead_paths: 3, - winner_class: "laminar", - }); - - expect(reading).not.toBeNull(); - expect(reading?.scope).toBe("BTC/USD"); - expect(reading?.sequence).toBe("measurement/BTC/USD/fluid"); - expect(reading?.regimePrefix).toBe("regime/BTC"); - expect(reading?.regimeCohort).toBe(2); - expect(reading?.ambiguous).toBe(true); - expect(reading?.sideline).toBe(true); - expect(reading?.entropyBits).toBe(1.5); - expect(reading?.entropyThreshold).toBe(2); - expect(reading?.classConfidence).toBe(0.82); - expect(reading?.contrastEvidence).toBe(0.41); - expect(reading?.lookaheadScore).toBe(0.67); - expect(reading?.lookaheadPaths).toBe(3); - expect(reading?.winnerClass).toBe("laminar"); - expect(reading?.prewarmPaths).toBeNull(); - expect(reading?.prewarmScore).toBeNull(); - }); - - it("accepts optional prewarm telemetry", () => { - const reading = parseCognitiveFrame({ - scope: "ETH/USD", - prewarm_paths: 5, - prewarm_score: 0.33, - }); - - expect(reading).not.toBeNull(); - expect(reading?.prewarmPaths).toBe(5); - expect(reading?.prewarmScore).toBe(0.33); - }); - - it("coerces invalid numeric fields to safe defaults", () => { - const reading = parseCognitiveFrame({ - scope: "SOL/USD", - regime_cohort: -3.7, - entropy_bits: "bad", - lookahead_paths: Number.NaN, - }); - - expect(reading).not.toBeNull(); - expect(reading?.regimeCohort).toBe(0); - expect(reading?.entropyBits).toBe(0); - expect(reading?.lookaheadPaths).toBe(0); - }); - - it("only treats explicit true as boolean flags", () => { - const reading = parseCognitiveFrame({ - scope: "BTC/USD", - ambiguous: 1, - sideline: "yes", - }); - - expect(reading).not.toBeNull(); - expect(reading?.ambiguous).toBe(false); - expect(reading?.sideline).toBe(false); - }); -}); - -describe("cognitiveStore", () => { - beforeEach(() => { - cognitiveStore.setState({ readings: {}, selectedScope: "" }); - }); - - it("stores readings by scope", () => { - const reading = sampleReading(); - - cognitiveStore.actions.updateReading(reading); - - expect(cognitiveStore.state.readings["BTC/USD"]).toEqual(reading); - }); - - it("selects the first sealed scope automatically", () => { - cognitiveStore.actions.updateReading(sampleReading()); - - expect(cognitiveStore.state.selectedScope).toBe("BTC/USD"); - }); - - it("keeps the selected scope when additional readings arrive", () => { - cognitiveStore.actions.updateReading(sampleReading()); - cognitiveStore.actions.updateReading({ - ...sampleReading(), - scope: "ETH/USD", - }); - - expect(cognitiveStore.state.selectedScope).toBe("BTC/USD"); - }); - - it("updates selected scope on demand", () => { - cognitiveStore.actions.updateReading(sampleReading()); - cognitiveStore.actions.updateReading({ - ...sampleReading(), - scope: "ETH/USD", - }); - cognitiveStore.actions.selectScope("ETH/USD"); - - expect(cognitiveStore.state.selectedScope).toBe("ETH/USD"); - expect(selectedCognitiveReading()?.scope).toBe("ETH/USD"); - }); - - it("lists scopes in sorted order", () => { - cognitiveStore.actions.updateReading({ - ...sampleReading(), - scope: "ETH/USD", - }); - cognitiveStore.actions.updateReading(sampleReading()); - - expect(cognitiveScopes()).toEqual(["BTC/USD", "ETH/USD"]); - }); - - it("returns null when no scope is selected", () => { - expect(selectedCognitiveReading()).toBeNull(); - }); -}); diff --git a/frontend/src/collections/cognitive.ts b/frontend/src/collections/cognitive.ts index 344c0da9..ce3eac8d 100644 --- a/frontend/src/collections/cognitive.ts +++ b/frontend/src/collections/cognitive.ts @@ -1,5 +1,10 @@ import { createStore } from "@tanstack/react-store"; +/* +CognitiveReading mirrors the backend market.CognitiveReading: a per-symbol +cognitive summary derived from the tick's measurements (regime sequence, entropy +gate, winning class). Optional prewarm fields are reserved for lookahead. +*/ export type CognitiveReading = { scope: string; sequence: string; @@ -14,88 +19,75 @@ export type CognitiveReading = { lookaheadScore: number; lookaheadPaths: number; winnerClass: string; - prewarmPaths: number | null; - prewarmScore: number | null; + prewarmPaths?: number | null; + prewarmScore?: number | null; updatedAt: number; + beamWidth?: number; + maxHops?: number; + nodeCount?: number; + branches?: CognitiveBranch[]; + beams?: CognitiveBeam[]; + classes?: CognitiveClass[]; }; -const finiteNumber = (value: unknown): number | null => - typeof value === "number" && Number.isFinite(value) ? value : null; - -const finiteCount = (value: unknown): number => - Math.max(0, Math.floor(finiteNumber(value) ?? 0)); - -const stringValue = (value: unknown): string => - typeof value === "string" ? value.trim() : ""; - -export const parseCognitiveFrame = ( - raw: Record, -): CognitiveReading | null => { - const scope = stringValue(raw.scope); +export type CognitiveBranch = { + id: number; + parentId: number; + token: string; + prefix: string; + depth: number; + probability: number; + count: number; +}; - if (scope === "") { - return null; - } +export type CognitiveBeam = { + sequence: string; + score: number; +}; - return { - scope: scope, - sequence: stringValue(raw.sequence), - regimePrefix: stringValue(raw.regime_prefix), - regimeCohort: finiteCount(raw.regime_cohort), - ambiguous: raw.ambiguous === true, - sideline: raw.sideline === true, - entropyBits: finiteNumber(raw.entropy_bits) ?? 0, - entropyThreshold: finiteNumber(raw.entropy_threshold) ?? 0, - classConfidence: finiteNumber(raw.class_confidence) ?? 0, - contrastEvidence: finiteNumber(raw.contrast_evidence) ?? 0, - lookaheadScore: finiteNumber(raw.lookahead_score) ?? 0, - lookaheadPaths: finiteCount(raw.lookahead_paths), - winnerClass: stringValue(raw.winner_class), - prewarmPaths: finiteNumber(raw.prewarm_paths), - prewarmScore: finiteNumber(raw.prewarm_score), - updatedAt: Date.now(), - }; +export type CognitiveClass = { + name: string; + probability: number; }; +/* +cognitiveStore holds the latest per-symbol cognitive readings broadcast by the +trader (role "cognitive"). The Cortex surface renders the DMT sequence tree, +entropy gate, and posterior from these. +*/ export const cognitiveStore = createStore( { readings: {} as Record, - selectedScope: "", + selectedScope: null as string | null, }, ({ setState }) => ({ - updateReading: (reading: CognitiveReading) => + updateFrame: (frame: Record) => setState((prev) => { - const readings = { - ...prev.readings, - [reading.scope]: reading, - }; + const readings = frame.readings as + | Record + | undefined; - const selectedScope = - prev.selectedScope === "" ? reading.scope : prev.selectedScope; + if (readings === undefined || readings === null) { + return prev; + } - return { - ...prev, - readings: readings, - selectedScope: selectedScope, - }; - }), - selectScope: (scope: string) => - setState((prev) => ({ - ...prev, - selectedScope: scope, - })), + return { + ...prev, + readings: { + ...prev.readings, + ...readings, + }, + }; + }), + selectScope: (selectedScope: string) => + setState((prev) => ({ ...prev, selectedScope })), }), ); -export const cognitiveScopes = (): string[] => - Object.keys(cognitiveStore.state.readings).sort(); - -export const selectedCognitiveReading = (): CognitiveReading | null => { - const scope = cognitiveStore.state.selectedScope; - - if (scope === "") { - return null; - } - - return cognitiveStore.state.readings[scope] ?? null; -}; +/* +cognitiveScopes lists the symbols that currently have a cognitive reading in a +stable order. +*/ +export const cognitiveScopes = ( + readings: Record, +): string[] => Object.keys(readings).sort(); diff --git a/frontend/src/collections/decisions.ts b/frontend/src/collections/decisions.ts new file mode 100644 index 00000000..a809d43e --- /dev/null +++ b/frontend/src/collections/decisions.ts @@ -0,0 +1,59 @@ +import { createStore } from "@tanstack/react-store"; +import { Circular } from "./circular"; + +export const decisionStore = createStore( + { + tick: null as number | null, + decisions: Circular(50), + allowed: [] as Record[], + denied: [] as Record[], + }, + ({ setState }) => ({ + observeTick: (tick: unknown) => + setState((prev) => { + const count = Number(tick); + + if (!Number.isFinite(count) || prev.tick === count) { + return prev; + } + + return { ...prev, tick: count }; + }), + updateFrame: (frame: unknown) => + setState((prev) => { + const next = { ...prev }; + const decisions = Array.isArray(frame) + ? (frame as Record[]) + : [frame as Record]; + + for (const decision of decisions) { + const tick = Number(decision.tick); + + if (Number.isFinite(tick)) { + next.tick = tick; + } + + next.decisions.push(decision); + next.allowed = + decision.verdict === "allow" + ? [...next.allowed, decision].slice(-50) + : next.allowed; + next.denied = + decision.verdict === "allow" + ? next.denied + : [...next.denied, decision].slice(-50); + } + + return { + ...next, + }; + }), + reset: () => + setState(() => ({ + tick: null, + decisions: Circular(50), + allowed: [], + denied: [], + })), + }), +); diff --git a/frontend/src/collections/diagnostics.ts b/frontend/src/collections/diagnostics.ts new file mode 100644 index 00000000..9b8f3fb4 --- /dev/null +++ b/frontend/src/collections/diagnostics.ts @@ -0,0 +1,3 @@ +import { createFrameCollection } from "#/collections/frames"; + +export const diagnosticsStore = createFrameCollection(); diff --git a/frontend/src/collections/executions.ts b/frontend/src/collections/executions.ts new file mode 100644 index 00000000..249c8c59 --- /dev/null +++ b/frontend/src/collections/executions.ts @@ -0,0 +1,24 @@ +import { createStore } from "@tanstack/react-store"; + +export type Execution = Record & { + exec_id?: string; + order_id?: string; + symbol?: string; + side?: string; + order_status?: string; + timestamp?: string; +}; + +export const executionsStore = createStore( + { + executions: [] as Execution[][], + observed: false, + }, + ({ setState }) => ({ + updateFrame: (executions: Execution[][]) => + setState(() => ({ + executions, + observed: true, + })), + }), +); diff --git a/frontend/src/collections/frames.ts b/frontend/src/collections/frames.ts new file mode 100644 index 00000000..76ec4a5a --- /dev/null +++ b/frontend/src/collections/frames.ts @@ -0,0 +1,108 @@ +import { createStore } from "@tanstack/react-store"; + +export type DashboardFrame = Record; +export type DashboardPayload = DashboardFrame | DashboardFrame[]; + +const DEFAULT_LIMIT = 256; + +export const boundedAppend = ( + frames: DashboardFrame[], + frame: DashboardFrame, + limit = DEFAULT_LIMIT, +): DashboardFrame[] => [...frames, frame].slice(-Math.max(1, limit)); + +export const appendByKey = ( + index: Record, + key: unknown, + frame: DashboardFrame, + limit = DEFAULT_LIMIT, +): Record => { + if (typeof key !== "string" || key === "") { + return index; + } + + return { + ...index, + [key]: boundedAppend(index[key] ?? [], frame, limit), + }; +}; + +export const createFrameCollection = (limit = DEFAULT_LIMIT) => + createStore( + { + frame: null as DashboardFrame | null, + frames: [] as DashboardFrame[], + history: [] as DashboardFrame[], + bySymbol: {} as Record, + bySource: {} as Record, + }, + ({ setState }) => ({ + updateFrame: (frame: DashboardPayload) => { + if (Array.isArray(frame)) { + if (frame.length === 0) { + return; + } + + setState((prev) => { + let next = prev; + + for (const row of frame) { + const frames = boundedAppend(next.frames, row, limit); + next = { + frame: row, + frames, + history: frames, + bySymbol: appendByKey(next.bySymbol, row.symbol, row, limit), + bySource: appendByKey(next.bySource, row.source, row, limit), + }; + } + + return next; + }); + return; + } + + setState((prev) => { + const frames = boundedAppend(prev.frames, frame, limit); + + return { + frame, + frames, + history: frames, + bySymbol: appendByKey(prev.bySymbol, frame.symbol, frame, limit), + bySource: appendByKey(prev.bySource, frame.source, frame, limit), + }; + }); + }, + updateFrames: (frames: DashboardFrame[]) => { + if (frames.length === 0) { + return; + } + + setState((prev) => { + let next = prev; + + for (const frame of frames) { + const nextFrames = boundedAppend(next.frames, frame, limit); + next = { + frame, + frames: nextFrames, + history: nextFrames, + bySymbol: appendByKey(next.bySymbol, frame.symbol, frame, limit), + bySource: appendByKey(next.bySource, frame.source, frame, limit), + }; + } + + return next; + }); + }, + reset: () => + setState(() => ({ + frame: null, + frames: [], + history: [], + bySymbol: {}, + bySource: {}, + })), + }), + ); diff --git a/frontend/src/collections/instruments.ts b/frontend/src/collections/instruments.ts new file mode 100644 index 00000000..20a901fa --- /dev/null +++ b/frontend/src/collections/instruments.ts @@ -0,0 +1,71 @@ +import { createStore } from "@tanstack/react-store"; +import { appStore } from "./app"; + +const symbolFrom = (value: unknown): string => { + if (value === null || typeof value !== "object" || Array.isArray(value)) { + return ""; + } + + const record = value as Record; + const symbol = String(record.symbol ?? record.scope ?? "").trim(); + + return symbol.includes("/") ? symbol : ""; +}; + +const pairsFrom = (frame: Record | unknown[]) => { + if (Array.isArray(frame)) { + return frame; + } + + const data = + frame.data !== null && typeof frame.data === "object" + ? (frame.data as Record) + : {}; + + if (Array.isArray(data.pairs)) { + return data.pairs; + } + + if (Array.isArray(frame.pairs)) { + return frame.pairs; + } + + if (Array.isArray(frame.symbols)) { + return frame.symbols; + } + + return [frame]; +}; + +export const instrumentsStore = createStore( + { + frame: null as Record | unknown[] | null, + instruments: {} as Record>, + symbols: [] as string[], + }, + ({ setState }) => ({ + updateFrame: (frame: Record | unknown[]) => + setState((prev) => { + const instruments = { ...prev.instruments }; + + for (const pair of pairsFrom(frame)) { + const symbol = symbolFrom(pair); + + if (symbol !== "") { + instruments[symbol] = pair as Record; + } + } + + const symbols = Object.keys(instruments).sort(); + if (symbols.length > 0 && !symbols.includes(appStore.state.focusSymbol)) { + appStore.actions.updateFocusSymbol(symbols[0] ?? ""); + } + + return { + frame, + instruments, + symbols, + }; + }), + }), +); diff --git a/frontend/src/collections/manifold.ts b/frontend/src/collections/manifold.ts new file mode 100644 index 00000000..4e154656 --- /dev/null +++ b/frontend/src/collections/manifold.ts @@ -0,0 +1,32 @@ +import { createStore } from "@tanstack/react-store"; +import { Circular, type CircularBuffer } from "./circular"; + +export type ManifoldFrame = Record & { + source: string; + symbol: string; + at: string; +}; + +export const manifoldStore = createStore( + { + manifold: {} as Record>, + }, + ({ setState }) => ({ + updateFrame: (frames: ManifoldFrame[]) => + setState((prev) => { + const manifold = { ...prev.manifold }; + + for (const frame of frames) { + if (!manifold[frame.symbol]) { + manifold[frame.symbol] = Circular(50); + } + + manifold[frame.symbol].push(frame); + } + + return { + manifold, + }; + }), + }), +); diff --git a/frontend/src/collections/measurements.ts b/frontend/src/collections/measurements.ts new file mode 100644 index 00000000..f66f8330 --- /dev/null +++ b/frontend/src/collections/measurements.ts @@ -0,0 +1,54 @@ +import { createStore } from "@tanstack/react-store"; +import { Circular, type CircularBuffer } from "./circular"; + +export type Category = { + type: string; + confidence: number; + surprisal: number; + strength: number; +}; + +export type Measurement = { + source: string; + symbol: string; + at: string; + status: string; + elapsed: number; + entryBaseline: number; + exitBaseline: number; + categories: Category[]; + metrics: Record; +}; + +/* +measurementsStore is the single source of truth for all signal data. +Every Measurement from the backend WebSocket is routed here, indexed +by source and by symbol. +*/ +export const measurementsStore = createStore( + { + measurements: {} as Record>>, + }, + ({ setState }) => ({ + updateFrame: (frames: Measurement[]) => + setState((prev) => { + const measurements = { ...prev.measurements }; + + for (const frame of frames) { + if (!measurements[frame.symbol]) { + measurements[frame.symbol] = {}; + } + + if (!measurements[frame.symbol][frame.source]) { + measurements[frame.symbol][frame.source] = Circular(50); + } + + measurements[frame.symbol][frame.source].push(frame); + } + + return { + measurements, + }; + }), + }), +); diff --git a/frontend/src/collections/orders.bench.ts b/frontend/src/collections/orders.bench.ts new file mode 100644 index 00000000..3fd5ebb9 --- /dev/null +++ b/frontend/src/collections/orders.bench.ts @@ -0,0 +1,21 @@ +import { bench, describe } from "vitest"; +import type { Order } from "./orders"; +import { ordersStore } from "./orders"; + +const orders: Order[] = Array.from({ length: 32 }, (_, index) => ({ + id: `PAPER-${String(index).padStart(5, "0")}`, + pair: "BTCUSD", + price: 90000 + index, + reserved_amount: 9 + index / 100, + reserved_asset: "USD", + side: "buy", + type: "limit", + volume: 0.0001, + created_at: "2026-07-06T10:00:00Z", +})); + +describe("ordersStore", () => { + bench("replaces the current order snapshot", () => { + ordersStore.actions.updateFrame(orders); + }); +}); diff --git a/frontend/src/collections/orders.test.ts b/frontend/src/collections/orders.test.ts new file mode 100644 index 00000000..46010876 --- /dev/null +++ b/frontend/src/collections/orders.test.ts @@ -0,0 +1,28 @@ +import { describe, expect, it } from "vitest"; +import type { Order } from "./orders"; +import { ordersStore } from "./orders"; + +const order: Order = { + id: "PAPER-00003", + pair: "BTCUSD", + price: 90000, + reserved_amount: 9, + reserved_asset: "USD", + side: "buy", + type: "limit", + volume: 0.0001, + created_at: "2026-07-06T10:00:00Z", +}; + +describe("ordersStore", () => { + it("keeps the current backend order snapshot", () => { + ordersStore.actions.updateFrame([order]); + + expect(ordersStore.state.orders).toEqual([order]); + expect(ordersStore.state.observed).toBe(true); + + ordersStore.actions.updateFrame([]); + + expect(ordersStore.state.orders).toEqual([]); + }); +}); diff --git a/frontend/src/collections/orders.ts b/frontend/src/collections/orders.ts new file mode 100644 index 00000000..de6246da --- /dev/null +++ b/frontend/src/collections/orders.ts @@ -0,0 +1,27 @@ +import { createStore } from "@tanstack/react-store"; + +export type Order = { + id: string; + pair: string; + price: number; + reserved_amount: number; + reserved_asset: string; + side: string; + type: string; + volume: number; + created_at: string; +}; + +export const ordersStore = createStore( + { + orders: [] as Order[], + observed: false, + }, + ({ setState }) => ({ + updateFrame: (orders: Order[]) => + setState(() => ({ + orders, + observed: true, + })), + }), +); diff --git a/frontend/src/collections/playbook.test.ts b/frontend/src/collections/playbook.test.ts deleted file mode 100644 index acf5574b..00000000 --- a/frontend/src/collections/playbook.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { describe, expect, it } from "vitest"; - -import { - mergeWalkActivation, - parseWalkTrace, - persistedNodeState, -} from "#/collections/playbook"; - -describe("parseWalkTrace", () => { - it("returns null when walk payload is absent", () => { - expect(parseWalkTrace(undefined)).toBeNull(); - expect(parseWalkTrace(null)).toBeNull(); - }); - - it("parses a valid walk trace", () => { - expect( - parseWalkTrace({ - symbol: "BTC/USD", - steps: [{ path: [0], outcome: "matched" }], - }), - ).toEqual({ - symbol: "BTC/USD", - steps: [{ path: [0], outcome: "matched" }], - active_path: undefined, - }); - }); -}); - -describe("mergeWalkActivation", () => { - it("keeps matched nodes green across later walks", () => { - const activated = mergeWalkActivation( - {}, - { - symbol: "BTC/USD", - steps: [ - { path: [0], outcome: "matched" }, - { path: [0, 1], outcome: "matched" }, - ], - }, - ); - - expect(activated).toEqual({ - "0": "matched", - "0.1": "matched", - }); - - const nextWalk = mergeWalkActivation(activated, { - symbol: "ETH/USD", - steps: [{ path: [0], outcome: "rejected" }], - }); - - expect(nextWalk).toEqual({ - "0": "matched", - "0.1": "matched", - }); - }); - - it("promotes action nodes above matched history", () => { - const activated = mergeWalkActivation( - { "0.1.2": "matched" }, - { - symbol: "BTC/USD", - steps: [{ path: [0, 1, 2], outcome: "action" }], - }, - ); - - expect(activated["0.1.2"]).toBe("action"); - }); -}); - -describe("persistedNodeState", () => { - it("returns matched for previously activated paths without a live step", () => { - expect( - persistedNodeState( - [0, 1], - { - symbol: "BTC/USD", - steps: [], - }, - { "0.1": "matched" }, - ), - ).toBe("matched"); - }); -}); diff --git a/frontend/src/collections/playbook.ts b/frontend/src/collections/playbook.ts index 7c221c0c..06c44ab7 100644 --- a/frontend/src/collections/playbook.ts +++ b/frontend/src/collections/playbook.ts @@ -1,27 +1,8 @@ import { createStore } from "@tanstack/react-store"; -export type PlaybookBranch = { - condition_group?: { - boolean?: string; - conditions?: Array<{ - type?: string; - left?: Record; - right?: Record; - }>; - }; - action?: { - type?: string; - side?: string; - fraction?: number; - }; - branches?: PlaybookBranch[]; -}; - -export type WalkStepOutcome = "rejected" | "matched" | "parked" | "action"; - export type WalkStep = { path: number[]; - outcome: WalkStepOutcome; + outcome: "rejected" | "matched" | "parked" | "action"; reason?: string; }; @@ -31,212 +12,31 @@ export type WalkTrace = { active_path?: number[]; }; -export const walkPathKey = (path: number[]): string => path.join("."); - -const OUTCOME_RANK: Record = { - rejected: 0, - parked: 1, - matched: 2, - action: 3, -}; - -const mergeWalkOutcome = ( - current: WalkStepOutcome | undefined, - incoming: WalkStepOutcome, -): WalkStepOutcome => { - if (current === undefined) { - return incoming; - } - - return OUTCOME_RANK[incoming] > OUTCOME_RANK[current] ? incoming : current; -}; - -/* -mergeWalkActivation keeps nodes that ever matched on the walk path lit green. -*/ -export const mergeWalkActivation = ( - activated: Record, - walkTrace: WalkTrace, -): Record => { - const next = { ...activated }; - - for (const step of walkTrace.steps) { - if (step.outcome === "rejected") { - continue; - } - - const key = walkPathKey(step.path); - next[key] = mergeWalkOutcome(next[key], step.outcome); - } - - if (walkTrace.active_path) { - for (let depth = 1; depth <= walkTrace.active_path.length; depth += 1) { - const prefix = walkTrace.active_path.slice(0, depth); - const key = walkPathKey(prefix); - next[key] = mergeWalkOutcome(next[key], "matched"); - } - } - - return next; -}; - -export type WalkNodeVisualState = "matched" | "action" | "rejected" | "idle"; - /* -persistedNodeState maps walk history to stable node colors for the decision tree. -Activated branches stay green so a full descent remains visible across ticks. +playbookStore holds the latest per-symbol playbook descent traces broadcast by the +trader (role "walk"). Each frame carries `evaluations` keyed by symbol; the +Decision Tree surface renders which branches matched, parked, or were rejected. */ -export const persistedNodeState = ( - path: number[], - walkTrace: WalkTrace | null, - activated: Record, -): WalkNodeVisualState => { - const key = walkPathKey(path); - const persisted = activated[key]; - const step = walkStepForPath(walkTrace, path); - const active = pathIsActive(walkTrace, path); - - if (persisted === "action" || step?.outcome === "action") { - return "action"; - } - - if ( - persisted === "matched" || - persisted === "parked" || - step?.outcome === "matched" || - step?.outcome === "parked" || - active - ) { - return "matched"; - } - - if (step?.outcome === "rejected") { - return "rejected"; - } - - return "idle"; -}; - -const pathsEqual = (left: number[] | undefined, right: number[]): boolean => { - if (!left || left.length !== right.length) { - return false; - } - - return left.every((value, index) => value === right[index]); -}; - -export const walkStepForPath = ( - trace: WalkTrace | null, - path: number[], -): WalkStep | null => { - if (!trace) { - return null; - } - - return trace.steps.find((step) => pathsEqual(step.path, path)) ?? null; -}; - -export const pathIsActive = ( - trace: WalkTrace | null, - path: number[], -): boolean => { - if (!trace?.active_path) { - return false; - } - - return pathsEqual(trace.active_path, path); -}; - -const isWalkStepOutcome = (value: unknown): value is WalkStepOutcome => - value === "rejected" || - value === "matched" || - value === "parked" || - value === "action"; - -const isWalkStep = (value: unknown): value is WalkStep => { - if (typeof value !== "object" || value === null) { - return false; - } - - const step = value as Record; - - if (!Array.isArray(step.path)) { - return false; - } - - if ( - !step.path.every( - (element): element is number => - typeof element === "number" && Number.isInteger(element), - ) - ) { - return false; - } - - return isWalkStepOutcome(step.outcome); -}; - -export const parseWalkTrace = (raw: unknown): WalkTrace | null => { - if (typeof raw !== "object" || raw === null) { - return null; - } - - const frame = raw as Record; - - if (typeof frame.symbol !== "string" || frame.symbol === "") { - return null; - } - - if (!Array.isArray(frame.steps) || !frame.steps.every(isWalkStep)) { - return null; - } - - const activePath = frame.active_path; - - if ( - activePath !== undefined && - (!Array.isArray(activePath) || !activePath.every(Number.isInteger)) - ) { - return null; - } - - return { - symbol: frame.symbol, - steps: frame.steps, - active_path: activePath, - }; -}; - export const playbookStore = createStore( - { - branches: [] as PlaybookBranch[], - walkTrace: null as WalkTrace | null, - activatedPathOutcomes: {} as Record, - }, + { evaluations: {} as Record }, ({ setState }) => ({ - updateBranches: (branches: PlaybookBranch[]) => - setState((prev) => ({ - ...prev, - branches: branches, - activatedPathOutcomes: {}, - })), - updateWalkTrace: (walkTrace: WalkTrace | null) => + updateFrame: (frame: Record) => setState((prev) => { - if (walkTrace === null) { + const evaluations = frame.evaluations as + | Record + | undefined; + + if (evaluations === undefined || evaluations === null) { + return prev; + } + return { ...prev, - walkTrace: null, + evaluations: { + ...prev.evaluations, + ...evaluations, + }, }; - } - - return { - ...prev, - walkTrace: walkTrace, - activatedPathOutcomes: mergeWalkActivation( - prev.activatedPathOutcomes, - walkTrace, - ), - }; - }), - }), -); + }), + }), + ); diff --git a/frontend/src/collections/positions.bench.ts b/frontend/src/collections/positions.bench.ts deleted file mode 100644 index ef2b1a9b..00000000 --- a/frontend/src/collections/positions.bench.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { bench, beforeEach, describe } from "vitest"; -import { - applyBalanceFrame, - applyPositionFrame, - resetPositionStateForTest, -} from "#/collections/positions"; - -const balanceFrame = { - type: "balances", - balanceLabel: "$38.22", - symbol: "$", - Currency: "USD", - Balance: 38.22, - Inventory: { - CFG: 189.2148, - GBP: 29.8238, - USDT: 40.0296, - ZEC: 0.0969, - }, - AvgEntry: { - CFG: 0.21, - GBP: 1.34, - USDT: 1.0, - ZEC: 414.41, - }, - Marks: { - "GBP/USD": 1.34, - "USDT/USD": 1.0, - "ZEC/USD": 411.84, - }, - ExpectedExit: { - GBP: 39.8623113712, - USDT: 39.9495408, - ZEC: 39.748913856, - }, - Unrealized: { - GBP: -0.0943806288, - USDT: -0.0800592, - ZEC: -0.406114144, - }, - ExitFeeRate: { - GBP: 0.002, - USDT: 0.002, - ZEC: 0.004, - }, -}; - -describe("dashboard positions", () => { - beforeEach(() => { - resetPositionStateForTest(); - }); - - bench("derive liquidation summary", () => { - applyBalanceFrame(balanceFrame); - }); - - bench("apply backend monitor frame", () => { - applyPositionFrame({ - type: "positions", - currency: "USD", - cash: 38.22, - open_positions: 4, - priced_positions: 4, - exit_value: 159.92, - exit_balance: -1.34, - liquidation_balance: 198.14, - liquidation_complete: true, - in_profit: false, - positions: [ - { - symbol: "CFG/USD", - qty: 189.2148, - avg_entry: 0.21, - mark: 0.2084, - exit_value: 39.4303, - unrealized: -0.304, - unrealized_pct: -0.7659, - priced: true, - stop_price: 0.205, - peak_price: 0.212, - offset: 0.015, - }, - { - symbol: "GBP/USD", - qty: 29.8238, - avg_entry: 1.34, - mark: 1.337, - exit_value: 39.8623, - unrealized: -0.0944, - unrealized_pct: -0.2362, - priced: true, - }, - { - symbol: "USDT/USD", - qty: 40.0296, - avg_entry: 1, - mark: 0.998, - exit_value: 39.9495, - unrealized: -0.0801, - unrealized_pct: -0.2, - priced: true, - }, - { - symbol: "ZEC/USD", - qty: 0.0969, - avg_entry: 414.41, - mark: 411.84, - exit_value: 39.7489, - unrealized: -0.4061, - unrealized_pct: -1.0109, - priced: true, - }, - ], - }); - }); -}); diff --git a/frontend/src/collections/positions.test.ts b/frontend/src/collections/positions.test.ts deleted file mode 100644 index 1c6d402c..00000000 --- a/frontend/src/collections/positions.test.ts +++ /dev/null @@ -1,220 +0,0 @@ -import { beforeEach, describe, expect, it } from "vitest"; -import { balanceStore } from "#/collections/balance"; -import { - applyBalanceFrame, - applyPositionFrame, - resetPositionStateForTest, -} from "#/collections/positions"; -import { statusStore } from "#/collections/status"; - -describe("dashboard positions", () => { - beforeEach(() => { - resetPositionStateForTest(); - }); - - it("derives the header balance label from wallet frames", () => { - applyBalanceFrame({ - type: "wallet", - Currency: "USD", - Balance: 200, - }); - - expect(balanceStore.state.balanceLabel).toBe("$200.00"); - }); - - it("renders open inventory from balance frames", () => { - applyBalanceFrame({ - type: "balances", - balanceLabel: "$149.87", - symbol: "$", - Currency: "USD", - Balance: 149.87, - Inventory: { BTC: 0.001 }, - AvgEntry: { BTC: 50130 }, - }); - - expect(statusStore.state.positionViews).toEqual([ - { - symbol: "BTC/USD", - qty: 0.001, - avgEntry: 50130, - mark: 0, - exitValue: 0, - unrealized: 0, - unrealizedPct: 0, - priced: false, - exitFeeRate: 0, - }, - ]); - expect(balanceStore.state.openPositions).toBe(1); - expect(balanceStore.state.pricedPositions).toBe(0); - expect(balanceStore.state.liquidationBalance).toBe(149.87); - expect(balanceStore.state.liquidationComplete).toBe(false); - expect(balanceStore.state.exitBalance).toBe(0); - expect(balanceStore.state.inProfit).toBe(true); - }); - - it("uses expected exit value after bid-side fee instead of optimistic mark P/L", () => { - applyBalanceFrame({ - type: "balances", - balanceLabel: "$149.87", - symbol: "$", - Currency: "USD", - Balance: 149.87, - Inventory: { BTC: 0.001 }, - AvgEntry: { BTC: 50130 }, - Marks: { "BTC/USD": 50630 }, - ExpectedExit: { BTC: 50.498362 }, - Unrealized: { BTC: 0.368362 }, - ExitFeeRate: { BTC: 0.0026 }, - }); - - const position = statusStore.state.positionViews[0]; - - if (position === undefined) { - throw new Error("expected one open position"); - } - - expect(position.priced).toBe(true); - expect(position.mark).toBe(50630); - expect(position.exitValue).toBe(50.498362); - expect(position.exitFeeRate).toBe(0.0026); - expect(position.unrealized).toBeCloseTo(0.368362); - expect(position.unrealizedPct).toBeCloseTo(0.7348, 4); - expect(balanceStore.state.pricedPositions).toBe(1); - expect(balanceStore.state.liquidationBalance).toBeCloseTo(200.368362); - expect(balanceStore.state.liquidationComplete).toBe(true); - expect(balanceStore.state.exitBalance).toBeCloseTo(0.368362); - expect(balanceStore.state.inProfit).toBe(true); - }); - - it("does not derive profit and loss from frontend marks", () => { - applyBalanceFrame({ - type: "balances", - balanceLabel: "$149.87", - symbol: "$", - Currency: "USD", - Balance: 149.87, - Inventory: { BTC: 0.001 }, - AvgEntry: { BTC: 50130 }, - Marks: { "BTC/USD": 50630 }, - ExitFeeRate: { BTC: 0.0026 }, - }); - - const position = statusStore.state.positionViews[0]; - - if (position === undefined) { - throw new Error("expected one open position"); - } - - expect(position.mark).toBe(50630); - expect(position.priced).toBe(false); - expect(position.exitValue).toBe(0); - expect(position.unrealized).toBe(0); - expect(balanceStore.state.pricedPositions).toBe(0); - expect(balanceStore.state.liquidationBalance).toBe(149.87); - }); - - it("uses backend position monitor frames as authoritative P&L", () => { - applyBalanceFrame({ - type: "balances", - balanceLabel: "$149.87", - symbol: "$", - Currency: "USD", - Balance: 149.87, - Inventory: { BTC: 0.001 }, - AvgEntry: { BTC: 50130 }, - }); - - applyPositionFrame({ - type: "positions", - currency: "USD", - cash: 149.87, - open_positions: 1, - priced_positions: 1, - exit_value: 50.63, - exit_balance: 0.5, - liquidation_balance: 200.5, - liquidation_complete: true, - in_profit: true, - positions: [ - { - symbol: "BTC/USD", - qty: 0.001, - avg_entry: 50130, - mark: 50630, - exit_value: 50.63, - unrealized: 0.5, - unrealized_pct: 0.9974077, - priced: true, - stop_price: 49870, - peak_price: 50700, - offset: 0.015, - mark_source: "stop_monitor", - }, - ], - }); - - expect(statusStore.state.positionViews).toEqual([ - { - symbol: "BTC/USD", - qty: 0.001, - avgEntry: 50130, - mark: 50630, - exitValue: 50.63, - unrealized: 0.5, - unrealizedPct: 0.9974077, - priced: true, - exitFeeRate: 0, - stopPrice: 49870, - peakPrice: 50700, - offset: 0.015, - markSource: "stop_monitor", - }, - ]); - expect(balanceStore.state.openPositions).toBe(1); - expect(balanceStore.state.pricedPositions).toBe(1); - expect(balanceStore.state.exitBalance).toBe(0.5); - expect(balanceStore.state.liquidationBalance).toBe(200.5); - expect(balanceStore.state.liquidationComplete).toBe(true); - expect(balanceStore.state.inProfit).toBe(true); - expect(balanceStore.state.balanceLabel).toBe("$149.87"); - }); - - it("does not let balance frames overwrite monitor-owned cash labels", () => { - applyPositionFrame({ - type: "positions", - currency: "USD", - cash: 189.53, - open_positions: 1, - priced_positions: 1, - exit_balance: -0.36, - liquidation_balance: 199.64, - liquidation_complete: true, - in_profit: false, - positions: [ - { - symbol: "BTC/USD", - qty: 0.001, - avg_entry: 50130, - mark: 50630, - exit_value: 50.11, - unrealized: -0.36, - unrealized_pct: -0.717, - priced: true, - }, - ], - }); - - applyBalanceFrame({ - type: "balances", - balanceLabel: "$187.76", - symbol: "$", - Currency: "USD", - Balance: 187.76, - }); - - expect(balanceStore.state.balanceLabel).toBe("$189.53"); - expect(balanceStore.state.liquidationBalance).toBe(199.64); - }); -}); diff --git a/frontend/src/collections/positions.ts b/frontend/src/collections/positions.ts index 3a1bc9be..96b57dc5 100644 --- a/frontend/src/collections/positions.ts +++ b/frontend/src/collections/positions.ts @@ -1,364 +1,24 @@ -import { balanceStore } from "#/collections/balance"; -import { statusStore } from "#/collections/status"; +import { createStore } from "@tanstack/react-store"; -type BalanceFrame = Record; - -type PositionView = { +export type Position = { symbol: string; qty: number; - avgEntry: number; + entry_price: number; mark: number; - exitValue: number; - unrealized: number; - unrealizedPct: number; - priced: boolean; - exitFeeRate: number; - stopPrice?: number; - peakPrice?: number; - offset?: number; - markSource?: string; -}; - -let monitorOwnsPositions = false; - -const finiteNumber = (value: unknown): number | null => { - if (typeof value !== "number" || !Number.isFinite(value)) { - return null; - } - - return value; -}; - -const numberMap = (value: unknown): Record => { - if (typeof value !== "object" || value === null || Array.isArray(value)) { - return {}; - } - - const output: Record = {}; - - for (const [key, raw] of Object.entries(value)) { - const parsed = finiteNumber(raw); - - if (parsed === null) { - continue; - } - - output[key] = parsed; - } - - return output; -}; - -const quoteCurrency = (frame: BalanceFrame): string => { - const currency = frame.Currency; - - if (typeof currency === "string" && currency.trim() !== "") { - return currency.trim().toUpperCase(); - } - - return "USD"; -}; - -const cashBalance = (frame: BalanceFrame, currency: string): number => { - const explicit = finiteNumber(frame.Balance); - - if (explicit !== null) { - return explicit; - } - - const assets = frame.assets as Record | undefined; - const rows = Array.isArray(assets?.asset) ? assets.asset : []; - - for (const row of rows) { - if (typeof row !== "object" || row === null) { - continue; - } - - const record = row as Record; - const asset = typeof record.asset === "string" ? record.asset : ""; - const balance = finiteNumber(record.balance); - const normalized = asset.trim().toUpperCase(); - - if (balance === null) { - continue; - } - - if (normalized === currency || normalized === `Z${currency}`) { - return balance; - } - } - - return 0; -}; - -const fallbackInventory = ( - frame: BalanceFrame, - currency: string, -): Record => { - const assets = frame.assets as Record | undefined; - const rows = Array.isArray(assets?.asset) ? assets.asset : []; - const inventory: Record = {}; - - for (const row of rows) { - if (typeof row !== "object" || row === null) { - continue; - } - - const record = row as Record; - const asset = typeof record.asset === "string" ? record.asset : ""; - const balance = finiteNumber(record.balance); - const normalized = asset.trim().toUpperCase(); - - if (balance === null || balance <= 0) { - continue; - } - - if (normalized === currency || normalized === `Z${currency}`) { - continue; - } - - inventory[normalized] = balance; - } - - return inventory; -}; - -const markForPosition = ( - symbol: string, - frame: BalanceFrame, -): number | null => { - const payloadMarks = numberMap(frame.Marks); - const payloadMark = payloadMarks[symbol]; - - if (payloadMark !== undefined && payloadMark > 0) { - return payloadMark; - } - - return null; -}; - -const optionalNumber = ( - record: Record, - key: string, -): number | undefined => { - const value = finiteNumber(record[key]); - - if (value === null) { - return undefined; - } - - return value; -}; - -const positionFromMonitor = (value: unknown): PositionView | null => { - if (typeof value !== "object" || value === null || Array.isArray(value)) { - return null; - } - - const record = value as Record; - const symbol = typeof record.symbol === "string" ? record.symbol.trim() : ""; - const qty = finiteNumber(record.qty); - const avgEntry = finiteNumber(record.avg_entry) ?? 0; - const mark = finiteNumber(record.mark) ?? 0; - const exitValue = finiteNumber(record.exit_value) ?? 0; - const unrealized = finiteNumber(record.unrealized) ?? 0; - const unrealizedPct = finiteNumber(record.unrealized_pct) ?? 0; - const exitFeeRate = finiteNumber(record.exit_fee_rate) ?? 0; - const priced = record.priced === true; - const markSource = - typeof record.mark_source === "string" ? record.mark_source.trim() : ""; - - if (symbol === "" || qty === null || qty <= 0) { - return null; - } - - return { - symbol, - qty, - avgEntry, - mark, - exitValue: priced ? exitValue : 0, - unrealized: priced ? unrealized : 0, - unrealizedPct: priced ? unrealizedPct : 0, - priced, - exitFeeRate, - stopPrice: optionalNumber(record, "stop_price"), - peakPrice: optionalNumber(record, "peak_price"), - offset: optionalNumber(record, "offset"), - markSource: markSource === "" ? undefined : markSource, - }; -}; - -const positionsFromMonitor = (frame: BalanceFrame): PositionView[] => { - const rows = Array.isArray(frame.positions) ? frame.positions : []; - const positions: PositionView[] = []; - - for (const row of rows) { - const position = positionFromMonitor(row); - - if (position === null) { - continue; - } - - positions.push(position); - } - - return positions.sort((left, right) => - left.symbol.localeCompare(right.symbol), - ); -}; - -const positionsFromBalance = (frame: BalanceFrame): PositionView[] => { - const currency = quoteCurrency(frame); - const inventory = { - ...fallbackInventory(frame, currency), - ...numberMap(frame.Inventory), - }; - const avgEntry = numberMap(frame.AvgEntry); - const expectedExit = numberMap(frame.ExpectedExit); - const expectedUnrealized = numberMap(frame.Unrealized); - const exitFeeRates = numberMap(frame.ExitFeeRate); - const positions: PositionView[] = []; - - for (const [base, quantity] of Object.entries(inventory)) { - if (quantity <= 0) { - continue; - } - - const entry = avgEntry[base] ?? 0; - const symbol = `${base}/${currency}`; - const mark = markForPosition(symbol, frame); - const exitFeeRate = exitFeeRates[base] ?? 0; - const entryCost = quantity * entry; - const exitValue = expectedExit[base] ?? 0; - const unrealized = expectedUnrealized[base] ?? 0; - const priced = - expectedExit[base] !== undefined && - expectedUnrealized[base] !== undefined && - entryCost > 0; - const unrealizedPct = priced ? (unrealized / entryCost) * 100 : 0; - - positions.push({ - symbol, - qty: quantity, - avgEntry: entry, - mark: mark ?? 0, - exitValue, - unrealized, - unrealizedPct, - priced, - exitFeeRate, - }); - } - - return positions.sort((left, right) => - left.symbol.localeCompare(right.symbol), - ); -}; - -const updatePositionStores = ( - positions: PositionView[], - cash: number, - currency = "USD", -) => { - const quoteSymbol = currency === "USD" ? "$" : currency; - const exitBalance = positions.reduce( - (total, position) => total + (position.priced ? position.unrealized : 0), - 0, - ); - const exitValue = positions.reduce( - (total, position) => total + (position.priced ? position.exitValue : 0), - 0, - ); - const pricedPositions = positions.filter( - (position) => position.priced, - ).length; - - statusStore.actions.updatePositionViews(positions); - balanceStore.setState((previous) => ({ - ...previous, - balanceLabel: cashBalanceLabel(cash, quoteSymbol), - symbol: quoteSymbol, - })); - balanceStore.actions.updateOpenPositions(positions.length); - balanceStore.actions.updatePricedPositions(pricedPositions); - balanceStore.actions.updateLiquidationBalance(cash + exitValue); - balanceStore.actions.updateLiquidationComplete( - pricedPositions === positions.length, - ); - balanceStore.actions.updateExitBalance(exitBalance); - balanceStore.actions.updateInProfit(exitBalance >= 0); -}; - -const cashBalanceLabel = (cash: number, symbol: string) => { - if (symbol.length === 1) { - return `${symbol}${cash.toFixed(2)}`; - } - - return `${cash.toFixed(2)} ${symbol.replace("$", "USD")}`; -}; - -export const applyBalanceFrame = (frame: BalanceFrame) => { - const currency = quoteCurrency(frame); - const cash = cashBalance(frame, currency); - - if (monitorOwnsPositions) { - balanceStore.setState((previous) => ({ - ...previous, - assets: - (frame.assets as Record | undefined) ?? - previous.assets, - })); - return; - } - - balanceStore.setState((previous) => ({ ...previous, ...frame })); - - updatePositionStores(positionsFromBalance(frame), cash, currency); -}; - -export const applyPositionFrame = (frame: BalanceFrame) => { - monitorOwnsPositions = true; - const positions = positionsFromMonitor(frame); - const cash = finiteNumber(frame.cash) ?? 0; - const currency = - typeof frame.currency === "string" && frame.currency.trim() !== "" - ? frame.currency.trim().toUpperCase() - : "USD"; - const quoteSymbol = currency === "USD" ? "$" : currency; - const openPositions = finiteNumber(frame.open_positions) ?? positions.length; - const pricedPositions = - finiteNumber(frame.priced_positions) ?? - positions.filter((position) => position.priced).length; - const liquidationBalance = finiteNumber(frame.liquidation_balance) ?? cash; - const exitBalance = finiteNumber(frame.exit_balance) ?? 0; - const liquidationComplete = frame.liquidation_complete === true; - const inProfit = frame.in_profit === true; - - statusStore.actions.updatePositionViews(positions); - balanceStore.setState((previous) => ({ - ...previous, - balanceLabel: cashBalanceLabel(cash, quoteSymbol), - symbol: quoteSymbol, - })); - balanceStore.actions.updateOpenPositions(openPositions); - balanceStore.actions.updatePricedPositions(pricedPositions); - balanceStore.actions.updateLiquidationBalance(liquidationBalance); - balanceStore.actions.updateLiquidationComplete(liquidationComplete); - balanceStore.actions.updateExitBalance(exitBalance); - balanceStore.actions.updateInProfit(inProfit); -}; - -export const resetPositionStateForTest = () => { - monitorOwnsPositions = false; - updatePositionStores([], 0); - balanceStore.setState((previous) => ({ - ...previous, - assets: {}, - balanceLabel: "Balance", - symbol: "$", - pricedPositions: 0, - liquidationBalance: 0, - liquidationComplete: true, - })); -}; + pnl: number; + return_pct: number; +}; + +export const positionsStore = createStore( + { + positions: [] as Position[], + observed: false, + }, + ({ setState }) => ({ + updateFrame: (positions: Position[]) => + setState(() => ({ + positions, + observed: true, + })), + }), +); diff --git a/frontend/src/collections/resonance.ts b/frontend/src/collections/resonance.ts new file mode 100644 index 00000000..936c1bb6 --- /dev/null +++ b/frontend/src/collections/resonance.ts @@ -0,0 +1,32 @@ +import { createStore } from "@tanstack/react-store"; +import { Circular, type CircularBuffer } from "./circular"; + +export type ResonanceFrame = Record & { + source: string; + symbol: string; + at: string; +}; + +export const resonanceStore = createStore( + { + resonance: {} as Record>, + }, + ({ setState }) => ({ + updateFrame: (frames: ResonanceFrame[]) => + setState((prev) => { + const resonance = { ...prev.resonance }; + + for (const frame of frames) { + if (!resonance[frame.symbol]) { + resonance[frame.symbol] = Circular(50); + } + + resonance[frame.symbol].push(frame); + } + + return { + resonance, + }; + }), + }), +); diff --git a/frontend/src/collections/signals.bench.ts b/frontend/src/collections/signals.bench.ts deleted file mode 100644 index b34a2028..00000000 --- a/frontend/src/collections/signals.bench.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { bench, describe } from "vitest"; - -import { - evidenceMeterValue, - healthMeterValue, - parseGaugeFrame, -} from "#/collections/signals"; - -const evidenceFrame = { - source: "fluid", - confidence: 0.64, - surprise: 2.8, - surprise_threshold: 2, - strength: 0.42, - elapsed: 60, - active_readings: 12, - readings_capacity: 16, - observed_at: new Date().toISOString(), - calibrated: true, -}; - -const evidenceReading = parseGaugeFrame(evidenceFrame); - -describe("signal diagnostics", () => { - bench("parse evidence gauge frames", () => { - parseGaugeFrame(evidenceFrame); - }); - - bench("score signal health", () => { - if (evidenceReading === null) { - return; - } - - healthMeterValue(evidenceReading); - evidenceMeterValue(evidenceReading); - }); -}); diff --git a/frontend/src/collections/signals.test.ts b/frontend/src/collections/signals.test.ts deleted file mode 100644 index 60d40ef0..00000000 --- a/frontend/src/collections/signals.test.ts +++ /dev/null @@ -1,317 +0,0 @@ -import { beforeEach, describe, expect, it } from "vitest"; - -import { - ALL_SIGNAL_SOURCES, - confidenceMeterValue, - evidenceMeterValue, - freshnessMeterValue, - healthMeterValue, - isSignalDiagnosticReading, - parseGaugeFrame, - SIGNAL_LABELS, - SIGNAL_SOURCES, - type SignalReading, - SPECTRUM_SOURCES, - signalHealthStatus, - signalStore, - surpriseMeterValue, - warmupProgress, -} from "#/collections/signals"; - -describe("parseGaugeFrame", () => { - it("returns null when source is missing", () => { - expect(parseGaugeFrame({ confidence: 0.5 })).toBeNull(); - }); - - it("normalizes gauge websocket payloads", () => { - const reading = parseGaugeFrame({ - source: "fluid", - confidence: 0.42, - surprise: 1.8, - surprise_threshold: 2, - samples: 120, - min_samples: 240, - calibrating: true, - calibrated: false, - }); - - expect(reading).not.toBeNull(); - expect(reading?.source).toBe("fluid"); - expect(reading?.confidence).toBe(0.42); - expect(reading?.surprise).toBe(1.8); - expect(reading?.surpriseThreshold).toBe(2); - expect(reading?.samples).toBe(120); - expect(reading?.minSamples).toBe(240); - expect(reading?.calibrating).toBe(true); - expect(reading?.calibrated).toBe(false); - }); - - it("normalizes bulk story measurements with PascalCase fields", () => { - const reading = parseGaugeFrame({ - Source: "leadlag", - Confidence: 0.55, - Surprise: 1.2, - }); - - expect(reading).not.toBeNull(); - expect(reading?.source).toBe("leadlag"); - expect(reading?.confidence).toBe(0.55); - expect(reading?.surprise).toBe(1.2); - expect(reading?.calibrated).toBe(false); - }); - - it("preserves bulk measurement evidence without declaring calibration", () => { - const observedAt = new Date(Date.now() - 500).toISOString(); - const reading = parseGaugeFrame({ - Source: "leadlag", - Confidence: 0.55, - Surprise: 1.2, - Strength: 0.48, - Elapsed: 5, - Category: "synchronized_drift", - ObservedAt: observedAt, - }); - - expect(reading).not.toBeNull(); - expect(reading?.calibrated).toBe(false); - expect(reading?.strength).toBe(0.48); - expect(reading?.category).toBe("synchronized_drift"); - expect(reading?.observedAt).toBe(Date.parse(observedAt)); - expect(reading === null ? null : isSignalDiagnosticReading(reading)).toBe( - false, - ); - }); - - it("accepts calibrated aggregate gauge evidence as healthy", () => { - const reading = parseGaugeFrame({ - source: "leadlag", - confidence: 0.55, - surprise: 3, - strength: 0.48, - elapsed: 5, - active_readings: 4, - readings_capacity: 8, - observed_at: new Date(Date.now() - 500).toISOString(), - calibrated: true, - }); - - expect(reading).not.toBeNull(); - expect(reading?.calibrated).toBe(true); - expect(reading === null ? null : isSignalDiagnosticReading(reading)).toBe( - true, - ); - expect(reading === null ? null : signalHealthStatus(reading)).toBe( - "healthy", - ); - }); - - it("maps measurement artifact fields into gauge readings", () => { - const observedAt = Date.now() - 250; - const reading = parseGaugeFrame({ - origin: "fluid", - scope: "BTC/USD", - timestamp: observedAt, - output: { - confidence: 0.71, - strength: 0.36, - category: 2, - surprise: 2.4, - elapsed: 30, - }, - }); - - expect(reading).not.toBeNull(); - expect(reading?.source).toBe("fluid"); - expect(reading?.confidence).toBe(0.71); - expect(reading?.surprise).toBe(2.4); - expect(reading?.strength).toBe(0.36); - expect(reading?.elapsed).toBe(30); - expect(reading?.category).toBe("2"); - expect(reading?.observedAt).toBe(observedAt); - }); -}); - -describe("signal source registry", () => { - it("lists the 13 spectrum sources in backend order", () => { - expect(SPECTRUM_SOURCES).toEqual([ - "causal", - "correlation", - "cvd", - "depthflow", - "exhaustion", - "fluid", - "hawkes", - "leadlag", - "liquidity", - "manifold", - "pumpdump", - "sentiment", - "toxicity", - ]); - }); - - it("exposes gauge telemetry sources plus resonance for heatmaps", () => { - expect(SIGNAL_SOURCES).toHaveLength(14); - expect(SIGNAL_SOURCES).not.toContain("resonance"); - expect(ALL_SIGNAL_SOURCES).toHaveLength(15); - expect(ALL_SIGNAL_SOURCES).toContain("resonance"); - }); - - it("provides canonical labels for every registered source", () => { - for (const source of ALL_SIGNAL_SOURCES) { - expect(SIGNAL_LABELS[source]).toBeTruthy(); - } - - expect(SIGNAL_LABELS.exhaustion).toBe("Exhaustion"); - expect(SIGNAL_LABELS.resonance).toBe("Resonance"); - }); -}); - -const sampleReading = (): SignalReading => ({ - source: "fluid", - confidence: 0.42, - surprise: 1.8, - surpriseThreshold: 2, - strength: 0.4, - elapsed: 60, - category: "laminar", - activeReadings: 1, - readingsCapacity: 8, - observedAt: Date.now(), - bestEffort: false, - gapReason: "", - samples: 0, - minSamples: 0, - calibrating: false, - calibrated: true, - updatedAt: Date.now(), -}); - -describe("signalStore", () => { - beforeEach(() => { - signalStore.setState({ readings: {} }); - }); - - it("stores readings by source", () => { - const reading = sampleReading(); - - signalStore.actions.updateReading(reading); - - expect(signalStore.state.readings.fluid).toEqual(reading); - }); - - it("replaces prior readings for the same source", () => { - signalStore.actions.updateReading(sampleReading()); - signalStore.actions.updateReading({ - ...sampleReading(), - confidence: 0.9, - }); - - expect(signalStore.state.readings.fluid?.confidence).toBe(0.9); - }); -}); - -describe("signal diagnostics meters", () => { - const calibratedReading = { - source: "hawkes", - confidence: 0.6, - surprise: 3, - surpriseThreshold: 2, - strength: 0.4, - elapsed: 60, - category: "laminar", - activeReadings: 1, - readingsCapacity: 8, - observedAt: Date.now(), - bestEffort: false, - gapReason: "", - samples: 0, - minSamples: 0, - calibrating: false, - calibrated: true, - updatedAt: Date.now(), - }; - - it("computes confidence and surprise meters", () => { - expect(confidenceMeterValue(calibratedReading)).toBe(60); - expect(surpriseMeterValue(calibratedReading)).toBe(50); - expect(evidenceMeterValue(calibratedReading)).toBe(100); - expect(freshnessMeterValue(calibratedReading)).toBe(100); - }); - - it("uses warmup progress while calibrating", () => { - const reading = { - ...calibratedReading, - calibrating: true, - calibrated: false, - samples: 50, - minSamples: 200, - }; - - expect(warmupProgress(reading)).toBe(25); - expect(healthMeterValue(reading)).toBe(25); - expect(signalHealthStatus(reading)).toBe("calibrating"); - }); - - it("marks low-energy calibrated signals as healthy when evidence is present", () => { - const reading = { - ...calibratedReading, - confidence: 0.05, - surprise: 0.1, - }; - - expect(signalHealthStatus(reading)).toBe("healthy"); - expect(healthMeterValue(reading)).toBeGreaterThan(25); - }); - - it("keeps threshold-edge signals healthy when evidence is present", () => { - const reading = { - ...calibratedReading, - confidence: 0.25, - surprise: 6, - }; - - expect(healthMeterValue(reading)).toBeGreaterThan(25); - expect(signalHealthStatus(reading)).toBe("healthy"); - }); - - it("marks measurements older than their observation window as stale", () => { - const reading = { - ...calibratedReading, - elapsed: 1, - observedAt: Date.now() - 2000, - }; - - expect(freshnessMeterValue(reading)).toBe(0); - expect(healthMeterValue(reading)).toBe(0); - expect(signalHealthStatus(reading)).toBe("stale"); - }); - - it("does not let high confidence mask missing evidence", () => { - const reading = { - ...calibratedReading, - confidence: 1, - surprise: 6, - strength: 0, - elapsed: 60, - category: "", - activeReadings: 0, - observedAt: null, - }; - - expect(evidenceMeterValue(reading)).toBe(0); - expect(healthMeterValue(reading)).toBe(0); - expect(signalHealthStatus(reading)).toBe("flat"); - }); - - it("reports explicit measurement gaps as faults", () => { - const reading = { - ...calibratedReading, - bestEffort: true, - gapReason: "insufficient_depth", - }; - - expect(evidenceMeterValue(reading)).toBe(0); - expect(signalHealthStatus(reading)).toBe("fault"); - }); -}); diff --git a/frontend/src/collections/signals.ts b/frontend/src/collections/signals.ts deleted file mode 100644 index da1c55b1..00000000 --- a/frontend/src/collections/signals.ts +++ /dev/null @@ -1,334 +0,0 @@ -import { createStore } from "@tanstack/react-store"; - -import { - gaugeConfidenceReading, - gaugeSurpriseReading, - normalizeWireFrame, -} from "#/components/charts/confidence/gauge-frame"; - -/** Mirrors logic/sources.go SpectrumSources / SourceCount = 13. */ -export const SPECTRUM_SOURCES = [ - "causal", - "correlation", - "cvd", - "depthflow", - "exhaustion", - "fluid", - "hawkes", - "leadlag", - "liquidity", - "manifold", - "pumpdump", - "sentiment", - "toxicity", -] as const; - -type SignalSourceDef = { - id: string; - label: string; - compactLabel: string; -}; - -const SOURCE_DEFS: readonly SignalSourceDef[] = [ - { id: "causal", label: "Causal", compactLabel: "Causal" }, - { id: "correlation", label: "Correlation", compactLabel: "Corr" }, - { id: "cvd", label: "CVD", compactLabel: "CVD" }, - { id: "depthflow", label: "Depth", compactLabel: "Depth" }, - { id: "exhaustion", label: "Exhaustion", compactLabel: "Exhaust" }, - { id: "fluid", label: "Fluid", compactLabel: "Fluid" }, - { id: "hawkes", label: "Hawkes", compactLabel: "Hawkes" }, - { id: "leadlag", label: "Lead-Lag", compactLabel: "L-Lag" }, - { id: "liquidity", label: "Liquidity", compactLabel: "Liquidity" }, - { id: "manifold", label: "Manifold", compactLabel: "Manifold" }, - { id: "pumpdump", label: "Pump", compactLabel: "Pump" }, - { id: "sentiment", label: "Sentiment", compactLabel: "Sent" }, - { id: "toxicity", label: "Toxicity", compactLabel: "Toxic" }, - { id: "prediction", label: "Prediction", compactLabel: "Pred" }, - { id: "resonance", label: "Resonance", compactLabel: "Resonance" }, -]; - -const GAUGE_SOURCE_ORDER = [ - "hawkes", - "fluid", - "pumpdump", - "causal", - "depthflow", - "leadlag", - "liquidity", - "sentiment", - "toxicity", - "correlation", - "exhaustion", - "prediction", - "cvd", - "manifold", -] as const; - -export const SIGNAL_LABELS: Record = Object.fromEntries( - SOURCE_DEFS.map((entry) => [entry.id, entry.label]), -); - -export const SIGNAL_COMPACT_LABELS: Record = Object.fromEntries( - SOURCE_DEFS.map((entry) => [entry.id, entry.compactLabel]), -); - -export const SIGNAL_SOURCES = [...GAUGE_SOURCE_ORDER]; - -export const ALL_SIGNAL_SOURCES = [...GAUGE_SOURCE_ORDER, "resonance"]; - -/** Wire keys for dashboard gauge frames (legacy gauge_readings or measurement artifacts). */ -const GAUGE_WIRE_FIELDS = { - source: "source", - confidence: "confidence", - surprise: "surprise", - strength: "strength", - elapsed: "elapsed", - category: "category", - observedAt: "observed_at", - calibrated: "calibrated", - readingsCapacity: "readings_capacity", - surpriseThreshold: "surprise_threshold", - activeReadings: "active_readings", - samples: "samples", - minSamples: "min_samples", - calibrating: "calibrating", - bestEffort: "best_effort", - gapReason: "gap_reason", -} as const; - -export type SignalReading = { - source: string; - confidence: number; - surprise: number; - surpriseThreshold: number; - strength: number; - elapsed: number; - category: string; - activeReadings: number; - readingsCapacity: number; - observedAt: number | null; - bestEffort: boolean; - gapReason: string; - samples: number; - minSamples: number; - calibrating: boolean; - calibrated: boolean; - updatedAt: number; -}; - -const finiteNumber = (value: unknown): number | null => - typeof value === "number" && Number.isFinite(value) ? value : null; - -const finiteCount = (value: unknown): number => - Math.max(0, Math.floor(finiteNumber(value) ?? 0)); - -const stringValue = (value: unknown): string => - typeof value === "string" ? value.trim() : ""; - -const timestampValue = (value: unknown): number | null => { - if (typeof value === "number" && Number.isFinite(value)) { - return value; - } - - if (typeof value !== "string") { - return null; - } - - const timestamp = Date.parse(value); - - return Number.isFinite(timestamp) ? timestamp : null; -}; - -/* -parseGaugeFrame normalizes dashboard gauge websocket payloads into signal readings. -*/ -export const parseGaugeFrame = ( - frame: Record, -): SignalReading | null => { - const raw = normalizeWireFrame(frame); - const source = stringValue(raw[GAUGE_WIRE_FIELDS.source]); - - if (source === "") { - return null; - } - - const confidence = gaugeConfidenceReading(raw) ?? 0; - const surprise = gaugeSurpriseReading(raw) ?? 0; - const thresholdReading = finiteNumber( - raw[GAUGE_WIRE_FIELDS.surpriseThreshold], - ); - const surpriseThreshold = - thresholdReading !== null ? Math.max(0.1, thresholdReading) : 2; - - return { - source: source, - confidence: confidence, - surprise: surprise, - surpriseThreshold: surpriseThreshold, - strength: finiteNumber(raw[GAUGE_WIRE_FIELDS.strength]) ?? 0, - elapsed: finiteNumber(raw[GAUGE_WIRE_FIELDS.elapsed]) ?? 0, - category: stringValue(raw[GAUGE_WIRE_FIELDS.category]), - activeReadings: finiteCount(raw[GAUGE_WIRE_FIELDS.activeReadings]), - readingsCapacity: finiteCount(raw[GAUGE_WIRE_FIELDS.readingsCapacity]), - observedAt: timestampValue(raw[GAUGE_WIRE_FIELDS.observedAt]), - bestEffort: raw[GAUGE_WIRE_FIELDS.bestEffort] === true, - gapReason: stringValue(raw[GAUGE_WIRE_FIELDS.gapReason]), - samples: finiteCount(raw[GAUGE_WIRE_FIELDS.samples]), - minSamples: finiteCount(raw[GAUGE_WIRE_FIELDS.minSamples]), - calibrating: raw[GAUGE_WIRE_FIELDS.calibrating] === true, - calibrated: raw[GAUGE_WIRE_FIELDS.calibrated] === true, - updatedAt: Date.now(), - }; -}; - -export const warmupProgress = (reading: SignalReading): number => { - if (reading.minSamples <= 0) { - return 0; - } - - return Math.min(100, (reading.samples / reading.minSamples) * 100); -}; - -export const confidenceMeterValue = (reading: SignalReading): number => - Math.min(100, Math.max(0, reading.confidence * 100)); - -export const surpriseMeterValue = (reading: SignalReading): number => { - const scale = reading.surpriseThreshold * 3; - - if (scale <= 0) { - return 0; - } - - return Math.min(100, (reading.surprise / scale) * 100); -}; - -export const evidenceMeterValue = (reading: SignalReading): number => { - if (reading.bestEffort || reading.gapReason !== "") { - return 0; - } - - if (reading.observedAt === null) { - return 0; - } - - if (reading.strength <= 0) { - return 0; - } - - if (reading.elapsed <= 0) { - return 0; - } - - if (reading.activeReadings > 0) { - return 100; - } - - if (reading.category !== "") { - return 100; - } - - return 0; -}; - -export const freshnessMeterValue = (reading: SignalReading): number => { - if (reading.observedAt === null || reading.elapsed <= 0) { - return 0; - } - - const observedAgeSeconds = Math.max( - 0, - (reading.updatedAt - reading.observedAt) / 1000, - ); - - if (observedAgeSeconds > reading.elapsed) { - return 0; - } - - return 100; -}; - -export const healthMeterValue = (reading: SignalReading): number => { - if (reading.calibrating) { - return warmupProgress(reading); - } - - if (!reading.calibrated) { - return 0; - } - - const evidenceScore = evidenceMeterValue(reading); - const freshnessScore = freshnessMeterValue(reading); - - if (evidenceScore <= 0 || freshnessScore <= 0) { - return 0; - } - - const confidenceScore = confidenceMeterValue(reading); - const surpriseScore = surpriseMeterValue(reading); - const operational = (evidenceScore + freshnessScore) / 2; - const energy = (confidenceScore + surpriseScore) / 2; - - return Math.round(0.65 * operational + 0.35 * energy); -}; - -export type SignalHealthStatus = - | "waiting" - | "calibrating" - | "fault" - | "stale" - | "flat" - | "healthy"; - -export const signalHealthStatus = ( - reading: SignalReading | null, -): SignalHealthStatus => { - if (reading === null) { - return "waiting"; - } - - if (reading.calibrating) { - return "calibrating"; - } - - if (!reading.calibrated) { - return "waiting"; - } - - if (reading.bestEffort || reading.gapReason !== "") { - return "fault"; - } - - if (evidenceMeterValue(reading) <= 0) { - return "flat"; - } - - if (freshnessMeterValue(reading) <= 0) { - return "stale"; - } - - return "healthy"; -}; - -export const isSignalDiagnosticReading = (reading: SignalReading): boolean => { - if (reading.calibrated || reading.calibrating) { - return true; - } - - return reading.samples > 0 || reading.minSamples > 0; -}; - -export const signalStore = createStore( - { - readings: {} as Record, - }, - ({ setState }) => ({ - updateReading: (reading: SignalReading) => - setState((prev) => ({ - ...prev, - readings: { - ...prev.readings, - [reading.source]: reading, - }, - })), - }), -); diff --git a/frontend/src/collections/status.ts b/frontend/src/collections/status.ts deleted file mode 100644 index ab0b2ec2..00000000 --- a/frontend/src/collections/status.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { createStore } from "@tanstack/react-store"; - -export const statusStore = createStore( - { - actions: [] as Array<{ - type: string; - symbol: string; - reason?: string; - verdict: "filled" | "submitted" | "rejected"; - ts: number; - }>, - positionViews: [] as Array<{ - symbol: string; - qty: number; - avgEntry: number; - mark: number; - exitValue: number; - unrealized: number; - unrealizedPct: number; - priced: boolean; - exitFeeRate: number; - stopPrice?: number; - peakPrice?: number; - offset?: number; - markSource?: string; - }>, - }, - ({ setState }) => ({ - updateActions: ( - actions: Array<{ - type: string; - symbol: string; - reason?: string; - verdict: "filled" | "submitted" | "rejected"; - ts: number; - }>, - ) => - setState((prev) => ({ - ...prev, - actions: actions, - })), - updatePositionViews: ( - positionViews: Array<{ - symbol: string; - qty: number; - avgEntry: number; - mark: number; - exitValue: number; - unrealized: number; - unrealizedPct: number; - priced: boolean; - exitFeeRate: number; - stopPrice?: number; - peakPrice?: number; - offset?: number; - markSource?: string; - }>, - ) => - setState((prev) => ({ - ...prev, - positionViews: positionViews, - })), - }), -); diff --git a/frontend/src/collections/terminal.ts b/frontend/src/collections/terminal.ts new file mode 100644 index 00000000..2566c8d1 --- /dev/null +++ b/frontend/src/collections/terminal.ts @@ -0,0 +1,80 @@ +import { createStore } from "@tanstack/react-store"; + +export type TerminalSurface = + | "dashboard" + | "signals" + | "decisions" + | "xray" + | "cortex" + | "allocation"; + +export const DEFAULT_FOCUS_SYMBOL = "stream"; + +export const terminalStore = createStore( + { + scanlines: true, + fieldStyle: "Heatmap" as "Heatmap" | "Contour", + selectedSource: "fluid", + inspectorSource: null as string | null, + paletteOpen: false, + paletteQuery: "", + paletteIndex: 0, + focusSymbol: DEFAULT_FOCUS_SYMBOL, + }, + ({ setState }) => ({ + toggleScanlines: () => + setState((prev) => ({ + ...prev, + scanlines: !prev.scanlines, + })), + toggleFieldStyle: () => + setState((prev) => ({ + ...prev, + fieldStyle: prev.fieldStyle === "Heatmap" ? "Contour" : "Heatmap", + })), + selectSource: (selectedSource: string) => + setState((prev) => ({ + ...prev, + selectedSource, + })), + inspectSource: (source: string) => + setState((prev) => ({ + ...prev, + selectedSource: source, + inspectorSource: source, + })), + closeInspect: () => + setState((prev) => ({ + ...prev, + inspectorSource: null, + })), + openPalette: () => + setState((prev) => ({ + ...prev, + paletteOpen: true, + paletteQuery: "", + paletteIndex: 0, + })), + closePalette: () => + setState((prev) => ({ + ...prev, + paletteOpen: false, + })), + setPaletteQuery: (paletteQuery: string) => + setState((prev) => ({ + ...prev, + paletteQuery, + paletteIndex: 0, + })), + bumpPaletteIndex: (delta: number) => + setState((prev) => ({ + ...prev, + paletteIndex: prev.paletteIndex + delta, + })), + selectFocusSymbol: (focusSymbol: string) => + setState((prev) => ({ + ...prev, + focusSymbol, + })), + }), +); diff --git a/frontend/src/collections/tick.ts b/frontend/src/collections/tick.ts new file mode 100644 index 00000000..81faf277 --- /dev/null +++ b/frontend/src/collections/tick.ts @@ -0,0 +1,3 @@ +import { createFrameCollection } from "#/collections/frames"; + +export const tickStore = createFrameCollection(); diff --git a/frontend/src/components/ThemeToggle.tsx b/frontend/src/components/ThemeToggle.tsx deleted file mode 100644 index 85b34723..00000000 --- a/frontend/src/components/ThemeToggle.tsx +++ /dev/null @@ -1,83 +0,0 @@ - -import { useEffect, useState } from "react"; - -type ThemeMode = "light" | "dark" | "auto"; - -function getInitialMode(): ThemeMode { - if (typeof window === "undefined") { - return "auto"; - } - - const stored = window.localStorage.getItem("theme"); - if (stored === "light" || stored === "dark" || stored === "auto") { - return stored; - } - - return "auto"; -} - -function applyThemeMode(mode: ThemeMode) { - const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches; - const resolved = mode === "auto" ? (prefersDark ? "dark" : "light") : mode; - - document.documentElement.classList.remove("light", "dark"); - document.documentElement.classList.add(resolved); - - if (mode === "auto") { - document.documentElement.removeAttribute("data-theme"); - } else { - document.documentElement.setAttribute("data-theme", mode); - } - - document.documentElement.style.colorScheme = resolved; -} - -export default function ThemeToggle() { - const [mode, setMode] = useState("auto"); - - useEffect(() => { - const initialMode = getInitialMode(); - setMode(initialMode); - applyThemeMode(initialMode); - }, []); - - useEffect(() => { - if (mode !== "auto") { - return; - } - - const media = window.matchMedia("(prefers-color-scheme: dark)"); - const onChange = () => applyThemeMode("auto"); - - media.addEventListener("change", onChange); - return () => { - media.removeEventListener("change", onChange); - }; - }, [mode]); - - function toggleMode() { - const nextMode: ThemeMode = - mode === "light" ? "dark" : mode === "dark" ? "auto" : "light"; - setMode(nextMode); - applyThemeMode(nextMode); - window.localStorage.setItem("theme", nextMode); - } - - const label = - mode === "auto" - ? "Theme mode: auto (system). Click to switch to light mode." - : `Theme mode: ${mode}. Click to switch mode.`; - - return ( - - ); -} - diff --git a/frontend/src/components/audit.tsx b/frontend/src/components/audit.tsx deleted file mode 100644 index dc6a8d00..00000000 --- a/frontend/src/components/audit.tsx +++ /dev/null @@ -1,69 +0,0 @@ - -import { - useSymmAuditRows, - useSymmConnected, -} from "#/lib/symm/use-dashboard-data"; -import { EmptyHint } from "./hint"; -import { SidebarSection } from "./sidebar-section"; - -const formatTime = (value: string) => { - const parsed = Date.parse(value); - - if (!Number.isFinite(parsed)) { - return value; - } - - return new Intl.DateTimeFormat(undefined, { - hour: "2-digit", - minute: "2-digit", - second: "2-digit", - hour12: false, - }).format(parsed); -}; - -export const AuditPanel = () => { - const connected = useSymmConnected(); - const rows = useSymmAuditRows(); - - return ( - - {rows.length === 0 ? ( - - ) : ( -
    - {rows.map((row) => ( -
  • -
    -
    -
    - {row.reason ?? row.event} -
    -
    - {[row.event, row.symbol, row.source] - .filter(Boolean) - .join(" · ")} -
    -
    - - #{row.seq} · {formatTime(row.ts)} - -
    - {row.summary ? ( -
    - {row.summary} -
    - ) : null} -
  • - ))} -
- )} -
- ); -}; - diff --git a/frontend/src/components/charts/cognitive/CognitivePanel.tsx b/frontend/src/components/charts/cognitive/CognitivePanel.tsx deleted file mode 100644 index e535b107..00000000 --- a/frontend/src/components/charts/cognitive/CognitivePanel.tsx +++ /dev/null @@ -1,240 +0,0 @@ -import { useStore } from "@tanstack/react-store"; -import { - type CognitiveReading, - cognitiveScopes, - cognitiveStore, -} from "#/collections/cognitive"; -import { Badge } from "#/components/ui/badge"; -import { Card, CardFrame, CardPanel } from "#/components/ui/card"; -import { Flex } from "#/components/ui/flex"; -import { cn } from "@/lib/utils"; - -const clampPercent = (value: number): number => - Math.min(100, Math.max(0, value * 100)); - -const MetricBar = ({ - label, - value, - max, - tone = "sky", -}: { - label: string; - value: number; - max: number; - tone?: "sky" | "amber" | "rose" | "emerald"; -}) => { - const ratio = max > 0 ? value / max : 0; - const width = clampPercent(ratio); - - return ( - - - {label} - - {value.toFixed(3)} / {max.toFixed(3)} - - -
-
-
- - ); -}; - -const ScopeCard = ({ - reading, - active, - onSelect, -}: { - reading: CognitiveReading; - active: boolean; - onSelect: () => void; -}) => ( - -); - -const ReadingDetail = ({ reading }: { reading: CognitiveReading }) => { - const entropyRatio = - reading.entropyThreshold > 0 - ? reading.entropyBits / reading.entropyThreshold - : 0; - - return ( - - - {reading.regimePrefix || "no-regime"} - cohort {reading.regimeCohort} - {reading.ambiguous ? ambiguous : null} - {reading.sideline ? ( - sideline - ) : null} - - - - -

DMT sequence

-

- {reading.sequence || "—"} -

-
-
- - -

Entropy gate

- = 1 ? "rose" : "emerald"} - /> - - -
- - -

Lookahead beam

- - - paths: {reading.lookaheadPaths} - winner: {reading.winnerClass || "—"} - {reading.prewarmPaths !== null ? ( - prewarm paths: {reading.prewarmPaths} - ) : null} - {reading.prewarmScore !== null ? ( - prewarm score: {reading.prewarmScore.toFixed(3)} - ) : null} - -
- - - -

Beam tree (path count × score)

-
- {Array.from({ length: Math.max(reading.lookaheadPaths, 1) }).map( - (_, index) => { - const weight = - reading.lookaheadPaths > 0 - ? reading.lookaheadScore / - Math.max(reading.lookaheadPaths - index, 1) - : 0; - - return ( -
-

- branch {index + 1} -

-

{weight.toFixed(3)}

-
- ); - }, - )} -
-
-
-
- ); -}; - -export const CognitivePanel = () => { - const { readings, selectedScope } = useStore(cognitiveStore); - const { selectScope } = cognitiveStore.actions; - const scopes = cognitiveScopes(); - const activeScope = - selectedScope !== "" && readings[selectedScope] - ? selectedScope - : (scopes[0] ?? ""); - const activeReading = activeScope ? readings[activeScope] : null; - - return ( - - - - -

Scopes

- {scopes.length === 0 ? ( -

- Waiting for cognitive frames from the backend… -

- ) : ( - scopes.map((scope) => ( - selectScope(scope)} - /> - )) - )} -
- {activeReading ? ( - - ) : ( - - Cognitive memory has not sealed a reading yet. - - )} -
-
-
- ); -}; diff --git a/frontend/src/components/charts/confidence/Gauges.tsx b/frontend/src/components/charts/confidence/Gauges.tsx deleted file mode 100644 index c0b9a1b6..00000000 --- a/frontend/src/components/charts/confidence/Gauges.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { CircleAlertIcon } from "lucide-react"; -import { memo } from "react"; -import { SciChartReact } from "scichart-react"; -import { appStore } from "#/collections/app"; -import { drawSignalGauge } from "#/components/charts/confidence/draw-signal-gauge"; -import { Card, CardPanel } from "#/components/ui/card"; -import { Frame, FrameFooter } from "#/components/ui/frame"; - -export const SignalGauge = memo(function SignalGauge({ - source, - label, -}: { - source: string; - label: string; -}) { - return ( - - - - { - appStore.actions.updateGaugeUpdater(source, result.addData); - - return () => appStore.actions.updateGaugeUpdater(source, null); - }} - style={{ height: "100%", width: "100%" }} - /> - - - -
- -

{label}

-
-
- - ); -}); diff --git a/frontend/src/components/charts/confidence/SignalHeatmap.tsx b/frontend/src/components/charts/confidence/SignalHeatmap.tsx deleted file mode 100644 index 86e19d33..00000000 --- a/frontend/src/components/charts/confidence/SignalHeatmap.tsx +++ /dev/null @@ -1,158 +0,0 @@ -import { memo } from "react"; -import { - EAutoRange, - EAxisAlignment, - ECoordinateMode, - EHorizontalAnchorPoint, - EVerticalAnchorPoint, - HeatmapColorMap, - NumberRange, - NumericAxis, - SciChartSurface, - TextAnnotation, - UniformHeatmapDataSeries, - UniformHeatmapRenderableSeries, - zeroArray2D, -} from "scichart"; -import { SciChartReact } from "scichart-react"; -import { appStore } from "#/collections/app"; -import { gaugeConfidenceReading } from "#/components/charts/confidence/gauge-frame"; -import { ensureSciChartWasm } from "#/lib/utils"; - -const TIME_COLS = 120; - -const initSignalHeatmap = async ( - rootElement: string | HTMLDivElement, - sources: readonly string[], - labels: Record, -) => { - await ensureSciChartWasm(); - - const { sciChartSurface, wasmContext } = await SciChartSurface.create( - rootElement, - { freezeWhenOutOfView: true }, - ); - const rowCount = sources.length; - const zValues = zeroArray2D([rowCount, TIME_COLS]); - - sciChartSurface.xAxes.add( - new NumericAxis(wasmContext, { - isVisible: false, - autoRange: EAutoRange.Never, - visibleRange: new NumberRange(0, TIME_COLS), - }), - ); - - sciChartSurface.yAxes.add( - new NumericAxis(wasmContext, { - axisAlignment: EAxisAlignment.Left, - isVisible: false, - autoRange: EAutoRange.Never, - visibleRange: new NumberRange(-0.5, rowCount - 0.5), - }), - ); - - const dataSeries = new UniformHeatmapDataSeries(wasmContext, { - zValues, - xStart: 0, - xStep: 1, - yStart: 0, - yStep: 1, - }); - - sciChartSurface.renderableSeries.add( - new UniformHeatmapRenderableSeries(wasmContext, { - dataSeries, - colorMap: new HeatmapColorMap({ - minimum: 0, - maximum: 4, - gradientStops: [ - { offset: 0, color: "#0b0f14" }, - { offset: 0.15, color: "#1e3a5f" }, - { offset: 0.4, color: "#1d6c4c" }, - { offset: 0.7, color: "#38bdf8" }, - { offset: 1, color: "#4ade80" }, - ], - }), - useLinearTextureFiltering: true, - }), - ); - - for (let rowIndex = 0; rowIndex < sources.length; rowIndex += 1) { - sciChartSurface.annotations.add( - new TextAnnotation({ - text: labels[sources[rowIndex]] ?? sources[rowIndex], - x1: 1, - y1: rowIndex, - xCoordinateMode: ECoordinateMode.DataValue, - yCoordinateMode: ECoordinateMode.DataValue, - horizontalAnchorPoint: EHorizontalAnchorPoint.Left, - verticalAnchorPoint: EVerticalAnchorPoint.Center, - fontSize: 9, - textColor: "rgba(226,232,240,0.7)", - background: "rgba(11,15,20,0.6)", - }), - ); - } - - sciChartSurface.background = "transparent"; - - const sourceIndex = new Map(sources.map((source, index) => [source, index])); - - const addData = (frame: Record) => { - const source = frame.source; - - if (typeof source !== "string") { - return; - } - - const confidence = gaugeConfidenceReading(frame); - - if (confidence === null) { - return; - } - - const rowIndex = sourceIndex.get(source); - - if (rowIndex === undefined) { - return; - } - - const row = zValues[rowIndex]; - const value = Math.min(4, Math.max(0, confidence) * 4); - - for (let col = 0; col < TIME_COLS - 1; col += 1) { - row[col] = row[col + 1]; - } - - row[TIME_COLS - 1] = value; - dataSeries.setZValues(zValues); - sciChartSurface.invalidateElement(); - }; - - return { sciChartSurface, wasmContext, addData }; -}; - -export const SignalHeatmap = memo(function SignalHeatmap({ - sources, - labels, -}: { - sources: string[]; - labels: Record; -}) { - return ( - - initSignalHeatmap(rootElement, sources, labels) - } - onInit={(result) => { - appStore.actions.updateConfidenceHeatmapUpdater(result.addData); - - return () => appStore.actions.updateConfidenceHeatmapUpdater(null); - }} - className="h-full w-full" - style={{ width: "100%", height: "100%" }} - /> - ); -}); diff --git a/frontend/src/components/charts/confidence/SignalSurpriseHeatmap.tsx b/frontend/src/components/charts/confidence/SignalSurpriseHeatmap.tsx deleted file mode 100644 index 621a8675..00000000 --- a/frontend/src/components/charts/confidence/SignalSurpriseHeatmap.tsx +++ /dev/null @@ -1,161 +0,0 @@ -import { memo } from "react"; -import { - EAutoRange, - EAxisAlignment, - ECoordinateMode, - EHorizontalAnchorPoint, - EVerticalAnchorPoint, - HeatmapColorMap, - NumberRange, - NumericAxis, - SciChartSurface, - TextAnnotation, - UniformHeatmapDataSeries, - UniformHeatmapRenderableSeries, - zeroArray2D, -} from "scichart"; -import { SciChartReact } from "scichart-react"; - -import { appStore } from "#/collections/app"; -import { gaugeSurpriseReading } from "#/components/charts/confidence/gauge-frame"; -import { ensureSciChartWasm } from "#/lib/utils"; - -const TIME_COLS = 120; -const GAUGE_FULL_SIGMA = 4; - -const initSignalSurpriseHeatmap = async ( - rootElement: string | HTMLDivElement, - sources: readonly string[], - labels: Record, -) => { - await ensureSciChartWasm(); - - const { sciChartSurface, wasmContext } = await SciChartSurface.create( - rootElement, - { freezeWhenOutOfView: true }, - ); - const rowCount = sources.length; - const zValues = zeroArray2D([rowCount, TIME_COLS]); - - sciChartSurface.xAxes.add( - new NumericAxis(wasmContext, { - isVisible: false, - autoRange: EAutoRange.Never, - visibleRange: new NumberRange(0, TIME_COLS), - }), - ); - - sciChartSurface.yAxes.add( - new NumericAxis(wasmContext, { - axisAlignment: EAxisAlignment.Left, - isVisible: false, - autoRange: EAutoRange.Never, - visibleRange: new NumberRange(-0.5, rowCount - 0.5), - }), - ); - - const dataSeries = new UniformHeatmapDataSeries(wasmContext, { - zValues, - xStart: 0, - xStep: 1, - yStart: 0, - yStep: 1, - }); - - sciChartSurface.renderableSeries.add( - new UniformHeatmapRenderableSeries(wasmContext, { - dataSeries, - colorMap: new HeatmapColorMap({ - minimum: 0, - maximum: 4, - gradientStops: [ - { offset: 0, color: "#0b0f14" }, - { offset: 0.2, color: "#312e81" }, - { offset: 0.45, color: "#7c3aed" }, - { offset: 0.7, color: "#f97316" }, - { offset: 1, color: "#fb7185" }, - ], - }), - useLinearTextureFiltering: true, - }), - ); - - for (let rowIndex = 0; rowIndex < sources.length; rowIndex += 1) { - sciChartSurface.annotations.add( - new TextAnnotation({ - text: labels[sources[rowIndex]] ?? sources[rowIndex], - x1: 1, - y1: rowIndex, - xCoordinateMode: ECoordinateMode.DataValue, - yCoordinateMode: ECoordinateMode.DataValue, - horizontalAnchorPoint: EHorizontalAnchorPoint.Left, - verticalAnchorPoint: EVerticalAnchorPoint.Center, - fontSize: 9, - textColor: "rgba(226,232,240,0.7)", - background: "rgba(11,15,20,0.6)", - }), - ); - } - - sciChartSurface.background = "transparent"; - - const sourceIndex = new Map(sources.map((source, index) => [source, index])); - - const addData = (frame: Record) => { - const source = frame.source; - - if (typeof source !== "string") { - return; - } - - const surprise = gaugeSurpriseReading(frame); - - if (surprise === null) { - return; - } - - const rowIndex = sourceIndex.get(source); - - if (rowIndex === undefined) { - return; - } - - const row = zValues[rowIndex]; - const value = - surprise <= 0 ? 0 : Math.min(4, (surprise / GAUGE_FULL_SIGMA) * 4); - - for (let col = 0; col < TIME_COLS - 1; col += 1) { - row[col] = row[col + 1]; - } - - row[TIME_COLS - 1] = value; - dataSeries.setZValues(zValues); - sciChartSurface.invalidateElement(); - }; - - return { sciChartSurface, wasmContext, addData }; -}; - -export const SignalSurpriseHeatmap = memo(function SignalSurpriseHeatmap({ - sources, - labels, -}: { - sources: string[]; - labels: Record; -}) { - return ( - - initSignalSurpriseHeatmap(rootElement, sources, labels) - } - onInit={(result) => { - appStore.actions.updateSurpriseHeatmapUpdater(result.addData); - - return () => appStore.actions.updateSurpriseHeatmapUpdater(null); - }} - className="h-full w-full" - style={{ width: "100%", height: "100%" }} - /> - ); -}); diff --git a/frontend/src/components/charts/confidence/confidence-subchart.ts b/frontend/src/components/charts/confidence/confidence-subchart.ts deleted file mode 100644 index 0bbb33e1..00000000 --- a/frontend/src/components/charts/confidence/confidence-subchart.ts +++ /dev/null @@ -1,217 +0,0 @@ -import { - EAxisAlignment, - ECoordinateMode, - EHorizontalAnchorPoint, - EPolarAxisMode, - EPolarLabelMode, - EStrokeLineJoin, - EVerticalAnchorPoint, - NativeTextAnnotation, - NumberRange, - PolarArcAnnotation, - PolarNumericAxis, - PolarPointerAnnotation, - type SciChartPolarSubSurface, - Thickness, -} from "scichart"; - -import { appTheme } from "#/components/charts/shared/theme"; - -const GAUGE_BANDS = [50, 75, 100] as const; -const GRADIENT_COLORS = [ - appTheme.VividGreen, - appTheme.VividOrange, - appTheme.VividPink, -] as const; - -type GaugeArcSet = { - valueArcs: PolarArcAnnotation[]; - pointer: PolarPointerAnnotation; - label: NativeTextAnnotation; -}; - -const applyGaugeNeedle = ( - gaugeArcs: GaugeArcSet, - needlePercent: number, -): void => { - const pointerValue = Math.max(0, Math.min(100, needlePercent)); - let hasPointerPassedValue = false; - - gaugeArcs.pointer.x1 = pointerValue; - - for (let index = 0; index < gaugeArcs.valueArcs.length; index += 1) { - const bandTop = GAUGE_BANDS[index]; - const bandBottom = GAUGE_BANDS[index - 1] ?? 0; - const arcEnd = hasPointerPassedValue - ? bandBottom - : bandTop > pointerValue - ? pointerValue - : bandTop; - - gaugeArcs.valueArcs[index].y1 = bandBottom; - gaugeArcs.valueArcs[index].y2 = arcEnd; - - if (bandTop >= pointerValue) { - hasPointerPassedValue = true; - } - } -}; - -const buildGaugeArcs = ( - subChart: SciChartPolarSubSurface, - pointerValue: number, -): GaugeArcSet => { - const valueArcs: PolarArcAnnotation[] = []; - let hasPointerPassedValue = false; - - for (let index = 0; index < GAUGE_BANDS.length; index += 1) { - const bandTop = GAUGE_BANDS[index]; - const bandBottom = GAUGE_BANDS[index - 1] ?? 0; - - subChart.annotations.add( - new PolarArcAnnotation({ - x2: 7.6, - x1: 7.9, - y1: bandBottom, - y2: bandTop, - fill: GRADIENT_COLORS[index], - strokeThickness: 0, - }), - ); - - const valueArc = new PolarArcAnnotation({ - id: `arc${index}`, - x2: 8.1, - x1: 10, - y1: bandBottom, - y2: hasPointerPassedValue - ? bandBottom - : bandTop > pointerValue - ? pointerValue - : bandTop, - fill: GRADIENT_COLORS[index], - strokeThickness: 0, - }); - - valueArcs.push(valueArc); - subChart.annotations.add(valueArc); - - if (bandTop >= pointerValue) { - hasPointerPassedValue = true; - } - } - - const pointer = new PolarPointerAnnotation({ - x1: pointerValue, - y1: 7.6, - xCoordinateMode: ECoordinateMode.DataValue, - yCoordinateMode: ECoordinateMode.DataValue, - pointerStyle: { - baseSize: 0, - strokeWidth: 0, - }, - pointerArrowStyle: { - strokeWidth: 2, - stroke: "white", - fill: "none", - height: 0.4, - width: 0.25, - }, - strokeLineJoin: EStrokeLineJoin.Miter, - }); - - const label = new NativeTextAnnotation({ - text: "0", - x1: 0, - y1: 0, - textColor: "#FFFFFF", - fontSize: 12, - padding: new Thickness(0, 0, 16, 0), - xCoordinateMode: ECoordinateMode.DataValue, - yCoordinateMode: ECoordinateMode.DataValue, - verticalAnchorPoint: EVerticalAnchorPoint.Center, - horizontalAnchorPoint: EHorizontalAnchorPoint.Center, - }); - - subChart.annotations.add(pointer, label); - - return { valueArcs, pointer, label }; -}; - -export type ConfidenceSubChartControls = { - update: (confidence: number, calibrating?: boolean) => void; -}; - -export const createConfidenceSubChart = ( - subChart: SciChartPolarSubSurface, -): ConfidenceSubChartControls => { - const wasmContext = subChart.webAssemblyContext2D; - - subChart.xAxes.add( - new PolarNumericAxis(wasmContext, { - polarAxisMode: EPolarAxisMode.Radial, - axisAlignment: EAxisAlignment.Right, - startAngle: (Math.PI * 3) / 2 + Math.PI / 4, - drawLabels: false, - drawMinorGridLines: false, - drawMajorGridLines: false, - drawMajorTickLines: false, - drawMinorTickLines: false, - labelStyle: { - fontSize: 8, - }, - useNativeText: true, - }), - ); - - subChart.yAxes.add( - new PolarNumericAxis(wasmContext, { - polarAxisMode: EPolarAxisMode.Angular, - axisAlignment: EAxisAlignment.Top, - polarLabelMode: EPolarLabelMode.Perpendicular, - visibleRange: new NumberRange(0, 100), - zoomExtentsToInitialRange: true, - flippedCoordinates: true, - totalAngleDegrees: 220, - startAngleDegrees: -20, - drawMinorGridLines: false, - drawMajorGridLines: false, - drawMinorTickLines: false, - drawMajorTickLines: false, - labelPrecision: 0, - labelStyle: { - fontSize: 8, - }, - useNativeText: true, - }), - ); - - subChart.annotations.add( - new PolarArcAnnotation({ - x2: 8.1, - x1: 10, - y1: 0, - y2: 100, - fill: "#88888844", - strokeThickness: 0, - }), - ); - - const gaugeArcs = buildGaugeArcs(subChart, 0); - - return { - update(confidence: number, calibrating = false) { - if (subChart.isDeleted) { - return; - } - - const needlePercent = confidence * 100; - - applyGaugeNeedle(gaugeArcs, needlePercent); - gaugeArcs.label.text = calibrating - ? `${Math.round(needlePercent)}%` - : confidence.toFixed(2); - subChart.invalidateElement(); - }, - }; -}; diff --git a/frontend/src/components/charts/confidence/draw-signal-gauge.ts b/frontend/src/components/charts/confidence/draw-signal-gauge.ts deleted file mode 100644 index e6cf9476..00000000 --- a/frontend/src/components/charts/confidence/draw-signal-gauge.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { - Rect, - SciChartPolarSubSurface, - SciChartPolarSurface, - SciChartSubSurface, - Thickness, -} from "scichart"; - -import { createConfidenceSubChart } from "#/components/charts/confidence/confidence-subchart"; -import { - gaugeConfidenceReading, - gaugeSurpriseReading, -} from "#/components/charts/confidence/gauge-frame"; -import { createSurpriseSubChart } from "#/components/charts/confidence/surprise-subchart"; -import { appTheme } from "#/components/charts/shared/theme"; -import { ensureSciChartWasm } from "#/lib/utils"; - -const CONFIDENCE_SUBCHART_RECT = new Rect(0, 0, 1, 0.86); -const SURPRISE_SUBCHART_RECT = new Rect(0, 0.86, 1, 0.14); - -const finiteNumber = (value: unknown): number | null => - typeof value === "number" && Number.isFinite(value) ? value : null; - -export const drawSignalGauge = async (rootElement: string | HTMLDivElement) => { - await ensureSciChartWasm(); - - const { sciChartSurface, wasmContext } = await SciChartPolarSurface.create( - rootElement, - { - padding: new Thickness(0, 0, 0, 0), - background: appTheme.Background, - freezeWhenOutOfView: true, - }, - ); - - const confidenceSubChart = SciChartPolarSubSurface.createSubSurface( - sciChartSurface, - { - position: CONFIDENCE_SUBCHART_RECT, - padding: new Thickness(0, 0, 0, 0), - background: appTheme.Background, - }, - ); - - const surpriseSubChart = SciChartSubSurface.createSubSurface( - sciChartSurface, - { - position: SURPRISE_SUBCHART_RECT, - padding: new Thickness(0, 0, 0, 0), - background: appTheme.Background, - }, - ); - - const confidenceControls = createConfidenceSubChart(confidenceSubChart); - const surpriseControls = createSurpriseSubChart(surpriseSubChart); - - const addData = (frame: Record) => { - const confidence = gaugeConfidenceReading(frame) ?? 0; - const surprise = gaugeSurpriseReading(frame) ?? 0; - - const thresholdReading = finiteNumber(frame.surprise_threshold); - const threshold = - thresholdReading !== null ? Math.max(0.1, thresholdReading) : 2; - - confidenceControls.update(confidence, false); - surpriseControls.update(surprise, threshold * 3, threshold); - }; - - return { - sciChartSurface, - wasmContext, - addData, - }; -}; diff --git a/frontend/src/components/charts/confidence/gauge-frame.ts b/frontend/src/components/charts/confidence/gauge-frame.ts deleted file mode 100644 index 504cfc9c..00000000 --- a/frontend/src/components/charts/confidence/gauge-frame.ts +++ /dev/null @@ -1,157 +0,0 @@ -const finiteNumber = (value: unknown): number | null => - typeof value === "number" && Number.isFinite(value) ? value : null; - -const finiteCount = (value: unknown): number => - Math.max(0, Math.floor(finiteNumber(value) ?? 0)); - -const wireString = (frame: Record, key: string): string => { - const value = frame[key]; - - return typeof value === "string" ? value.trim() : ""; -}; - -const wireBoolean = (frame: Record, key: string): boolean => - frame[key] === true; - -const wireRecord = (value: unknown): Record | null => - typeof value === "object" && value !== null - ? (value as Record) - : null; - -const nestedNumber = ( - frame: Record, - ...path: string[] -): number | null => { - let current: unknown = frame; - - for (const segment of path) { - const record = wireRecord(current); - - if (record === null) { - return null; - } - - current = record[segment]; - } - - return finiteNumber(current); -}; - -/* -normalizeWireFrame maps measurement artifacts and legacy gauge payloads -into the lowercase dashboard wire shape. -*/ -export const normalizeWireFrame = ( - frame: Record, -): Record => { - const source = - wireString(frame, "source") || - wireString(frame, "origin") || - wireString(frame, "Source"); - const symbol = - wireString(frame, "symbol") || - wireString(frame, "scope") || - wireString(frame, "Symbol"); - const confidence = - nestedNumber(frame, "output", "confidence") ?? - finiteNumber(frame.confidence) ?? - finiteNumber(frame.Confidence); - const surprise = - nestedNumber(frame, "output", "surprise") ?? - nestedNumber(frame, "output", "value") ?? - gaugeSurpriseReading(frame) ?? - finiteNumber(frame.Surprise); - const thresholdReading = - finiteNumber(frame.surprise_threshold) ?? - finiteNumber(frame.surpriseThreshold); - const samples = finiteCount(frame.samples ?? frame.Samples); - const minSamples = finiteCount(frame.min_samples ?? frame.minSamples); - const strength = - nestedNumber(frame, "output", "strength") ?? - finiteNumber(frame.strength) ?? - finiteNumber(frame.Strength); - const elapsed = - nestedNumber(frame, "output", "elapsed") ?? - finiteNumber(frame.elapsed) ?? - finiteNumber(frame.Elapsed); - const activeReadings = finiteCount( - frame.active_readings ?? frame.activeReadings ?? frame.ActiveReadings, - ); - const readingsCapacity = finiteCount( - frame.readings_capacity ?? frame.readingsCapacity ?? frame.ReadingsCapacity, - ); - const observedAt = - frame.observed_at ?? - frame.observedAt ?? - frame.ObservedAt ?? - (typeof frame.timestamp === "number" ? frame.timestamp : undefined); - const category = - wireString(frame, "category") || - wireString(frame, "Category") || - (nestedNumber(frame, "output", "category") !== null - ? String(nestedNumber(frame, "output", "category")) - : ""); - const gapReason = - wireString(frame, "gap_reason") || - wireString(frame, "gapReason") || - wireString(frame, "GapReason"); - const bestEffort = - wireBoolean(frame, "best_effort") || - wireBoolean(frame, "bestEffort") || - wireBoolean(frame, "BestEffort"); - const calibrating = frame.calibrating === true || frame.Calibrating === true; - const calibrated = frame.calibrated === true || frame.Calibrated === true; - - return { - ...frame, - source: source, - symbol: symbol, - confidence: confidence ?? 0, - surprise: surprise, - surprise_threshold: - thresholdReading !== null ? Math.max(0.1, thresholdReading) : 2, - strength: strength ?? 0, - elapsed: elapsed ?? 0, - active_readings: activeReadings, - readings_capacity: readingsCapacity, - observed_at: observedAt, - category: category, - best_effort: bestEffort, - gap_reason: gapReason, - samples: samples, - min_samples: minSamples, - calibrating: calibrating, - calibrated: calibrated, - }; -}; - -/* -gaugeConfidenceReading mirrors the dashboard gauge needle input. -Confidence is always the softmax category share (1/N for a uniform guess). -*/ -export const gaugeConfidenceReading = ( - frame: Record, -): number | null => - nestedNumber(frame, "output", "confidence") ?? finiteNumber(frame.confidence); - -/* -gaugeSurpriseReading mirrors the dashboard surprise strip input. -*/ -export const gaugeSurpriseReading = ( - frame: Record, -): number | null => { - const surpriseReading = - nestedNumber(frame, "output", "surprise") ?? - nestedNumber(frame, "output", "value") ?? - frame.surprise ?? - frame.snr; - - if ( - typeof surpriseReading !== "number" || - !Number.isFinite(surpriseReading) - ) { - return null; - } - - return Math.max(0, surpriseReading); -}; diff --git a/frontend/src/components/charts/confidence/surprise-subchart.ts b/frontend/src/components/charts/confidence/surprise-subchart.ts deleted file mode 100644 index 29bffb89..00000000 --- a/frontend/src/components/charts/confidence/surprise-subchart.ts +++ /dev/null @@ -1,197 +0,0 @@ -import { - EArrowHeadPosition, - EColumnMode, - EColumnYMode, - EFillPaletteMode, - EHorizontalAnchorPoint, - EVerticalAnchorPoint, - FastRectangleRenderableSeries, - type IFillPaletteProvider, - type IRenderableSeries, - LineArrowAnnotation, - NativeTextAnnotation, - NumberRange, - NumericAxis, - parseColorToUIntArgb, - type SciChartSubSurface, - XyxyDataSeries, -} from "scichart"; - -import { appTheme } from "#/components/charts/shared/theme"; - -const TRACK_HEIGHT = 8; -const SURPRISE_BAND_COLORS = [ - appTheme.VividGreen, - appTheme.VividOrange, - appTheme.VividRed, -] as const; - -class SurpriseBandPalette implements IFillPaletteProvider { - public readonly fillPaletteMode = EFillPaletteMode.SOLID; - - private readonly colors: number[]; - - constructor(colorStrings: readonly string[]) { - this.colors = colorStrings.map((color) => parseColorToUIntArgb(color)); - } - - public onAttached(_parentSeries: IRenderableSeries): void {} - - public onDetached(): void {} - - public overrideFillArgb( - _xValue: number, - _yValue: number, - index: number, - ): number | undefined { - return this.colors[index % this.colors.length]; - } -} - -const segmentEdges = ( - threshold: number, -): readonly [number, number, number, number] => [ - 0, - threshold, - threshold * 2, - threshold * 3, -]; - -const buildBandSeries = ( - wasmContext: SciChartSubSurface["webAssemblyContext2D"], - threshold: number, -): FastRectangleRenderableSeries => { - const [start, mid, upper, end] = segmentEdges(threshold); - const segments: Array<[number, number]> = [ - [start, mid], - [mid, upper], - [upper, end], - ]; - - const xValues: number[] = []; - const yValues: number[] = []; - const x1Values: number[] = []; - const y1Values: number[] = []; - - for (const [segmentStart, segmentEnd] of segments) { - if (segmentEnd <= segmentStart) { - continue; - } - - xValues.push(segmentStart); - yValues.push(0); - x1Values.push(segmentEnd); - y1Values.push(TRACK_HEIGHT); - } - - return new FastRectangleRenderableSeries(wasmContext, { - dataSeries: new XyxyDataSeries(wasmContext, { - xValues, - yValues, - x1Values, - y1Values, - containsNaN: false, - dataIsSortedInX: true, - }), - columnXMode: EColumnMode.StartEnd, - columnYMode: EColumnYMode.TopBottom, - strokeThickness: 0, - paletteProvider: new SurpriseBandPalette(SURPRISE_BAND_COLORS), - }); -}; - -export type SurpriseSubChartControls = { - update: (surprise: number, scaleMax: number, threshold: number) => void; -}; - -export const createSurpriseSubChart = ( - subChart: SciChartSubSurface, -): SurpriseSubChartControls => { - const wasmContext = subChart.webAssemblyContext2D; - - const xAxis = new NumericAxis(wasmContext, { - isVisible: false, - growBy: new NumberRange(0, 0), - visibleRange: new NumberRange(0, 6), - useNativeText: true, - }); - - const yAxis = new NumericAxis(wasmContext, { - isVisible: false, - growBy: new NumberRange(2, 2), - }); - - subChart.xAxes.add(xAxis); - subChart.yAxes.add(yAxis); - - let bandSeries = buildBandSeries(wasmContext, 2); - subChart.renderableSeries.add(bandSeries); - - const pointer = new LineArrowAnnotation({ - y1: TRACK_HEIGHT, - y2: TRACK_HEIGHT + 1, - x1: 0, - x2: 0, - isArrowHeadScalable: true, - arrowStyle: { - headLength: 6, - headWidth: 5, - headDepth: 1, - fill: appTheme.ForegroundColor, - strokeThickness: 0, - }, - stroke: appTheme.ForegroundColor, - strokeThickness: 1.5, - arrowHeadPosition: EArrowHeadPosition.Start, - }); - - const label = new NativeTextAnnotation({ - y1: TRACK_HEIGHT + 2, - x1: 0, - text: "0.00", - fontSize: 9, - textColor: appTheme.ForegroundColor, - horizontalAnchorPoint: EHorizontalAnchorPoint.Center, - verticalAnchorPoint: EVerticalAnchorPoint.Top, - }); - - subChart.annotations.add(pointer, label); - - let currentScaleMax = 6; - let currentThreshold = 2; - - const replaceBandSeries = (threshold: number): void => { - subChart.renderableSeries.remove(bandSeries); - bandSeries = buildBandSeries(wasmContext, threshold); - subChart.renderableSeries.add(bandSeries); - }; - - return { - update(surprise: number, scaleMax: number, threshold: number) { - if (subChart.isDeleted) { - return; - } - - const nextThreshold = Math.max(threshold, 0.1); - const nextScaleMax = Math.max(scaleMax, nextThreshold * 3, 1); - - if ( - nextScaleMax !== currentScaleMax || - nextThreshold !== currentThreshold - ) { - currentScaleMax = nextScaleMax; - currentThreshold = nextThreshold; - xAxis.visibleRange = new NumberRange(0, nextScaleMax); - replaceBandSeries(nextThreshold); - } - - const marker = Math.max(0, Math.min(surprise, nextScaleMax)); - - pointer.x1 = marker; - pointer.x2 = marker; - label.x1 = marker; - label.text = Math.max(0, surprise).toFixed(2); - subChart.invalidateElement(); - }, - }; -}; diff --git a/frontend/src/components/charts/fluid/SurfaceChart.tsx b/frontend/src/components/charts/fluid/SurfaceChart.tsx deleted file mode 100644 index a8fa647e..00000000 --- a/frontend/src/components/charts/fluid/SurfaceChart.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { memo } from "react"; -import { SciChartReact } from "scichart-react"; -import { appStore } from "#/collections/app"; -import { initFluidSurfaceChart } from "#/components/charts/fluid/init-fluid-surface-chart"; - -export const FluidFieldSurfaceChart = memo(function FluidFieldSurfaceChart() { - return ( - { - appStore.actions.updateFluidUpdater(result.addData); - - return () => appStore.actions.updateFluidUpdater(null); - }} - /> - ); -}); diff --git a/frontend/src/components/charts/fluid/fluid-grid-smoothing.ts b/frontend/src/components/charts/fluid/fluid-grid-smoothing.ts deleted file mode 100644 index c82301b5..00000000 --- a/frontend/src/components/charts/fluid/fluid-grid-smoothing.ts +++ /dev/null @@ -1,207 +0,0 @@ -export const cellSmoothRadius = ( - baseRadius: number, - turbulence: number, -): number => { - if (!Number.isFinite(baseRadius) || baseRadius <= 0) { - return 0; - } - - if (!Number.isFinite(turbulence) || turbulence <= 0) { - return baseRadius; - } - - return Math.max(0, Math.round(baseRadius / (1 + turbulence))); -}; - -export const anomalySNRForActivity = ( - activity: number, - clippedAt: number, -): number => { - if (!Number.isFinite(activity) || activity <= 0 || clippedAt <= 0) { - return 0; - } - - if (activity <= clippedAt) { - return 0; - } - - return (activity - clippedAt) / clippedAt; -}; - -function gaussianKernel(radius: number): number[][] { - const sigma = Math.max(radius / 2, 0.5); - const size = radius * 2 + 1; - const kernel: number[][] = []; - let weightSum = 0; - - for (let rowIndex = 0; rowIndex < size; rowIndex++) { - const row: number[] = []; - const deltaZ = rowIndex - radius; - - for (let colIndex = 0; colIndex < size; colIndex++) { - const deltaX = colIndex - radius; - const weight = Math.exp( - -(deltaX * deltaX + deltaZ * deltaZ) / (2 * sigma * sigma), - ); - - row.push(weight); - weightSum += weight; - } - - kernel.push(row); - } - - for (let rowIndex = 0; rowIndex < size; rowIndex++) { - for (let colIndex = 0; colIndex < size; colIndex++) { - kernel[rowIndex][colIndex] /= weightSum; - } - } - - return kernel; -} - -function smoothCell( - heightmap: number[][], - zIndex: number, - xIndex: number, - radius: number, -): number { - const zSize = heightmap.length; - const xSize = heightmap[0]?.length ?? 0; - const kernel = gaussianKernel(radius); - let value = 0; - let weightSum = 0; - - for (let kernelZ = 0; kernelZ < kernel.length; kernelZ++) { - for (let kernelX = 0; kernelX < kernel[kernelZ].length; kernelX++) { - const sampleZ = Math.min( - Math.max(zIndex + kernelZ - radius, 0), - zSize - 1, - ); - const sampleX = Math.min( - Math.max(xIndex + kernelX - radius, 0), - xSize - 1, - ); - const weight = kernel[kernelZ][kernelX]; - - value += heightmap[sampleZ][sampleX] * weight; - weightSum += weight; - } - } - - return weightSum > 0 ? value / weightSum : heightmap[zIndex][xIndex]; -} - -/** Spatial Gaussian smooth with per-cell radius inversely scaled by turbulence. */ -export const smoothHeightmapSpatialAdaptive = ( - heightmap: number[][], - turbulence: number[][], - baseRadius: number, -): number[][] => { - const zSize = heightmap.length; - const xSize = heightmap[0]?.length ?? 0; - - if (zSize === 0 || xSize === 0) { - return heightmap.map((row) => [...row]); - } - - const smoothed = Array.from({ length: zSize }, () => - Array.from({ length: xSize }, () => 0), - ); - - for (let zIndex = 0; zIndex < zSize; zIndex++) { - for (let xIndex = 0; xIndex < xSize; xIndex++) { - const turb = turbulence[zIndex]?.[xIndex] ?? 0; - const radius = cellSmoothRadius(baseRadius, turb); - - if (radius <= 0) { - smoothed[zIndex][xIndex] = heightmap[zIndex][xIndex]; - continue; - } - - smoothed[zIndex][xIndex] = smoothCell( - heightmap, - zIndex, - xIndex, - radius, - ); - } - } - - return smoothed; -}; - -export const emaSmoothHeightsVolumeAware = ( - raw: number[][], - volumes: number[][], - previous: number[][] | null, - alpha = 0.35, -): number[][] => { - const size = raw.length; - - if (!previous || previous.length !== size) { - return raw.map((row) => [...row]); - } - - const smoothed = previous.map((row) => [...row]); - const flatVolumes = volumes.flat().filter((value) => value > 0); - const medianVolume = - flatVolumes.length > 0 - ? flatVolumes.sort((left, right) => left - right)[ - Math.floor(flatVolumes.length / 2) - ] - : 0; - - for (let zIndex = 0; zIndex < size; zIndex++) { - for (let xIndex = 0; xIndex < size; xIndex++) { - const next = raw[zIndex][xIndex]; - const prev = smoothed[zIndex][xIndex]; - - if (!Number.isFinite(next)) { - continue; - } - - if (!Number.isFinite(prev)) { - smoothed[zIndex][xIndex] = next; - continue; - } - - const volume = volumes[zIndex]?.[xIndex] ?? 0; - const volumeScale = - medianVolume > 0 && volume > 0 ? volume / medianVolume : 0; - const cellAlpha = alpha / (1 + volumeScale); - - smoothed[zIndex][xIndex] = cellAlpha * next + (1 - cellAlpha) * prev; - } - } - - return smoothed; -}; - -export const peakAnomalyIntensity = (anomalySNR: number[][]): number => { - let peak = 0; - - for (const row of anomalySNR) { - for (const value of row) { - if (Number.isFinite(value)) { - peak = Math.max(peak, value); - } - } - } - - return peak; -}; - -export const visualStressFromAnomaly = ( - baseHighlight: number, - baseHardness: number, - anomalySNR: number[][], -): { highlight: number; cellHardnessFactor: number } => { - const peak = peakAnomalyIntensity(anomalySNR); - const scale = Math.min(2, peak); - - return { - highlight: baseHighlight * (1 + scale), - cellHardnessFactor: baseHardness * (1 + scale * 0.5), - }; -}; diff --git a/frontend/src/components/charts/fluid/fluid-grid.test.ts b/frontend/src/components/charts/fluid/fluid-grid.test.ts deleted file mode 100644 index 7b602cae..00000000 --- a/frontend/src/components/charts/fluid/fluid-grid.test.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { describe, expect, it } from "vitest"; - -import { - buildFluidGrid, - projectFluidGridToHeightmap, - resetFluidHeightSmoothing, -} from "#/components/charts/fluid/fluid-grid"; - -const sampleRows = () => [ - { - symbol: "BTC/EUR", - change_pct: -2.5, - vol: 120, - div: 0.35, - vort: 0.8, - turb: 0.12, - visc: 0.9, - re: 0.8, - }, - { - symbol: "ETH/EUR", - change_pct: 1.2, - vol: 80, - div: -0.2, - vort: 0.4, - turb: 0.05, - visc: 0.85, - re: 0.4, - }, - { - symbol: "SOL/EUR", - change_pct: 4.8, - vol: 40, - div: 0.1, - vort: 1.2, - turb: 0.2, - visc: 0.7, - re: 1.2, - }, -]; - -describe("buildFluidGrid", () => { - it("produces non-flat heights for active symbols", () => { - resetFluidHeightSmoothing(); - - const grid = buildFluidGrid(sampleRows()); - const values = grid.heights - .flat() - .filter((value) => Number.isFinite(value)); - - expect(values.length).toBeGreaterThan(0); - expect(Math.max(...values)).toBeGreaterThan(Math.min(...values)); - }); - - it("projects to a heightmap with visible vertical span", () => { - resetFluidHeightSmoothing(); - - const grid = buildFluidGrid(sampleRows()); - const projected = projectFluidGridToHeightmap(grid, 32, 32, -0.3, 0.5); - const displayValues = projected.display.flat(); - - expect(Math.max(...displayValues)).toBeGreaterThan( - Math.min(...displayValues), - ); - }); -}); diff --git a/frontend/src/components/charts/fluid/fluid-grid.ts b/frontend/src/components/charts/fluid/fluid-grid.ts deleted file mode 100644 index 25062d78..00000000 --- a/frontend/src/components/charts/fluid/fluid-grid.ts +++ /dev/null @@ -1,654 +0,0 @@ -import { - anomalySNRForActivity, - emaSmoothHeightsVolumeAware, - smoothHeightmapSpatialAdaptive, -} from "#/components/charts/fluid/fluid-grid-smoothing"; - -export const FLUID_GRID_SIZE = 32; -export const FLUID_HEIGHT_EMA_ALPHA = 0.35; - -let smoothedHeights: number[][] | null = null; -let smoothedVolumes: number[][] | null = null; - -const rowNumber = (row: unknown, key: string): number => { - if (typeof row !== "object" || row === null) { - return Number.NaN; - } - - const value = (row as Record)[key]; - - return typeof value === "number" && Number.isFinite(value) - ? value - : Number.NaN; -}; - -const rowString = (row: unknown, key: string): string => { - if (typeof row !== "object" || row === null) { - return ""; - } - - const value = (row as Record)[key]; - - return typeof value === "string" ? value : ""; -}; - -export type FluidGrid = { - heights: number[][]; - turbulence: number[][]; - volumes: number[][]; - anomalySNR: number[][]; - min: number; - max: number; - filledCells: number; - outliers: FluidScaleSummary; -}; - -export type FluidScaleSummary = { - clippedCount: number; - clippedAt: number; - rawMax: number; - rawMaxSymbol?: string; - displayMax: number; -}; - -/** Map backend grid payload into chart-ready heights. */ -export function gridFromPayload(payload: { - size?: number; - heights: number[][]; - min: number; - max: number; - filled_cells: number; - outliers: { - clipped_count: number; - clipped_at: number; - raw_max: number; - raw_max_symbol?: string; - display_max: number; - }; -}): FluidGrid { - const fallback = Number.isFinite(payload.min) ? payload.min : 0; - const heights = sanitizeHeights(payload.heights, fallback); - const size = heights.length; - - return { - heights, - turbulence: emptyGrid(size), - volumes: emptyGrid(size), - anomalySNR: emptyGrid(size), - min: payload.min, - max: payload.max, - filledCells: payload.filled_cells, - outliers: { - clippedCount: payload.outliers.clipped_count, - clippedAt: payload.outliers.clipped_at, - rawMax: payload.outliers.raw_max, - rawMaxSymbol: payload.outliers.raw_max_symbol, - displayMax: payload.outliers.display_max, - }, - }; -} - -function sanitizeHeights(heights: number[][], fallback: number): number[][] { - return heights.map((row) => - row.map((value) => (Number.isFinite(value) ? value : fallback)), - ); -} - -function emptyGrid(size: number): number[][] { - return Array.from({ length: size }, () => - Array.from({ length: size }, () => 0), - ); -} - -function percentileRank(value: number, sorted: number[]): number { - if (sorted.length === 0) return 0.5; - let below = 0; - for (const v of sorted) { - if (v < value) below++; - } - return below / sorted.length; -} - -function median(values: number[]): number { - if (values.length === 0) return 0; - const sorted = [...values].sort((a, b) => a - b); - const mid = Math.floor(sorted.length / 2); - if (sorted.length % 2 === 0) { - return (sorted[mid - 1] + sorted[mid]) / 2; - } - return sorted[mid]; -} - -function medianPositive(values: number[]): number { - const positive = values.filter((value) => value > 0); - - if (positive.length === 0) { - return Number.NaN; - } - - return median(positive); -} - -function quantile(sorted: number[], q: number): number { - if (sorted.length === 0) return 0; - const pos = (sorted.length - 1) * q; - const base = Math.floor(pos); - const rest = pos - base; - const next = sorted[base + 1]; - if (next === undefined) return sorted[base]; - return sorted[base] + rest * (next - sorted[base]); -} - -function binIndex(rank: number, size: number): number { - const idx = Math.floor(rank * size); - if (idx < 0) return 0; - if (idx >= size) return size - 1; - return idx; -} - -function smoothEmptyCells(grid: number[][], fallback: number): number { - const size = grid.length; - let filled = 0; - for (let z = 0; z < size; z++) { - for (let x = 0; x < size; x++) { - if (Number.isFinite(grid[z][x])) filled++; - } - } - if (filled === 0) { - for (let z = 0; z < size; z++) { - for (let x = 0; x < size; x++) { - grid[z][x] = fallback; - } - } - return 0; - } - - for (let pass = 0; pass < Math.max(3, size); pass++) { - for (let z = 0; z < size; z++) { - for (let x = 0; x < size; x++) { - if (Number.isFinite(grid[z][x])) continue; - let sum = 0; - let count = 0; - for (let dz = -1; dz <= 1; dz++) { - for (let dx = -1; dx <= 1; dx++) { - if (dz === 0 && dx === 0) continue; - const nz = z + dz; - const nx = x + dx; - if (nz < 0 || nz >= size || nx < 0 || nx >= size) continue; - const v = grid[nz][nx]; - if (!Number.isFinite(v)) continue; - sum += v; - count++; - } - } - if (count > 0) { - grid[z][x] = sum / count; - } - } - } - } - - for (let z = 0; z < size; z++) { - for (let x = 0; x < size; x++) { - if (Number.isFinite(grid[z][x])) { - continue; - } - - grid[z][x] = fallback; - } - } - - return filled; -} - -function displayActivity(value: number, clippedAt: number): number { - const clamped = Math.min(Math.max(value, 0), clippedAt); - return Math.log1p(clamped); -} - -function emaSmoothHeights(raw: number[][], volumes: number[][]): number[][] { - const next = emaSmoothHeightsVolumeAware( - raw, - volumes, - smoothedHeights, - FLUID_HEIGHT_EMA_ALPHA, - ); - - smoothedHeights = next; - smoothedVolumes = volumes.map((row) => [...row]); - - return smoothedHeights; -} - -export function resetFluidHeightSmoothing() { - smoothedHeights = null; - smoothedVolumes = null; -} - -/** Fractional bilinear sample on a square height grid. */ -export function bilinearSampleGrid( - grid: number[][], - zIndex: number, - xIndex: number, -): number { - const zSize = grid.length; - - if (zSize === 0) { - return 0; - } - - const xSize = grid[0]?.length ?? 0; - - if (xSize === 0) { - return 0; - } - - const zClamped = Math.min(Math.max(zIndex, 0), zSize - 1); - const xClamped = Math.min(Math.max(xIndex, 0), xSize - 1); - const zFloor = Math.floor(zClamped); - const xFloor = Math.floor(xClamped); - const zFrac = zClamped - zFloor; - const xFrac = xClamped - xFloor; - const zCeil = Math.min(zFloor + 1, zSize - 1); - const xCeil = Math.min(xFloor + 1, xSize - 1); - - const topLeft = grid[zFloor]?.[xFloor] ?? 0; - const topRight = grid[zFloor]?.[xCeil] ?? 0; - const bottomLeft = grid[zCeil]?.[xFloor] ?? 0; - const bottomRight = grid[zCeil]?.[xCeil] ?? 0; - const top = topLeft + (topRight - topLeft) * xFrac; - const bottom = bottomLeft + (bottomRight - bottomLeft) * xFrac; - - return top + (bottom - top) * zFrac; -} - -function gaussianKernel(radius: number): number[][] { - const sigma = Math.max(radius / 2, 0.5); - const size = radius * 2 + 1; - const kernel: number[][] = []; - let weightSum = 0; - - for (let rowIndex = 0; rowIndex < size; rowIndex++) { - const row: number[] = []; - const deltaZ = rowIndex - radius; - - for (let colIndex = 0; colIndex < size; colIndex++) { - const deltaX = colIndex - radius; - const weight = Math.exp( - -(deltaX * deltaX + deltaZ * deltaZ) / (2 * sigma * sigma), - ); - - row.push(weight); - weightSum += weight; - } - - kernel.push(row); - } - - for (let rowIndex = 0; rowIndex < size; rowIndex++) { - for (let colIndex = 0; colIndex < size; colIndex++) { - kernel[rowIndex][colIndex] /= weightSum; - } - } - - return kernel; -} - -/** Spatial Gaussian smooth; radius scales with grid dimensions when omitted. */ -export function smoothHeightmapSpatial( - heightmap: number[][], - radius = spatialSmoothRadius(heightmap.length, heightmap[0]?.length ?? 0), -): number[][] { - const zSize = heightmap.length; - const xSize = heightmap[0]?.length ?? 0; - - if (zSize === 0 || xSize === 0 || radius <= 0) { - return heightmap.map((row) => [...row]); - } - - const kernel = gaussianKernel(radius); - const smoothed = Array.from({ length: zSize }, () => - Array.from({ length: xSize }, () => 0), - ); - - for (let zIndex = 0; zIndex < zSize; zIndex++) { - for (let xIndex = 0; xIndex < xSize; xIndex++) { - let value = 0; - let weightSum = 0; - - for (let kernelZ = 0; kernelZ < kernel.length; kernelZ++) { - for (let kernelX = 0; kernelX < kernel[kernelZ].length; kernelX++) { - const sampleZ = Math.min( - Math.max(zIndex + kernelZ - radius, 0), - zSize - 1, - ); - const sampleX = Math.min( - Math.max(xIndex + kernelX - radius, 0), - xSize - 1, - ); - const weight = kernel[kernelZ][kernelX]; - - value += heightmap[sampleZ][sampleX] * weight; - weightSum += weight; - } - } - - smoothed[zIndex][xIndex] = weightSum > 0 ? value / weightSum : 0; - } - } - - return smoothed; -} - -export function spatialSmoothRadius(gridZ: number, gridX: number): number { - return Math.max(1, Math.round(Math.min(gridZ, gridX) / 16)); -} - -/** Blend smoothed geometry toward raw peaks so hotspots stay visible in color. */ -export function blendHeightmapTowardPeaks( - smoothed: number[][], - raw: number[][], - peakBlend: number, -): number[][] { - const zSize = smoothed.length; - const xSize = smoothed[0]?.length ?? 0; - const blend = Math.min(Math.max(peakBlend, 0), 1); - const blended = Array.from({ length: zSize }, () => - Array.from({ length: xSize }, () => 0), - ); - - for (let zIndex = 0; zIndex < zSize; zIndex++) { - for (let xIndex = 0; xIndex < xSize; xIndex++) { - const smoothValue = smoothed[zIndex][xIndex]; - const rawValue = raw[zIndex]?.[xIndex] ?? smoothValue; - const peakDelta = Math.max(0, rawValue - smoothValue); - - blended[zIndex][xIndex] = smoothValue + peakDelta * blend; - } - } - - return blended; -} - -export function projectFluidGridToHeightmap( - grid: FluidGrid, - targetZ: number, - targetX: number, - yMin: number, - yMax: number, -): { raw: number[][]; display: number[][]; anomalySNR: number[][] } { - const raw = Array.from({ length: targetZ }, () => - Array.from({ length: targetX }, () => yMin), - ); - const turbulence = Array.from({ length: targetZ }, () => - Array.from({ length: targetX }, () => 0), - ); - const anomalySNR = Array.from({ length: targetZ }, () => - Array.from({ length: targetX }, () => 0), - ); - const srcSize = grid.heights.length; - const span = grid.max - grid.min; - const useSpan = Number.isFinite(span) && span > 1e-6; - const scaleMax = useSpan - ? span - : Math.max(grid.outliers.displayMax, grid.max, 0.05); - const base = useSpan ? grid.min : 0; - const ySpan = yMax - yMin; - - if (srcSize === 0) { - return { raw, display: raw, anomalySNR }; - } - - for (let zIndex = 0; zIndex < targetZ; zIndex++) { - const srcZ = (zIndex * (srcSize - 1)) / Math.max(targetZ - 1, 1); - - for (let xIndex = 0; xIndex < targetX; xIndex++) { - const rowLen = grid.heights[Math.round(srcZ)]?.length ?? 0; - - if (rowLen === 0) { - continue; - } - - const srcX = (xIndex * (rowLen - 1)) / Math.max(targetX - 1, 1); - const sample = bilinearSampleGrid(grid.heights, srcZ, srcX); - const turbSample = bilinearSampleGrid(grid.turbulence, srcZ, srcX); - const snrSample = bilinearSampleGrid(grid.anomalySNR, srcZ, srcX); - - turbulence[zIndex][xIndex] = turbSample; - anomalySNR[zIndex][xIndex] = snrSample; - - if (!Number.isFinite(sample) || sample <= 0) { - continue; - } - - const normalized = useSpan - ? (sample - base) / scaleMax - : sample / scaleMax; - - raw[zIndex][xIndex] = yMin + normalized * ySpan; - } - } - - const radius = spatialSmoothRadius(targetZ, targetX); - const smoothed = smoothHeightmapSpatialAdaptive(raw, turbulence, radius); - const peakBlend = Math.min(0.5, 0.2 + radius / Math.max(targetZ, targetX, 1)); - const display = blendHeightmapTowardPeaks(smoothed, raw, peakBlend); - - return { raw, display, anomalySNR }; -} - -function cellTurbulence(row: unknown, clippedAt: number): number { - const re = Math.abs(rowNumber(row, "re")); - const turb = Math.abs(rowNumber(row, "turb")); - - if (re <= 0 && turb <= 0) { - return 0; - } - - const activity = Math.max(re, turb); - - if (clippedAt <= 0) { - return activity; - } - - return activity / clippedAt; -} - -function fieldActivity(row: unknown): number { - return Math.max( - Math.abs(rowNumber(row, "re")), - Math.abs(rowNumber(row, "div")), - Math.abs(rowNumber(row, "vort")), - Math.abs(rowNumber(row, "turb")), - ); -} - -export function summarizeFluidScaling(rows: unknown[]): FluidScaleSummary { - const finiteRows = rows.filter( - (row) => - Number.isFinite(rowNumber(row, "re")) && - Number.isFinite(rowNumber(row, "div")) && - Number.isFinite(rowNumber(row, "vort")) && - Number.isFinite(rowNumber(row, "turb")), - ); - if (finiteRows.length === 0) { - return { clippedCount: 0, clippedAt: 0, rawMax: 0, displayMax: 0 }; - } - - const sortedActivity = finiteRows - .map((row) => fieldActivity(row)) - .filter((value) => value > 0) - .sort((a, b) => a - b); - if (sortedActivity.length === 0) { - return { clippedCount: 0, clippedAt: 0, rawMax: 0, displayMax: 0 }; - } - - const clippedAt = Math.max(quantile(sortedActivity, 0.95), 0); - let rawMax = Number.NEGATIVE_INFINITY; - let rawMaxSymbol: string | undefined; - let clippedCount = 0; - - for (const row of finiteRows) { - const activity = fieldActivity(row); - - if (activity > rawMax) { - rawMax = activity; - rawMaxSymbol = rowString(row, "symbol"); - } - if (activity > clippedAt) clippedCount++; - } - - return { - clippedCount, - clippedAt, - rawMax, - rawMaxSymbol, - displayMax: displayActivity(rawMax, clippedAt), - }; -} - -function displayHeight(row: unknown, clippedAt: number): number { - return displayActivity(fieldActivity(row), clippedAt); -} - -/** Bin symbols by change% × vol rank; height = median clipped fluid activity. */ -export function buildFluidGrid( - rows: unknown[], - size = FLUID_GRID_SIZE, -): FluidGrid { - const heights = Array.from({ length: size }, () => - Array.from({ length: size }, () => Number.NaN), - ); - const turbulence = emptyGrid(size); - const volumes = emptyGrid(size); - const anomalySNR = emptyGrid(size); - const cells = Array.from({ length: size }, () => - Array.from({ length: size }, () => [] as number[]), - ); - const turbCells = Array.from({ length: size }, () => - Array.from({ length: size }, () => [] as number[]), - ); - const volumeCells = Array.from({ length: size }, () => - Array.from({ length: size }, () => [] as number[]), - ); - const snrCells = Array.from({ length: size }, () => - Array.from({ length: size }, () => [] as number[]), - ); - - if (rows.length === 0) { - return { - heights, - turbulence, - volumes, - anomalySNR, - min: 0, - max: 1, - filledCells: 0, - outliers: summarizeFluidScaling(rows), - }; - } - - const finiteRows = rows.filter( - (row) => - Number.isFinite(rowNumber(row, "change_pct")) && - Number.isFinite(rowNumber(row, "vol")) && - Number.isFinite(rowNumber(row, "re")) && - Number.isFinite(rowNumber(row, "div")) && - Number.isFinite(rowNumber(row, "vort")) && - Number.isFinite(rowNumber(row, "turb")), - ); - const outliers = summarizeFluidScaling(finiteRows); - if (finiteRows.length === 0) { - return { - heights, - turbulence, - volumes, - anomalySNR, - min: 0, - max: 1, - filledCells: 0, - outliers, - }; - } - - const changes = finiteRows - .map((row) => rowNumber(row, "change_pct")) - .sort((left, right) => left - right); - const vols = finiteRows - .map((row) => rowNumber(row, "vol")) - .sort((left, right) => left - right); - const displayValues = finiteRows.map((row) => - displayHeight(row, outliers.clippedAt), - ); - const fallback = median(displayValues); - - for (const row of finiteRows) { - if (fieldActivity(row) <= 0) { - continue; - } - - const changePct = rowNumber(row, "change_pct"); - const vol = rowNumber(row, "vol"); - const x = binIndex(percentileRank(changePct, changes), size); - const z = binIndex(percentileRank(vol, vols), size); - const activity = fieldActivity(row); - - cells[z][x].push(displayHeight(row, outliers.clippedAt)); - turbCells[z][x].push(cellTurbulence(row, outliers.clippedAt)); - volumeCells[z][x].push(vol); - snrCells[z][x].push(anomalySNRForActivity(activity, outliers.clippedAt)); - } - - let min = Number.POSITIVE_INFINITY; - let max = Number.NEGATIVE_INFINITY; - for (let z = 0; z < size; z++) { - for (let x = 0; x < size; x++) { - const values = cells[z][x]; - const y = values.length > 0 ? medianPositive(values) : Number.NaN; - heights[z][x] = y; - turbulence[z][x] = - turbCells[z][x].length > 0 ? medianPositive(turbCells[z][x]) : 0; - volumes[z][x] = - volumeCells[z][x].length > 0 ? medianPositive(volumeCells[z][x]) : 0; - anomalySNR[z][x] = - snrCells[z][x].length > 0 ? medianPositive(snrCells[z][x]) : 0; - if (Number.isFinite(y)) { - min = Math.min(min, y); - max = Math.max(max, y); - } - } - } - - const filledCells = smoothEmptyCells(heights, 0); - const smoothed = emaSmoothHeights(heights, volumes); - - for (let z = 0; z < size; z++) { - for (let x = 0; x < size; x++) { - heights[z][x] = smoothed[z][x]; - } - } - - if (!Number.isFinite(min) || !Number.isFinite(max) || min === max) { - min = fallback - 0.5; - max = fallback + 0.5; - } - - for (let z = 0; z < size; z++) { - for (let x = 0; x < size; x++) { - if (!Number.isFinite(heights[z][x])) { - heights[z][x] = 0; - } - } - } - - return { - heights, - turbulence, - volumes, - anomalySNR, - min, - max, - filledCells, - outliers, - }; -} diff --git a/frontend/src/components/charts/fluid/init-fluid-surface-chart.ts b/frontend/src/components/charts/fluid/init-fluid-surface-chart.ts deleted file mode 100644 index f0354a8c..00000000 --- a/frontend/src/components/charts/fluid/init-fluid-surface-chart.ts +++ /dev/null @@ -1,150 +0,0 @@ -import { - CameraController, - EDrawMeshAs, - GradientColorPalette, - NumberRange, - NumericAxis3D, - SciChart3DSurface, - SurfaceMeshRenderableSeries3D, - UniformGridDataSeries3D, - Vector3, - zeroArray2D, -} from "scichart"; -import { - buildFluidGrid, - FLUID_GRID_SIZE, - projectFluidGridToHeightmap, - resetFluidHeightSmoothing, -} from "#/components/charts/fluid/fluid-grid"; -import { appTheme } from "#/components/charts/fluid/theme"; -import { ensureSciChartWasm } from "#/lib/utils"; - -const FLUID_SURFACE_Y_MIN = -0.3; -const FLUID_SURFACE_Y_MAX = 0.5; - -export const initFluidSurfaceChart = async ( - rootElement: string | HTMLDivElement, -) => { - resetFluidHeightSmoothing(); - - await ensureSciChartWasm(); - - const { sciChart3DSurface, wasmContext } = await SciChart3DSurface.create( - rootElement, - { - theme: appTheme.SciChartJsTheme, - freezeWhenOutOfView: true, - }, - ); - - sciChart3DSurface.camera = new CameraController(wasmContext, { - position: new Vector3(-150, 200, 150), - target: new Vector3(0, 50, 0), - }); - sciChart3DSurface.worldDimensions = new Vector3(200, 100, 200); - - sciChart3DSurface.xAxis = new NumericAxis3D(wasmContext, { - axisTitle: "X Axis", - }); - sciChart3DSurface.yAxis = new NumericAxis3D(wasmContext, { - axisTitle: "Y Axis", - visibleRange: new NumberRange(FLUID_SURFACE_Y_MIN, FLUID_SURFACE_Y_MAX), - }); - sciChart3DSurface.zAxis = new NumericAxis3D(wasmContext, { - axisTitle: "Z Axis", - }); - - const gridSize = FLUID_GRID_SIZE; - const heightmapArray = zeroArray2D([gridSize, gridSize]); - - const dataSeries = new UniformGridDataSeries3D(wasmContext, { - yValues: heightmapArray, - xStep: 1, - zStep: 1, - dataSeriesName: "Uniform Surface Mesh", - }); - - const colorMap = new GradientColorPalette(wasmContext, { - gradientStops: [ - { offset: 1, color: appTheme.VividPink }, - { offset: 0.9, color: appTheme.VividOrange }, - { offset: 0.7, color: appTheme.MutedRed }, - { offset: 0.5, color: appTheme.VividGreen }, - { offset: 0.3, color: appTheme.VividSkyBlue }, - { offset: 0.15, color: appTheme.Indigo }, - { offset: 0, color: appTheme.DarkIndigo }, - ], - }); - - const series = new SurfaceMeshRenderableSeries3D(wasmContext, { - dataSeries, - minimum: -0.3, - maximum: 0.5, - opacity: 0.9, - cellHardnessFactor: 1.0, - shininess: 0, - lightingFactor: 0.0, - highlight: 1.0, - stroke: appTheme.VividBlue, - strokeThickness: 2.0, - contourStroke: appTheme.VividBlue, - contourInterval: 2, - contourOffset: 0, - contourStrokeThickness: 2, - drawSkirt: false, - drawMeshAs: EDrawMeshAs.SOLID_WITH_CONTOURS, - meshColorPalette: colorMap, - isVisible: true, - }); - - sciChart3DSurface.renderableSeries.add(series); - - const addData = (frame: Record) => { - const symbols = frame.symbols; - - if (!Array.isArray(symbols) || symbols.length === 0) { - return; - } - - const grid = buildFluidGrid(symbols); - const projected = projectFluidGridToHeightmap( - grid, - gridSize, - gridSize, - FLUID_SURFACE_Y_MIN, - FLUID_SURFACE_Y_MAX, - ); - const heights = projected.display; - - for (let zIndex = 0; zIndex < gridSize; zIndex++) { - const heightRow = heights[zIndex]; - - if (!heightRow) { - continue; - } - - for (let xIndex = 0; xIndex < gridSize; xIndex++) { - const value = heightRow[xIndex]; - const finite = - typeof value === "number" && Number.isFinite(value) ? value : 0; - - heightmapArray[zIndex][xIndex] = finite; - } - } - - dataSeries.setYValues(heightmapArray); - series.minimum = FLUID_SURFACE_Y_MIN; - series.maximum = FLUID_SURFACE_Y_MAX; - sciChart3DSurface.yAxis.visibleRange = new NumberRange( - FLUID_SURFACE_Y_MIN, - FLUID_SURFACE_Y_MAX, - ); - sciChart3DSurface.invalidateElement(); - }; - - return { - sciChartSurface: sciChart3DSurface, - wasmContext, - addData, - }; -}; diff --git a/frontend/src/components/charts/fluid/theme.ts b/frontend/src/components/charts/fluid/theme.ts deleted file mode 100644 index d6ff159b..00000000 --- a/frontend/src/components/charts/fluid/theme.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { type IThemeProvider, SciChartJsNavyTheme } from "scichart"; - -const getCssColor = (cssVar: string, fallback: string): string => { - if (typeof document === "undefined") { - return fallback; - } - const cssValue = getComputedStyle(document.documentElement) - .getPropertyValue(cssVar) - .trim(); - return cssValue || fallback; -}; - -type TRgbColor = { r: number; g: number; b: number }; - -const parseCssColorToRgb = (color: string): TRgbColor | undefined => { - const trimmed = color.trim(); - - if (trimmed.startsWith("#")) { - let hex = trimmed.slice(1); - if (hex.length === 3 || hex.length === 4) { - hex = hex - .slice(0, 3) - .split("") - .map((channel) => channel + channel) - .join(""); - } else if (hex.length === 6 || hex.length === 8) { - hex = hex.slice(0, 6); - } else { - return undefined; - } - - if (!/^[0-9a-fA-F]{6}$/.test(hex)) { - return undefined; - } - - return { - r: Number.parseInt(hex.slice(0, 2), 16), - g: Number.parseInt(hex.slice(2, 4), 16), - b: Number.parseInt(hex.slice(4, 6), 16), - }; - } - - const rgbMatch = trimmed.match(/^rgba?\((.+)\)$/i); - if (!rgbMatch) { - return undefined; - } - - const channels = rgbMatch[1] - .split(",") - .slice(0, 3) - .map((channel) => Number.parseFloat(channel.trim())); - - if ( - channels.length !== 3 || - channels.some((channel) => !Number.isFinite(channel)) - ) { - return undefined; - } - - const clamp = (value: number) => Math.max(0, Math.min(255, value)); - - return { - r: clamp(channels[0]), - g: clamp(channels[1]), - b: clamp(channels[2]), - }; -}; - -const getPerceivedBrightness = (color: string): number | undefined => { - const rgb = parseCssColorToRgb(color); - if (!rgb) return undefined; - - // WCAG-adjacent perceptual weighting for quick dark/light detection. - return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000; -}; - -export interface AppThemeBase { - SciChartJsTheme: IThemeProvider; - - // general colors - isDark: boolean; - ForegroundColor: string; - Background: string; - - // Series colors - VividSkyBlue: string; - VividPink: string; - VividTeal: string; - VividOrange: string; - VividBlue: string; - VividPurple: string; - VividGreen: string; - VividRed: string; - - MutedSkyBlue: string; - MutedPink: string; - MutedTeal: string; - MutedOrange: string; - MutedBlue: string; - MutedPurple: string; - MutedRed: string; - - PaleSkyBlue: string; - PalePink: string; - PaleTeal: string; - PaleOrange: string; - PaleBlue: string; - PalePurple: string; -} - -export class SciChart2022AppTheme implements AppThemeBase { - SciChartJsTheme = new SciChartJsNavyTheme(); - - // Dynamic colors - get isDark() { - const brightness = getPerceivedBrightness(this.Background); - return brightness === undefined || brightness < 128; - } - get TextColor() { - return this.ForegroundColor; - } - get ForegroundColor() { - return getCssColor("--text", "#F5F5F5"); - } - get Background() { - return getCssColor("--bg-chart", this.SciChartJsTheme.sciChartBackground); - } - - // Series colors - VividSkyBlue = "#50C7E0"; - VividPink = "#EC0F6C"; - VividTeal = "#30BC9A"; - VividOrange = "#F48420"; - VividBlue = "#364BA0"; - VividPurple = "#882B91"; - VividGreen = "#67BDAF"; - VividRed = "#C52E60"; - - DarkIndigo = "#14233C"; - Indigo = "#264B93"; - - MutedSkyBlue = "#83D2F5"; - MutedPink = "#DF69A8"; - MutedTeal = "#7BCAAB"; - MutedOrange = "#E7C565"; - MutedBlue = "#537ABD"; - MutedPurple = "#A16DAE"; - MutedRed = "#DC7969"; - - PaleSkyBlue = "#E4F5FC"; - PalePink = "#EEB3D2"; - PaleTeal = "#B9E0D4"; - PaleOrange = "#F1CFB5"; - PaleBlue = "#B5BEDF"; - PalePurple = "#CFB4D5"; -} - -export const appTheme = new SciChart2022AppTheme(); diff --git a/frontend/src/components/charts/manifold/ManifoldSurfaceChart.tsx b/frontend/src/components/charts/manifold/ManifoldSurfaceChart.tsx deleted file mode 100644 index 81d31f43..00000000 --- a/frontend/src/components/charts/manifold/ManifoldSurfaceChart.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import { memo } from "react"; -import { SciChartReact } from "scichart-react"; -import { appStore } from "#/collections/app"; -import { initManifoldSurfaceChart } from "#/components/charts/manifold/init-manifold-surface-chart"; - -export const ManifoldSurfaceChart = memo(function ManifoldSurfaceChart() { - return ( - { - appStore.actions.updateManifoldUpdater(result.addData); - - return () => appStore.actions.updateManifoldUpdater(null); - }} - /> - ); -}); diff --git a/frontend/src/components/charts/manifold/init-manifold-surface-chart.ts b/frontend/src/components/charts/manifold/init-manifold-surface-chart.ts deleted file mode 100644 index ff87595b..00000000 --- a/frontend/src/components/charts/manifold/init-manifold-surface-chart.ts +++ /dev/null @@ -1,363 +0,0 @@ -import { - CameraController, - EDrawMeshAs, - GradientColorPalette, - NumberRange, - NumericAxis3D, - ScatterRenderableSeries3D, - SciChart3DSurface, - SpherePointMarker3D, - SurfaceMeshRenderableSeries3D, - UniformGridDataSeries3D, - Vector3, - XyzDataSeries3D, - zeroArray2D, -} from "scichart"; -import { appTheme } from "#/components/charts/fluid/theme"; -import { - manifoldCameraFrame, - manifoldHeightExtent, -} from "#/components/charts/manifold/manifold-camera"; -import { - isDegenerateHeightmap, - projectManifoldHeightmap, -} from "#/components/charts/manifold/manifold-grid"; -import { ensureSciChartWasm } from "#/lib/utils"; - -const MANIFOLD_GRID_X = 32; -const MANIFOLD_GRID_Z = 16; -const MANIFOLD_AXIS_LABEL_SIZE = 9; -const MANIFOLD_AXIS_TITLE_SIZE = 10; -const MANIFOLD_SYMBOL_MARKER_SIZE = 0.35; -const MANIFOLD_WHALE_MARKER_SIZE = 0.55; - -const rowNumber = (row: unknown, key: string): number => { - if (typeof row !== "object" || row === null) { - return Number.NaN; - } - - const value = (row as Record)[key]; - - return typeof value === "number" && Number.isFinite(value) - ? value - : Number.NaN; -}; - -const fitManifoldCamera = ( - sciChart3DSurface: SciChart3DSurface, - wasmContext: Awaited< - ReturnType - >["wasmContext"], - gridX: number, - gridZ: number, - yMin: number, - yMax: number, -) => { - const frame = manifoldCameraFrame(gridX, gridZ, yMax - yMin); - - sciChart3DSurface.camera = new CameraController(wasmContext, { - position: new Vector3( - frame.centerX - frame.orbit * 0.82, - frame.orbit * 0.62, - frame.centerZ + frame.orbit * 0.82, - ), - target: new Vector3(frame.centerX, frame.yCenter, frame.centerZ), - }); - sciChart3DSurface.worldDimensions = new Vector3( - gridX, - frame.worldHeight, - gridZ, - ); - sciChart3DSurface.xAxis.visibleRange = new NumberRange( - 0, - Math.max(gridX - 1, 1), - ); - sciChart3DSurface.zAxis.visibleRange = new NumberRange( - 0, - Math.max(gridZ - 1, 1), - ); - sciChart3DSurface.yAxis.visibleRange = new NumberRange(yMin, yMax); -}; - -const sampleSurfaceHeight = ( - heights: number[][], - chartX: number, - chartZ: number, -): number | null => { - const gridZ = heights.length; - const gridX = gridZ > 0 ? (heights[0]?.length ?? 0) : 0; - - if (gridX === 0 || gridZ === 0) { - return null; - } - - const xIndex = Math.min(Math.max(Math.round(chartX), 0), gridX - 1); - const zIndex = Math.min(Math.max(Math.round(chartZ), 0), gridZ - 1); - const value = heights[zIndex]?.[xIndex]; - - if (typeof value !== "number" || !Number.isFinite(value)) { - return null; - } - - return value; -}; - -const updateCarrierSeries = ( - series: ScatterRenderableSeries3D, - carriers: unknown[], - spacing: number, - heights: number[][], -) => { - const dataSeries = series.dataSeries as XyzDataSeries3D; - - dataSeries.clear(); - - for (const carrier of carriers) { - const chartX = rowNumber(carrier, "x") / spacing; - const chartZ = rowNumber(carrier, "z") / spacing; - const chartY = sampleSurfaceHeight(heights, chartX, chartZ); - - if (chartY === null) { - continue; - } - - dataSeries.append(chartX, chartY, chartZ); - } - - series.isVisible = dataSeries.count() > 0; -}; - -export const initManifoldSurfaceChart = async ( - rootElement: string | HTMLDivElement, -) => { - await ensureSciChartWasm(); - - const { sciChart3DSurface, wasmContext } = await SciChart3DSurface.create( - rootElement, - { - theme: appTheme.SciChartJsTheme, - freezeWhenOutOfView: false, - }, - ); - - const axisLabelStyle = { fontSize: MANIFOLD_AXIS_LABEL_SIZE }; - const axisTitleStyle = { fontSize: MANIFOLD_AXIS_TITLE_SIZE }; - - sciChart3DSurface.xAxis = new NumericAxis3D(wasmContext, { - axisTitle: "Depth (price ticks)", - labelStyle: axisLabelStyle, - axisTitleStyle: axisTitleStyle, - }); - sciChart3DSurface.yAxis = new NumericAxis3D(wasmContext, { - axisTitle: "Density ρ", - labelStyle: axisLabelStyle, - axisTitleStyle: axisTitleStyle, - }); - sciChart3DSurface.zAxis = new NumericAxis3D(wasmContext, { - axisTitle: "Cross-asset rank", - labelStyle: axisLabelStyle, - axisTitleStyle: axisTitleStyle, - }); - - let gridX = MANIFOLD_GRID_X; - let gridZ = MANIFOLD_GRID_Z; - let surfaceYMin = 0; - let surfaceYMax = 1; - let cameraFitted = false; - let heightmapArray = zeroArray2D([gridZ, gridX]); - - let dataSeries = new UniformGridDataSeries3D(wasmContext, { - yValues: heightmapArray, - xStep: 1, - zStep: 1, - dataSeriesName: "Manifold density projection", - }); - - const colorMap = new GradientColorPalette(wasmContext, { - gradientStops: [ - { offset: 1, color: appTheme.VividPink }, - { offset: 0.75, color: appTheme.VividOrange }, - { offset: 0.5, color: appTheme.VividGreen }, - { offset: 0.25, color: appTheme.VividSkyBlue }, - { offset: 0, color: appTheme.DarkIndigo }, - ], - }); - - const series = new SurfaceMeshRenderableSeries3D(wasmContext, { - dataSeries, - minimum: surfaceYMin, - maximum: surfaceYMax, - opacity: 0.92, - cellHardnessFactor: 0.85, - shininess: 0.2, - lightingFactor: 0.35, - highlight: 1.0, - stroke: appTheme.VividPurple, - strokeThickness: 1, - contourStroke: appTheme.VividTeal, - contourInterval: 2, - contourOffset: 0, - contourStrokeThickness: 1, - drawSkirt: true, - drawMeshAs: EDrawMeshAs.SOLID_WITH_CONTOURS, - meshColorPalette: colorMap, - isVisible: true, - }); - - const symbolCarrierSeries = new ScatterRenderableSeries3D(wasmContext, { - dataSeries: new XyzDataSeries3D(wasmContext, { - dataSeriesName: "Symbol carriers", - }), - pointMarker: new SpherePointMarker3D(wasmContext, { - size: MANIFOLD_SYMBOL_MARKER_SIZE, - fill: appTheme.VividSkyBlue, - }), - isVisible: false, - }); - - const whaleCarrierSeries = new ScatterRenderableSeries3D(wasmContext, { - dataSeries: new XyzDataSeries3D(wasmContext, { - dataSeriesName: "Whale carriers", - }), - pointMarker: new SpherePointMarker3D(wasmContext, { - size: MANIFOLD_WHALE_MARKER_SIZE, - fill: appTheme.VividPink, - }), - isVisible: false, - }); - - sciChart3DSurface.renderableSeries.add(series); - sciChart3DSurface.renderableSeries.add(symbolCarrierSeries); - sciChart3DSurface.renderableSeries.add(whaleCarrierSeries); - - fitManifoldCamera( - sciChart3DSurface, - wasmContext, - gridX, - gridZ, - surfaceYMin, - surfaceYMax, - ); - - const addData = (frame: Record) => { - const gridRaw = - typeof frame.grid === "object" && frame.grid !== null - ? (frame.grid as Record) - : {}; - const spacing = rowNumber(gridRaw, "spacing"); - const gridXCount = rowNumber(gridRaw, "x"); - const gridZCount = rowNumber(gridRaw, "z"); - const domainX = rowNumber(gridRaw, "domain_x"); - const domainZ = rowNumber(gridRaw, "domain_z"); - - let effectiveSpacing = spacing; - - if (!(effectiveSpacing > 0) && domainX > 0 && gridXCount > 0) { - effectiveSpacing = domainX / gridXCount; - } - - if (!(effectiveSpacing > 0) && domainZ > 0 && gridZCount > 0) { - effectiveSpacing = domainZ / gridZCount; - } - - if (!(effectiveSpacing > 0)) { - effectiveSpacing = 1; - } - - const projected = projectManifoldHeightmap(frame, 0, 1); - const heights = projected.heights; - - if (isDegenerateHeightmap(heights)) { - return; - } - - const extent = manifoldHeightExtent(heights); - const pad = Math.max((extent.max - extent.min) * 0.08, 0.04); - - surfaceYMin = extent.min - pad; - surfaceYMax = extent.max + pad; - - const nextGridZ = heights.length; - const nextGridX = heights[0]?.length ?? 0; - const gridChanged = nextGridZ !== gridZ || nextGridX !== gridX; - - if (gridChanged) { - gridZ = nextGridZ; - gridX = nextGridX; - heightmapArray = zeroArray2D([gridZ, gridX]); - dataSeries = new UniformGridDataSeries3D(wasmContext, { - yValues: heightmapArray, - xStep: 1, - zStep: 1, - dataSeriesName: "Manifold density projection", - }); - series.dataSeries = dataSeries; - } - - for (let zIndex = 0; zIndex < gridZ; zIndex += 1) { - const heightRow = heights[zIndex]; - const targetRow = heightmapArray[zIndex]; - - if (!heightRow || !targetRow) { - continue; - } - - for (let xIndex = 0; xIndex < gridX; xIndex += 1) { - const value = heightRow[xIndex]; - targetRow[xIndex] = - typeof value === "number" && Number.isFinite(value) ? value : 0; - } - } - - dataSeries.setYValues(heightmapArray); - series.minimum = surfaceYMin; - series.maximum = surfaceYMax; - - const carriers = Array.isArray(frame.carriers) ? frame.carriers : []; - const symbolCarriers = carriers.filter( - (carrier) => - typeof carrier === "object" && - carrier !== null && - (carrier as Record).role === "symbol", - ); - const whaleCarriers = carriers.filter( - (carrier) => - typeof carrier === "object" && - carrier !== null && - (carrier as Record).role === "whale", - ); - - updateCarrierSeries( - symbolCarrierSeries, - symbolCarriers, - effectiveSpacing, - heights, - ); - updateCarrierSeries( - whaleCarrierSeries, - whaleCarriers, - effectiveSpacing, - heights, - ); - - if (gridChanged || !cameraFitted) { - fitManifoldCamera( - sciChart3DSurface, - wasmContext, - gridX, - gridZ, - surfaceYMin, - surfaceYMax, - ); - cameraFitted = true; - } - - sciChart3DSurface.invalidateElement(); - }; - - return { - sciChartSurface: sciChart3DSurface, - wasmContext, - addData, - }; -}; diff --git a/frontend/src/components/charts/manifold/manifold-camera.test.ts b/frontend/src/components/charts/manifold/manifold-camera.test.ts deleted file mode 100644 index 24dfa70a..00000000 --- a/frontend/src/components/charts/manifold/manifold-camera.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { describe, expect, it } from "vitest"; - -import { - manifoldCameraFrame, - manifoldHeightExtent, - normalizeCarrierWeights, -} from "#/components/charts/manifold/manifold-camera"; - -describe("manifoldCameraFrame", () => { - it("centers the orbit on the grid midpoint", () => { - const frame = manifoldCameraFrame(32, 16, 1); - - expect(frame.centerX).toBe(3.875); - expect(frame.centerZ).toBe(3.75); - expect(frame.orbit).toBeGreaterThan(0); - }); -}); - -describe("manifoldHeightExtent", () => { - it("adds padding when the surface is flat", () => { - expect(manifoldHeightExtent([[0.5, 0.5]])).toEqual({ - min: 0.45, - max: 0.55, - }); - }); -}); - -describe("normalizeCarrierWeights", () => { - it("scales carrier weights relative to the strongest carrier", () => { - const weights = normalizeCarrierWeights([ - { role: "symbol", symbol: "BTC/USD", amplitude: 0.2, heat: 0 }, - { role: "symbol", symbol: "ETH/USD", amplitude: 0.8, heat: 0 }, - ]); - - expect(weights.get("BTC/USD")).toBe(0.25); - expect(weights.get("ETH/USD")).toBe(1); - }); -}); diff --git a/frontend/src/components/charts/manifold/manifold-camera.ts b/frontend/src/components/charts/manifold/manifold-camera.ts deleted file mode 100644 index 07bfea59..00000000 --- a/frontend/src/components/charts/manifold/manifold-camera.ts +++ /dev/null @@ -1,109 +0,0 @@ -export const manifoldCameraFrame = ( - gridX: number, - gridZ: number, - ySpan: number, -): { - centerX: number; - centerZ: number; - yCenter: number; - orbit: number; - worldHeight: number; -} => { - const centerX = (gridX - 1) / 8; - const centerZ = (gridZ - 1) / 4; - const span = Math.max(gridX, gridZ, 1); - const orbit = span * 1.15; - const safeYSpan = Math.max(ySpan, 0.25); - const yCenter = safeYSpan / 2; - - return { - centerX, - centerZ, - yCenter, - orbit, - worldHeight: Math.max(safeYSpan * span * 0.42, 6), - }; -}; - -export const manifoldHeightExtent = ( - heights: number[][], -): { min: number; max: number } => { - let min = Number.POSITIVE_INFINITY; - let max = Number.NEGATIVE_INFINITY; - - for (const row of heights) { - for (const value of row) { - if (!Number.isFinite(value)) { - continue; - } - - if (value < min) { - min = value; - } - - if (value > max) { - max = value; - } - } - } - - if (!Number.isFinite(min) || !Number.isFinite(max)) { - return { min: 0, max: 1 }; - } - - if (max <= min) { - const pad = Math.max(Math.abs(min) * 0.1, 0.05); - - return { min: min - pad, max: max + pad }; - } - - return { min, max }; -}; - -export const carrierDisplayWeight = (carrier: unknown): number => { - if (typeof carrier !== "object" || carrier === null) { - return 0; - } - - const row = carrier as Record; - const role = typeof row.role === "string" ? row.role : ""; - const amplitude = - typeof row.amplitude === "number" && Number.isFinite(row.amplitude) - ? row.amplitude - : 0; - const heat = - typeof row.heat === "number" && Number.isFinite(row.heat) ? row.heat : 0; - - return role === "whale" ? heat : amplitude; -}; - -export const normalizeCarrierWeights = ( - carriers: unknown[], -): Map => { - let maxWeight = 0; - - for (const carrier of carriers) { - const weight = carrierDisplayWeight(carrier); - - if (weight > maxWeight) { - maxWeight = weight; - } - } - - if (maxWeight <= 0) { - maxWeight = 1; - } - - return new Map( - carriers.map((carrier) => { - const symbol = - typeof carrier === "object" && - carrier !== null && - typeof (carrier as Record).symbol === "string" - ? ((carrier as Record).symbol as string) - : ""; - - return [symbol, carrierDisplayWeight(carrier) / maxWeight]; - }), - ); -}; diff --git a/frontend/src/components/charts/manifold/manifold-grid.test.ts b/frontend/src/components/charts/manifold/manifold-grid.test.ts deleted file mode 100644 index 8f94857e..00000000 --- a/frontend/src/components/charts/manifold/manifold-grid.test.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { - isDegenerateHeightmap, - projectManifoldHeightmap, -} from "#/components/charts/manifold/manifold-grid"; - -const sampleFrame = () => ({ - type: "manifold", - ts: "2024-01-01T00:00:00Z", - grid: { x: 3, y: 1, z: 2, spacing: 1 }, - rho: [ - [0, 1, 2], - [1, 3, 4], - ], - reading: { - pressure_grad_x: 0, - pressure_grad_y: 0, - pressure_grad_z: 0, - pressure_grad_norm: 1, - divergence: 0, - coherence_mag2: 0.5, - guidance_speed: 0.2, - viscosity_proxy: 0.1, - }, - carriers: [ - { - role: "whale", - symbol: "XBT/USD", - x: 1, - y: 0, - z: 1, - cell_x: 1, - cell_y: 0, - cell_z: 1, - amplitude: 0.2, - heat: 0.8, - omega: 1, - phase: 0, - vel_x: 0.2, - vel_y: 0, - vel_z: 0, - }, - ], -}); - -describe("projectManifoldHeightmap", () => { - it("normalizes rho into a surface and bumps whale carriers", () => { - const projected = projectManifoldHeightmap(sampleFrame(), 0, 1); - - expect(projected.gridX).toBe(3); - expect(projected.gridZ).toBe(2); - expect(projected.heights[1][1]).toBeGreaterThan(projected.heights[0][0]); - }); -}); - -describe("isDegenerateHeightmap", () => { - it("rejects empty or non-finite surfaces", () => { - expect(isDegenerateHeightmap([])).toBe(true); - expect(isDegenerateHeightmap([[Number.NaN, 0.5]])).toBe(true); - expect(isDegenerateHeightmap([[0.5, 0.5]])).toBe(false); - expect(isDegenerateHeightmap([[0, 0.5, 1]])).toBe(false); - }); -}); diff --git a/frontend/src/components/charts/manifold/manifold-grid.ts b/frontend/src/components/charts/manifold/manifold-grid.ts deleted file mode 100644 index 620dbafc..00000000 --- a/frontend/src/components/charts/manifold/manifold-grid.ts +++ /dev/null @@ -1,197 +0,0 @@ -import { - carrierDisplayWeight, - normalizeCarrierWeights, -} from "#/components/charts/manifold/manifold-camera"; - -const clamp = (value: number, lower: number, upper: number): number => - Math.min(upper, Math.max(lower, value)); - -const MIN_CARRIER_PEAK_SCALE = 0.12; -const WEIGHT_PEAK_MULTIPLIER = 0.28; - -const rowNumber = (row: unknown, key: string): number => { - if (typeof row !== "object" || row === null) { - return Number.NaN; - } - - const value = (row as Record)[key]; - - return typeof value === "number" && Number.isFinite(value) - ? value - : Number.NaN; -}; - -const rowString = (row: unknown, key: string): string => { - if (typeof row !== "object" || row === null) { - return ""; - } - - const value = (row as Record)[key]; - - return typeof value === "string" ? value : ""; -}; - -export const isDegenerateHeightmap = (heights: number[][]): boolean => { - if (heights.length === 0 || (heights[0]?.length ?? 0) === 0) { - return true; - } - - for (const row of heights) { - for (const value of row) { - if (!Number.isFinite(value)) { - return true; - } - } - } - - return false; -}; - -const parseRho = (raw: unknown): number[][] | null => { - if (!Array.isArray(raw) || raw.length === 0) { - return null; - } - - const rho = raw.map((row) => { - if (!Array.isArray(row)) { - return []; - } - - return row.map((value) => - typeof value === "number" && Number.isFinite(value) ? value : 0, - ); - }); - - return rho.length > 0 && (rho[0]?.length ?? 0) > 0 ? rho : null; -}; - -const applyCarrierBumps = ( - heights: number[][], - carriers: unknown[], - gridX: number, - gridZ: number, - spacing: number, - yMin: number, - yMax: number, -) => { - if (carriers.length === 0 || gridX <= 0 || gridZ <= 0 || spacing <= 0) { - return; - } - - const weights = normalizeCarrierWeights(carriers); - - for (const carrier of carriers) { - const cellX = clamp(Math.round(rowNumber(carrier, "cell_x")), 0, gridX - 1); - const cellZ = clamp(Math.round(rowNumber(carrier, "cell_z")), 0, gridZ - 1); - const normalizedWeight = weights.get(rowString(carrier, "symbol")) ?? 0; - const peak = - yMin + - normalizedWeight * - (yMax - yMin) * - Math.max( - MIN_CARRIER_PEAK_SCALE, - WEIGHT_PEAK_MULTIPLIER * normalizedWeight, - ); - - for (let zOffset = -1; zOffset <= 1; zOffset += 1) { - for (let xOffset = -1; xOffset <= 1; xOffset += 1) { - const xIndex = cellX + xOffset; - const zIndex = cellZ + zOffset; - - if (xIndex < 0 || zIndex < 0 || xIndex >= gridX || zIndex >= gridZ) { - continue; - } - - const row = heights[zIndex]; - - if (!row) { - continue; - } - - const weight = 1 / (1 + Math.abs(xOffset) + Math.abs(zOffset)); - row[xIndex] = Math.max( - row[xIndex] ?? yMin, - yMin + (peak - yMin) * weight, - ); - } - } - } -}; - -export const projectManifoldHeightmap = ( - frame: Record, - yMin: number, - yMax: number, -) => { - const rho = parseRho(frame.rho); - - if (rho === null) { - return { - heights: [] as number[][], - gridX: 0, - gridZ: 0, - min: 0, - max: 1, - }; - } - - const gridZ = rho.length; - const gridX = rho[0]?.length ?? 0; - const heights = rho.map((row) => - row.map((value) => (Number.isFinite(value) ? value : 0)), - ); - - let min = Number.POSITIVE_INFINITY; - let max = Number.NEGATIVE_INFINITY; - - for (const row of heights) { - for (const value of row) { - if (value < min) { - min = value; - } - - if (value > max) { - max = value; - } - } - } - - if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min) { - min = 0; - max = 1; - } - - const span = max - min; - const normalized = heights.map((row) => - row.map((value) => yMin + ((value - min) / span) * (yMax - yMin)), - ); - - const gridRaw = - typeof frame.grid === "object" && frame.grid !== null - ? (frame.grid as Record) - : {}; - const gridXCount = rowNumber(gridRaw, "x"); - const gridZCount = rowNumber(gridRaw, "z"); - const spacing = rowNumber(gridRaw, "spacing"); - const carriers = Array.isArray(frame.carriers) ? frame.carriers : []; - - applyCarrierBumps( - normalized, - carriers, - Number.isFinite(gridXCount) ? gridXCount : gridX, - Number.isFinite(gridZCount) ? gridZCount : gridZ, - Number.isFinite(spacing) && spacing > 0 ? spacing : 1, - yMin, - yMax, - ); - - return { - heights: normalized, - gridX, - gridZ, - min, - max, - }; -}; - -export { carrierDisplayWeight }; diff --git a/frontend/src/components/charts/prediction/PredictionChart.tsx b/frontend/src/components/charts/prediction/PredictionChart.tsx deleted file mode 100644 index 515c7653..00000000 --- a/frontend/src/components/charts/prediction/PredictionChart.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { memo } from "react"; -import { SciChartReact } from "scichart-react"; -import { appStore } from "#/collections/app"; -import { initPredictionChart } from "#/components/charts/prediction/init-prediction-chart"; - -export const PredictionChart = memo(function PredictionChart() { - return ( - { - if (typeof rootElement === "string") { - throw new Error( - "initPredictionChart requires an HTMLDivElement root", - ); - } - - return initPredictionChart(rootElement); - }} - onInit={(result) => { - appStore.actions.updatePredictionUpdater(result.addData); - - return () => appStore.actions.updatePredictionUpdater(null); - }} - /> - ); -}); diff --git a/frontend/src/components/charts/prediction/init-prediction-chart.ts b/frontend/src/components/charts/prediction/init-prediction-chart.ts deleted file mode 100644 index afa39048..00000000 --- a/frontend/src/components/charts/prediction/init-prediction-chart.ts +++ /dev/null @@ -1,171 +0,0 @@ -import { - DiscontinuousDateAxis, - EAutoRange, - EAxisAlignment, - ENumericFormat, - FastLineRenderableSeries, - NumberRange, - NumericAxis, - SciChartSurface, - XyDataSeries, -} from "scichart"; -import { - PREDICTION_VALUE_MAX, - PREDICTION_VALUE_MIN, - predictionVisibleXRange, - pruneSeriesBefore, - seriesEarliestX, - seriesLatestX, - upsertSortedPoint, -} from "#/components/charts/prediction/prediction-chart-series"; -import { ensureSciChartWasm } from "#/lib/utils"; - -const SERIES_CAPACITY = 600; - -export const initPredictionChart = async (rootElement: HTMLDivElement) => { - await ensureSciChartWasm(); - - const { wasmContext, sciChartSurface } = await SciChartSurface.create( - rootElement, - { freezeWhenOutOfView: true }, - ); - - const xAxis = new DiscontinuousDateAxis(wasmContext, { - axisAlignment: EAxisAlignment.Bottom, - labelFormat: ENumericFormat.Date_HHMMSS, - growBy: new NumberRange(0.02, 0), - drawMajorBands: false, - drawMinorGridLines: false, - labelStyle: { - fontSize: 10, - }, - }); - - const yAxis = new NumericAxis(wasmContext, { - axisAlignment: EAxisAlignment.Left, - autoRange: EAutoRange.Never, - visibleRange: new NumberRange(PREDICTION_VALUE_MIN, PREDICTION_VALUE_MAX), - growBy: new NumberRange(0.05, 0.05), - labelStyle: { - fontSize: 10, - }, - }); - - sciChartSurface.xAxes.add(xAxis); - sciChartSurface.yAxes.add(yAxis); - - const forecastSeries = new XyDataSeries(wasmContext, { - dataSeriesName: "Mean forecast (60s)", - dataIsSortedInX: true, - containsNaN: false, - capacity: SERIES_CAPACITY, - }); - - const actualSeries = new XyDataSeries(wasmContext, { - dataSeriesName: "Mean actual", - dataIsSortedInX: true, - containsNaN: false, - capacity: SERIES_CAPACITY, - }); - - const errorSeries = new XyDataSeries(wasmContext, { - dataSeriesName: "Mean error", - dataIsSortedInX: true, - containsNaN: false, - capacity: SERIES_CAPACITY, - }); - - sciChartSurface.renderableSeries.add( - new FastLineRenderableSeries(wasmContext, { - dataSeries: forecastSeries, - stroke: "#FBA55A", - strokeThickness: 2, - strokeDashArray: [6, 4], - }), - new FastLineRenderableSeries(wasmContext, { - dataSeries: actualSeries, - stroke: "#4EC385", - strokeThickness: 2, - }), - new FastLineRenderableSeries(wasmContext, { - dataSeries: errorSeries, - stroke: "#E85D75", - strokeThickness: 2, - }), - ); - - let horizonSec = 60; - - const visibleXRange = () => - predictionVisibleXRange( - horizonSec, - seriesLatestX(forecastSeries), - seriesEarliestX(actualSeries), - seriesEarliestX(errorSeries), - Math.floor(Date.now() / 1000), - ); - - const syncXRange = () => { - const { minX, maxX } = visibleXRange(); - - xAxis.visibleRange = new NumberRange(minX, maxX); - }; - - syncXRange(); - - const addData = (frame: Record) => { - const kind = frame.kind; - - if (kind !== "actual" && kind !== "prediction" && kind !== "error") { - return; - } - - const xValue = frame.x; - const pointValue = frame.value; - - if ( - typeof xValue !== "number" || - !Number.isFinite(xValue) || - typeof pointValue !== "number" || - !Number.isFinite(pointValue) - ) { - return; - } - - const horizon = frame.horizon; - - if ( - typeof horizon === "number" && - Number.isFinite(horizon) && - horizon > 0 - ) { - horizonSec = horizon; - } - - const { minX } = visibleXRange(); - - if (kind === "prediction") { - upsertSortedPoint(forecastSeries, xValue, pointValue); - } - - if (kind === "actual") { - upsertSortedPoint(actualSeries, xValue, pointValue); - } - - if (kind === "error") { - upsertSortedPoint(errorSeries, xValue, pointValue); - } - - pruneSeriesBefore(forecastSeries, minX); - pruneSeriesBefore(actualSeries, minX); - pruneSeriesBefore(errorSeries, minX); - - syncXRange(); - sciChartSurface.invalidateElement(); - }; - - return { - sciChartSurface, - addData, - }; -}; diff --git a/frontend/src/components/charts/prediction/prediction-chart-series.ts b/frontend/src/components/charts/prediction/prediction-chart-series.ts deleted file mode 100644 index 506c1cf6..00000000 --- a/frontend/src/components/charts/prediction/prediction-chart-series.ts +++ /dev/null @@ -1,115 +0,0 @@ -import type { XyDataSeries } from "scichart"; - -export const PREDICTION_VALUE_MIN = -1; -export const PREDICTION_VALUE_MAX = 1; - -export const predictionWindowMin = ( - rightEdge: number, - horizonSec: number, -): number => rightEdge - 2 * horizonSec; - -export const predictionVisibleXRange = ( - horizonSec: number, - forecastTipX: number | null, - actualEarliestX: number | null, - errorEarliestX: number | null, - nowSec: number, -) => { - if (horizonSec <= 0) { - throw new RangeError( - "predictionVisibleXRange: horizonSec must be positive", - ); - } - - const maxX = forecastTipX ?? nowSec + horizonSec; - let minX = predictionWindowMin(maxX, horizonSec); - - const groundMin = Math.min( - actualEarliestX ?? Number.POSITIVE_INFINITY, - errorEarliestX ?? Number.POSITIVE_INFINITY, - ); - - if (groundMin < minX) { - minX = groundMin; - } - - const maxSpan = 4 * horizonSec; - - if (maxX - minX > maxSpan) { - minX = maxX - maxSpan; - } - - return { minX, maxX }; -}; - -export const upsertSortedPoint = ( - dataSeries: XyDataSeries, - x: number, - value: number, -): void => { - const nativeX = dataSeries.getNativeXValues(); - const count = dataSeries.count(); - - for (let index = 0; index < count; index += 1) { - const existingX = nativeX.get(index); - - if (existingX === x) { - dataSeries.update(index, value); - return; - } - - if (existingX > x) { - dataSeries.insert(index, x, value); - return; - } - } - - dataSeries.append(x, value); -}; - -export const pruneSeriesBefore = ( - dataSeries: XyDataSeries, - minX: number, -): void => { - const nativeX = dataSeries.getNativeXValues(); - const nativeY = dataSeries.getNativeYValues(); - const nextX: number[] = []; - const nextY: number[] = []; - - for (let index = 0; index < dataSeries.count(); index += 1) { - const x = nativeX.get(index); - - if (x < minX) { - continue; - } - - nextX.push(x); - nextY.push(nativeY.get(index)); - } - - dataSeries.clear(); - - for (let index = 0; index < nextX.length; index += 1) { - dataSeries.append(nextX[index] ?? 0, nextY[index] ?? 0); - } -}; - -export const seriesLatestX = (dataSeries: XyDataSeries): number | null => { - const count = dataSeries.count(); - - if (count <= 0) { - return null; - } - - return dataSeries.getNativeXValues().get(count - 1); -}; - -export const seriesEarliestX = (dataSeries: XyDataSeries): number | null => { - const count = dataSeries.count(); - - if (count <= 0) { - return null; - } - - return dataSeries.getNativeXValues().get(0); -}; diff --git a/frontend/src/components/charts/resonance/ResonanceXRayChart.tsx b/frontend/src/components/charts/resonance/ResonanceXRayChart.tsx deleted file mode 100644 index 96d0ff68..00000000 --- a/frontend/src/components/charts/resonance/ResonanceXRayChart.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import { memo, useEffect, useRef } from "react"; -import { SciChartReact } from "scichart-react"; -import { appStore } from "#/collections/app"; -import { initResonanceConstellationChart } from "#/components/charts/resonance/init-resonance-constellation-chart"; -import { initResonanceUniverseHeatmap } from "#/components/charts/resonance/init-resonance-universe-heatmap"; -import { initResonanceXRayChart } from "#/components/charts/resonance/init-resonance-xray-chart"; -import { Flex } from "#/components/ui/flex"; - -type ResonanceFrameUpdater = (frame: Record) => void; - -export const ResonanceXRayChart = memo(function ResonanceXRayChart() { - const updatersRef = useRef<{ - universeHeatmap: ResonanceFrameUpdater | null; - xray: ResonanceFrameUpdater | null; - constellation: ResonanceFrameUpdater | null; - }>({ - universeHeatmap: null, - xray: null, - constellation: null, - }); - - const pendingFrameRef = useRef | null>(null); - const animationFrameRef = useRef(0); - - useEffect(() => { - return () => { - if (animationFrameRef.current !== 0) { - cancelAnimationFrame(animationFrameRef.current); - } - }; - }, []); - - const registerResonanceFanOut = () => { - appStore.actions.updateResonanceUpdater((frame) => { - pendingFrameRef.current = frame; - - if (animationFrameRef.current !== 0) { - return; - } - - animationFrameRef.current = requestAnimationFrame(() => { - animationFrameRef.current = 0; - - const pendingFrame = pendingFrameRef.current; - - if (pendingFrame === null) { - return; - } - - pendingFrameRef.current = null; - updatersRef.current.universeHeatmap?.(pendingFrame); - updatersRef.current.xray?.(pendingFrame); - updatersRef.current.constellation?.(pendingFrame); - }); - }); - }; - - return ( - -
- { - updatersRef.current.universeHeatmap = result.addData; - registerResonanceFanOut(); - - return () => { - updatersRef.current.universeHeatmap = null; - registerResonanceFanOut(); - }; - }} - /> -
- -
- { - updatersRef.current.xray = result.addData; - registerResonanceFanOut(); - - return () => { - updatersRef.current.xray = null; - registerResonanceFanOut(); - }; - }} - /> -
-
- { - updatersRef.current.constellation = result.addData; - registerResonanceFanOut(); - - return () => { - updatersRef.current.constellation = null; - registerResonanceFanOut(); - }; - }} - /> -
-
-
- ); -}); diff --git a/frontend/src/components/charts/resonance/init-resonance-constellation-chart.ts b/frontend/src/components/charts/resonance/init-resonance-constellation-chart.ts deleted file mode 100644 index 1d704509..00000000 --- a/frontend/src/components/charts/resonance/init-resonance-constellation-chart.ts +++ /dev/null @@ -1,218 +0,0 @@ -import { - CameraController, - NumberRange, - NumericAxis3D, - ScatterRenderableSeries3D, - SciChart3DSurface, - SpherePointMarker3D, - Vector3, - XyzDataSeries3D, -} from "scichart"; -import { - constellationCameraFrame, - latentWorldCameraFrame, -} from "#/components/charts/resonance/latent-camera"; -import { - categoryFill, - latentPointFromVector, - parseResonanceUniverseFrame, -} from "#/components/charts/resonance/resonance-universe-frame"; -import { - type LatentPoint3D, - latentMarkerSizes, -} from "#/components/charts/resonance/resonance-xray-frame"; -import { appTheme } from "#/components/charts/shared/theme"; -import { ensureSciChartWasm } from "#/lib/utils"; - -const MIN_ORBIT_RADIUS = 0.75; - -const fitConstellationCamera = ( - sciChart3DSurface: SciChart3DSurface, - wasmContext: Awaited< - ReturnType - >["wasmContext"], - points: LatentPoint3D[], - fieldMarker: SpherePointMarker3D, - focusMarker: SpherePointMarker3D, -) => { - const frame = constellationCameraFrame(points, MIN_ORBIT_RADIUS); - - if (frame === null) { - return; - } - - const worldFrame = latentWorldCameraFrame(frame); - - sciChart3DSurface.xAxis.visibleRange = new NumberRange( - worldFrame.visibleRange.x.min, - worldFrame.visibleRange.x.max, - ); - sciChart3DSurface.yAxis.visibleRange = new NumberRange( - worldFrame.visibleRange.y.min, - worldFrame.visibleRange.y.max, - ); - sciChart3DSurface.zAxis.visibleRange = new NumberRange( - worldFrame.visibleRange.z.min, - worldFrame.visibleRange.z.max, - ); - - sciChart3DSurface.camera = new CameraController(wasmContext, { - position: new Vector3( - worldFrame.cameraPosition.x, - worldFrame.cameraPosition.y, - worldFrame.cameraPosition.z, - ), - target: new Vector3( - worldFrame.worldCenter.x, - worldFrame.worldCenter.y, - worldFrame.worldCenter.z, - ), - }); - sciChart3DSurface.worldDimensions = new Vector3( - worldFrame.worldDimensions.x, - worldFrame.worldDimensions.y, - worldFrame.worldDimensions.z, - ); - - fieldMarker.size = worldFrame.markerSizes.trail; - focusMarker.size = worldFrame.markerSizes.head; -}; - -export const initResonanceConstellationChart = async ( - rootElement: string | HTMLDivElement, -) => { - await ensureSciChartWasm(); - - const { sciChart3DSurface, wasmContext } = await SciChart3DSurface.create( - rootElement, - { - theme: appTheme.SciChartJsTheme, - freezeWhenOutOfView: false, - }, - ); - - sciChart3DSurface.xAxis = new NumericAxis3D(wasmContext, { - axisTitle: "z0", - axisTitleStyle: { fontSize: 10, color: appTheme.ForegroundColor }, - }); - sciChart3DSurface.yAxis = new NumericAxis3D(wasmContext, { - axisTitle: "z1", - axisTitleStyle: { fontSize: 10, color: appTheme.ForegroundColor }, - }); - sciChart3DSurface.zAxis = new NumericAxis3D(wasmContext, { - axisTitle: "z2", - axisTitleStyle: { fontSize: 10, color: appTheme.ForegroundColor }, - }); - - const fieldSeries = new XyzDataSeries3D(wasmContext, { - dataSeriesName: "Resonance field", - }); - const focusSeries = new XyzDataSeries3D(wasmContext, { - dataSeriesName: "Resonance focus", - }); - - const initialMarkerSizes = latentMarkerSizes(MIN_ORBIT_RADIUS); - - const fieldMarker = new SpherePointMarker3D(wasmContext, { - size: initialMarkerSizes.trail, - fill: `${appTheme.VividSkyBlue}AA`, - }); - const focusMarker = new SpherePointMarker3D(wasmContext, { - size: initialMarkerSizes.head, - fill: appTheme.VividPink, - }); - - const fieldRenderable = new ScatterRenderableSeries3D(wasmContext, { - dataSeries: fieldSeries, - pointMarker: fieldMarker, - isVisible: false, - }); - const focusRenderable = new ScatterRenderableSeries3D(wasmContext, { - dataSeries: focusSeries, - pointMarker: focusMarker, - isVisible: false, - }); - - sciChart3DSurface.camera = new CameraController(wasmContext, { - position: new Vector3(-1.1, 0.85, 1.1), - target: new Vector3(1, 1, 1), - }); - sciChart3DSurface.worldDimensions = new Vector3(2, 2, 2); - - sciChart3DSurface.renderableSeries.add(fieldRenderable, focusRenderable); - - let hasRenderablePoints = false; - - const addData = (raw: Record) => { - if (sciChart3DSurface.isDeleted) { - return; - } - - const frame = parseResonanceUniverseFrame(raw); - - if (frame === null) { - return; - } - - const points: LatentPoint3D[] = []; - - for (const summary of frame.symbols) { - const point = latentPointFromVector(summary.latent); - - if (point === null) { - return; - } - - points.push(point); - } - - if (points.length === 0) { - return; - } - - const focusSummary = frame.symbols.find( - (summary) => summary.symbol === frame.focusSymbol, - ); - - if (focusSummary === undefined) { - return; - } - - const focusPoint = latentPointFromVector(focusSummary.latent); - - if (focusPoint === null) { - return; - } - - fieldSeries.clear(); - focusSeries.clear(); - - for (const point of points) { - fieldSeries.append(point.x, point.y, point.z); - } - - focusMarker.fill = categoryFill(frame.focus.category); - focusSeries.append(focusPoint.x, focusPoint.y, focusPoint.z); - - if (!hasRenderablePoints) { - hasRenderablePoints = true; - fieldRenderable.isVisible = true; - focusRenderable.isVisible = true; - } - - fitConstellationCamera( - sciChart3DSurface, - wasmContext, - points, - fieldMarker, - focusMarker, - ); - sciChart3DSurface.invalidateElement(); - }; - - return { - sciChartSurface: sciChart3DSurface, - wasmContext, - addData, - }; -}; diff --git a/frontend/src/components/charts/resonance/init-resonance-latent-chart.ts b/frontend/src/components/charts/resonance/init-resonance-latent-chart.ts deleted file mode 100644 index e687685d..00000000 --- a/frontend/src/components/charts/resonance/init-resonance-latent-chart.ts +++ /dev/null @@ -1,249 +0,0 @@ -import { - CameraController, - NumberRange, - NumericAxis3D, - ScatterRenderableSeries3D, - SciChart3DSurface, - SpherePointMarker3D, - Vector3, - XyzDataSeries3D, -} from "scichart"; -import { - latentCameraFrame, - latentWorldCameraFrame, -} from "#/components/charts/resonance/latent-camera"; -import { - type LatentPoint3D, - latentMarkerSizes, - latentPoint3D, - parseResonanceXRayFrame, -} from "#/components/charts/resonance/resonance-xray-frame"; -import { appTheme } from "#/components/charts/shared/theme"; -import { ensureSciChartWasm } from "#/lib/utils"; - -const LATENT_TRAIL_CAPACITY = 512; -const MIN_ORBIT_RADIUS = 0.75; - -const surpriseFill = (surprise: number, surpriseScale: number): string => { - const normalized = Math.min(1, Math.max(0, surprise / surpriseScale)); - - if (normalized < 0.5) { - return appTheme.VividGreen; - } - - if (normalized < 0.8) { - return appTheme.VividOrange; - } - - return appTheme.VividRed; -}; - -const readTrailPoints = (trailSeries: XyzDataSeries3D): LatentPoint3D[] => { - const count = trailSeries.count(); - - if (count === 0) { - return []; - } - - const xValues = trailSeries.getNativeXValues(); - const yValues = trailSeries.getNativeYValues(); - const zValues = trailSeries.getNativeZValues(); - const points: LatentPoint3D[] = []; - - for (let pointIndex = 0; pointIndex < count; pointIndex += 1) { - points.push({ - x: xValues.get(pointIndex), - y: yValues.get(pointIndex), - z: zValues.get(pointIndex), - }); - } - - return points; -}; - -const fitLatentCamera = ( - sciChart3DSurface: SciChart3DSurface, - wasmContext: Awaited< - ReturnType - >["wasmContext"], - trailSeries: XyzDataSeries3D, - headMarker: SpherePointMarker3D, - trailMarker: SpherePointMarker3D, -) => { - const frame = latentCameraFrame( - readTrailPoints(trailSeries), - MIN_ORBIT_RADIUS, - ); - - if (frame === null) { - return; - } - - const worldFrame = latentWorldCameraFrame(frame); - - sciChart3DSurface.xAxis.visibleRange = new NumberRange( - worldFrame.visibleRange.x.min, - worldFrame.visibleRange.x.max, - ); - sciChart3DSurface.yAxis.visibleRange = new NumberRange( - worldFrame.visibleRange.y.min, - worldFrame.visibleRange.y.max, - ); - sciChart3DSurface.zAxis.visibleRange = new NumberRange( - worldFrame.visibleRange.z.min, - worldFrame.visibleRange.z.max, - ); - - sciChart3DSurface.camera = new CameraController(wasmContext, { - position: new Vector3( - worldFrame.cameraPosition.x, - worldFrame.cameraPosition.y, - worldFrame.cameraPosition.z, - ), - target: new Vector3( - worldFrame.worldCenter.x, - worldFrame.worldCenter.y, - worldFrame.worldCenter.z, - ), - }); - sciChart3DSurface.worldDimensions = new Vector3( - worldFrame.worldDimensions.x, - worldFrame.worldDimensions.y, - worldFrame.worldDimensions.z, - ); - - headMarker.size = worldFrame.markerSizes.head; - trailMarker.size = worldFrame.markerSizes.trail; -}; - -export const initResonanceLatentChart = async ( - rootElement: string | HTMLDivElement, -) => { - await ensureSciChartWasm(); - - const { sciChart3DSurface, wasmContext } = await SciChart3DSurface.create( - rootElement, - { - theme: appTheme.SciChartJsTheme, - freezeWhenOutOfView: false, - }, - ); - - sciChart3DSurface.xAxis = new NumericAxis3D(wasmContext, { - axisTitle: "z0", - axisTitleStyle: { fontSize: 10, color: appTheme.ForegroundColor }, - }); - sciChart3DSurface.yAxis = new NumericAxis3D(wasmContext, { - axisTitle: "z1", - axisTitleStyle: { fontSize: 10, color: appTheme.ForegroundColor }, - }); - sciChart3DSurface.zAxis = new NumericAxis3D(wasmContext, { - axisTitle: "z2", - axisTitleStyle: { fontSize: 10, color: appTheme.ForegroundColor }, - }); - - const trailSeries = new XyzDataSeries3D(wasmContext, { - dataSeriesName: "Latent trajectory", - fifoCapacity: LATENT_TRAIL_CAPACITY, - capacity: LATENT_TRAIL_CAPACITY, - }); - - const headSeries = new XyzDataSeries3D(wasmContext, { - dataSeriesName: "Latent head", - }); - - const initialMarkerSizes = latentMarkerSizes(MIN_ORBIT_RADIUS); - - const trailMarker = new SpherePointMarker3D(wasmContext, { - size: initialMarkerSizes.trail, - fill: `${appTheme.VividSkyBlue}AA`, - }); - - const headMarker = new SpherePointMarker3D(wasmContext, { - size: initialMarkerSizes.head, - fill: appTheme.VividPink, - }); - - const trailRenderable = new ScatterRenderableSeries3D(wasmContext, { - dataSeries: trailSeries, - pointMarker: trailMarker, - isVisible: false, - }); - - const headRenderable = new ScatterRenderableSeries3D(wasmContext, { - dataSeries: headSeries, - pointMarker: headMarker, - isVisible: false, - }); - - sciChart3DSurface.camera = new CameraController(wasmContext, { - position: new Vector3(-1.1, 0.85, 1.1), - target: new Vector3(1, 1, 1), - }); - sciChart3DSurface.worldDimensions = new Vector3(2, 2, 2); - - sciChart3DSurface.renderableSeries.add(trailRenderable, headRenderable); - - let surpriseScale = 1; - let activeSymbol = ""; - let hasRenderablePoints = false; - - const setHeadPoint = (point: LatentPoint3D) => { - if (headSeries.count() === 0) { - headSeries.append(point.x, point.y, point.z); - - return; - } - - headSeries.getNativeXValues().set(0, point.x); - headSeries.getNativeYValues().set(0, point.y); - headSeries.getNativeZValues().set(0, point.z); - }; - - const addData = (raw: Record) => { - if (sciChart3DSurface.isDeleted) { - return; - } - - const frame = parseResonanceXRayFrame(raw); - - if (frame === null) { - return; - } - - if (activeSymbol !== "" && activeSymbol !== frame.symbol) { - trailSeries.clear(); - } - - activeSymbol = frame.symbol; - - const point = latentPoint3D(frame.layers); - - trailSeries.append(point.x, point.y, point.z); - setHeadPoint(point); - - surpriseScale = Math.max(surpriseScale * 0.95, frame.surprise, 1e-6); - headMarker.fill = surpriseFill(frame.surprise, surpriseScale); - - if (!hasRenderablePoints) { - hasRenderablePoints = true; - trailRenderable.isVisible = true; - headRenderable.isVisible = true; - } - - fitLatentCamera( - sciChart3DSurface, - wasmContext, - trailSeries, - headMarker, - trailMarker, - ); - sciChart3DSurface.invalidateElement(); - }; - - return { - sciChartSurface: sciChart3DSurface, - wasmContext, - addData, - }; -}; diff --git a/frontend/src/components/charts/resonance/init-resonance-universe-heatmap.test.ts b/frontend/src/components/charts/resonance/init-resonance-universe-heatmap.test.ts deleted file mode 100644 index e9a26fe0..00000000 --- a/frontend/src/components/charts/resonance/init-resonance-universe-heatmap.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { - applyUniverseHeatmapRows, - UNIVERSE_HEATMAP_MAX_ROWS, - UNIVERSE_HEATMAP_TIME_COLS, -} from "#/components/charts/resonance/init-resonance-universe-heatmap"; - -describe("applyUniverseHeatmapRows", () => { - it("keeps a fixed buffer size while updating active rows", () => { - const zValues = Array.from({ length: UNIVERSE_HEATMAP_MAX_ROWS }, () => - Array.from({ length: UNIVERSE_HEATMAP_TIME_COLS }, () => 0), - ); - const historyBySymbol = new Map(); - - const activeRowCount = applyUniverseHeatmapRows( - zValues, - historyBySymbol, - [ - { - symbol: "BTC/USD", - surprise: 0.2, - energy: 0, - confidence: 0, - category: "", - strength: 0, - latent: [0, 0, 0], - }, - { - symbol: "ETH/USD", - surprise: 0.9, - energy: 0, - confidence: 0, - category: "", - strength: 0, - latent: [0, 0, 0], - }, - ], - 1, - ); - - expect(activeRowCount).toBe(2); - expect(zValues).toHaveLength(UNIVERSE_HEATMAP_MAX_ROWS); - expect(zValues[0]?.[UNIVERSE_HEATMAP_TIME_COLS - 1]).toBeGreaterThan( - zValues[1]?.[UNIVERSE_HEATMAP_TIME_COLS - 1] ?? 0, - ); - expect(zValues[2]?.[UNIVERSE_HEATMAP_TIME_COLS - 1]).toBe(0); - }); -}); diff --git a/frontend/src/components/charts/resonance/init-resonance-universe-heatmap.ts b/frontend/src/components/charts/resonance/init-resonance-universe-heatmap.ts deleted file mode 100644 index d9d94d7e..00000000 --- a/frontend/src/components/charts/resonance/init-resonance-universe-heatmap.ts +++ /dev/null @@ -1,231 +0,0 @@ -import { - EAutoRange, - EAxisAlignment, - ECoordinateMode, - EHorizontalAnchorPoint, - EVerticalAnchorPoint, - HeatmapColorMap, - NumberRange, - NumericAxis, - SciChartSurface, - TextAnnotation, - UniformHeatmapDataSeries, - UniformHeatmapRenderableSeries, - zeroArray2D, -} from "scichart"; -import { - normalizedSurpriseReading, - parseResonanceUniverseFrame, - type ResonanceSymbolSummary, - type ResonanceUniverseFrame, - sortedUniverseSymbols, -} from "#/components/charts/resonance/resonance-universe-frame"; -import { recentHeatmapTimeRange } from "#/components/charts/resonance/resonance-xray-frame"; -import { appTheme } from "#/components/charts/shared/theme"; -import { ensureSciChartWasm } from "#/lib/utils"; - -export const UNIVERSE_HEATMAP_TIME_COLS = 120; -export const UNIVERSE_HEATMAP_TIME_WINDOW = 48; -export const UNIVERSE_HEATMAP_MAX_ROWS = 1024; - -export const applyUniverseHeatmapRows = ( - zValues: number[][], - historyBySymbol: Map, - symbols: ResonanceSymbolSummary[], - surpriseScale: number, -): number => { - const sortedSymbols = sortedUniverseSymbols(symbols).slice( - 0, - UNIVERSE_HEATMAP_MAX_ROWS, - ); - const activeRowCount = sortedSymbols.length; - - for (let rowIndex = 0; rowIndex < activeRowCount; rowIndex += 1) { - const summary = sortedSymbols[rowIndex]; - const reading = normalizedSurpriseReading(summary.surprise, surpriseScale); - let history = historyBySymbol.get(summary.symbol); - - if (history === undefined) { - history = Array.from({ length: UNIVERSE_HEATMAP_TIME_COLS }, () => 0); - historyBySymbol.set(summary.symbol, history); - } - - for ( - let columnIndex = 0; - columnIndex < UNIVERSE_HEATMAP_TIME_COLS - 1; - columnIndex += 1 - ) { - history[columnIndex] = history[columnIndex + 1]; - } - - history[UNIVERSE_HEATMAP_TIME_COLS - 1] = reading; - - for ( - let columnIndex = 0; - columnIndex < UNIVERSE_HEATMAP_TIME_COLS; - columnIndex += 1 - ) { - zValues[rowIndex][columnIndex] = history[columnIndex] ?? 0; - } - } - - for ( - let rowIndex = activeRowCount; - rowIndex < UNIVERSE_HEATMAP_MAX_ROWS; - rowIndex += 1 - ) { - for ( - let columnIndex = 0; - columnIndex < UNIVERSE_HEATMAP_TIME_COLS; - columnIndex += 1 - ) { - zValues[rowIndex][columnIndex] = 0; - } - } - - return activeRowCount; -}; - -export const initResonanceUniverseHeatmap = async ( - rootElement: string | HTMLDivElement, -) => { - await ensureSciChartWasm(); - - const { sciChartSurface, wasmContext } = await SciChartSurface.create( - rootElement, - { - background: appTheme.Background, - freezeWhenOutOfView: false, - }, - ); - - const zValues = zeroArray2D([ - UNIVERSE_HEATMAP_MAX_ROWS, - UNIVERSE_HEATMAP_TIME_COLS, - ]); - const historyBySymbol = new Map(); - - sciChartSurface.xAxes.add( - new NumericAxis(wasmContext, { - isVisible: false, - autoRange: EAutoRange.Never, - visibleRange: new NumberRange( - recentHeatmapTimeRange( - UNIVERSE_HEATMAP_TIME_COLS, - UNIVERSE_HEATMAP_TIME_WINDOW, - ).start, - UNIVERSE_HEATMAP_TIME_COLS, - ), - }), - ); - - const yAxis = new NumericAxis(wasmContext, { - axisAlignment: EAxisAlignment.Left, - isVisible: false, - autoRange: EAutoRange.Never, - visibleRange: new NumberRange(-0.5, UNIVERSE_HEATMAP_MAX_ROWS - 0.5), - }); - - sciChartSurface.yAxes.add(yAxis); - - const xAxis = sciChartSurface.xAxes.get(0); - - const dataSeries = new UniformHeatmapDataSeries(wasmContext, { - zValues, - xStart: 0, - xStep: 1, - yStart: 0, - yStep: 1, - }); - - const series = new UniformHeatmapRenderableSeries(wasmContext, { - dataSeries, - colorMap: new HeatmapColorMap({ - minimum: 0, - maximum: 1, - gradientStops: [ - { offset: 0, color: "#0b0f14" }, - { offset: 0.25, color: appTheme.Indigo }, - { offset: 0.55, color: appTheme.VividOrange }, - { offset: 1, color: appTheme.VividPink }, - ], - }), - useLinearTextureFiltering: true, - }); - - sciChartSurface.renderableSeries.add(series); - - const headerAnnotation = new TextAnnotation({ - text: "Resonance universe", - x1: 0, - y1: 0, - xCoordinateMode: ECoordinateMode.Relative, - yCoordinateMode: ECoordinateMode.Relative, - horizontalAnchorPoint: EHorizontalAnchorPoint.Left, - verticalAnchorPoint: EVerticalAnchorPoint.Top, - fontSize: 11, - textColor: "rgba(226,232,240,0.85)", - background: "rgba(11,15,20,0.65)", - }); - - sciChartSurface.annotations.add(headerAnnotation); - - let surpriseScale = 1; - let activeRowCount = 0; - - const applyUniverseFrame = (frame: ResonanceUniverseFrame) => { - surpriseScale = Math.max( - surpriseScale * 0.98, - ...frame.symbols.map((entry) => entry.surprise), - 1e-6, - ); - - activeRowCount = applyUniverseHeatmapRows( - zValues, - historyBySymbol, - frame.symbols, - surpriseScale, - ); - - yAxis.visibleRange = new NumberRange( - -0.5, - Math.max(activeRowCount, 1) - 0.5, - ); - - const timeRange = recentHeatmapTimeRange( - UNIVERSE_HEATMAP_TIME_COLS, - UNIVERSE_HEATMAP_TIME_WINDOW, - ); - - xAxis.visibleRange = new NumberRange(timeRange.start, timeRange.end); - dataSeries.setZValues(zValues); - - const cappedCount = - frame.symbolCount > UNIVERSE_HEATMAP_MAX_ROWS - ? `${UNIVERSE_HEATMAP_MAX_ROWS}/${frame.symbolCount}` - : `${frame.symbolCount}`; - - headerAnnotation.text = `${cappedCount} symbols · focus ${frame.focusSymbol} · ${frame.focus.category || "resonance"}`; - sciChartSurface.invalidateElement(); - }; - - const addData = (raw: Record) => { - if (sciChartSurface.isDeleted) { - return; - } - - const frame = parseResonanceUniverseFrame(raw); - - if (frame === null) { - return; - } - - applyUniverseFrame(frame); - }; - - return { - sciChartSurface, - wasmContext, - addData, - }; -}; diff --git a/frontend/src/components/charts/resonance/init-resonance-xray-chart.ts b/frontend/src/components/charts/resonance/init-resonance-xray-chart.ts deleted file mode 100644 index e87a42b6..00000000 --- a/frontend/src/components/charts/resonance/init-resonance-xray-chart.ts +++ /dev/null @@ -1,400 +0,0 @@ -import { - EAutoRange, - EAxisAlignment, - ECoordinateMode, - EHorizontalAnchorPoint, - EVerticalAnchorPoint, - FastColumnRenderableSeries, - HeatmapColorMap, - NumberRange, - NumericAxis, - Rect, - SciChartSubSurface, - SciChartSurface, - TextAnnotation, - Thickness, - UniformHeatmapDataSeries, - UniformHeatmapRenderableSeries, - XyDataSeries, - zeroArray2D, -} from "scichart"; -import { parseResonanceUniverseFrame } from "#/components/charts/resonance/resonance-universe-frame"; -import { - flattenResonanceStates, - type ResonanceLayerFrame, - recentHeatmapTimeRange, - resonanceChannelLabels, - shiftHeatmapRow, -} from "#/components/charts/resonance/resonance-xray-frame"; -import { appTheme } from "#/components/charts/shared/theme"; -import { ensureSciChartWasm } from "#/lib/utils"; - -const TIME_COLS = 160; -const TIME_WINDOW_COLS = 64; -const MAX_STATE_ROWS = 32; -const MAX_ERROR_ROWS = 8; - -const STATE_RECT = new Rect(0, 0, 1, 0.56); -const ERROR_RECT = new Rect(0, 0.56, 1, 0.26); -const CROSS_RECT = new Rect(0, 0.82, 1, 0.18); - -const activationColorMap = () => - new HeatmapColorMap({ - minimum: -1, - maximum: 1, - gradientStops: [ - { offset: 0, color: appTheme.VividBlue }, - { offset: 0.45, color: "#0b0f14" }, - { offset: 0.55, color: "#0b0f14" }, - { offset: 1, color: appTheme.VividPink }, - ], - }); - -const errorColorMap = () => - new HeatmapColorMap({ - minimum: 0, - maximum: 1, - gradientStops: [ - { offset: 0, color: "#0b0f14" }, - { offset: 0.35, color: appTheme.Indigo }, - { offset: 0.7, color: appTheme.VividOrange }, - { offset: 1, color: appTheme.VividRed }, - ], - }); - -const createHeatmapSubChart = ( - parentSurface: SciChartSurface, - position: Rect, - rowCount: number, - colorMap: HeatmapColorMap, -) => { - const subChart = SciChartSubSurface.createSubSurface(parentSurface, { - position, - padding: new Thickness(8, 8, 8, 8), - background: appTheme.Background, - }); - - const wasmContext = subChart.webAssemblyContext2D; - const zValues = zeroArray2D([rowCount, TIME_COLS]); - const timeRange = recentHeatmapTimeRange(TIME_COLS, TIME_WINDOW_COLS); - - const xAxis = new NumericAxis(wasmContext, { - isVisible: false, - autoRange: EAutoRange.Never, - visibleRange: new NumberRange(timeRange.start, timeRange.end), - }); - - subChart.xAxes.add(xAxis); - - const yAxis = new NumericAxis(wasmContext, { - axisAlignment: EAxisAlignment.Left, - isVisible: false, - autoRange: EAutoRange.Never, - visibleRange: new NumberRange(-0.5, rowCount - 0.5), - }); - - subChart.yAxes.add(yAxis); - - const dataSeries = new UniformHeatmapDataSeries(wasmContext, { - zValues, - xStart: 0, - xStep: 1, - yStart: 0, - yStep: 1, - }); - - const series = new UniformHeatmapRenderableSeries(wasmContext, { - dataSeries, - colorMap, - useLinearTextureFiltering: true, - }); - - subChart.renderableSeries.add(series); - - return { - subChart, - xAxis, - yAxis, - zValues, - dataSeries, - series, - }; -}; - -const createCrossSectionSubChart = (parentSurface: SciChartSurface) => { - const subChart = SciChartSubSurface.createSubSurface(parentSurface, { - position: CROSS_RECT, - padding: new Thickness(8, 8, 4, 48), - background: appTheme.Background, - }); - - const wasmContext = subChart.webAssemblyContext2D; - - subChart.xAxes.add( - new NumericAxis(wasmContext, { - autoRange: EAutoRange.Always, - drawMajorGridLines: false, - drawMinorGridLines: false, - }), - ); - - subChart.yAxes.add( - new NumericAxis(wasmContext, { - autoRange: EAutoRange.Always, - drawMajorGridLines: false, - drawMinorGridLines: false, - }), - ); - - const observationSeries = new XyDataSeries(wasmContext, { - containsNaN: false, - isSorted: true, - }); - - const predictionSeries = new XyDataSeries(wasmContext, { - containsNaN: false, - isSorted: true, - }); - - subChart.renderableSeries.add( - new FastColumnRenderableSeries(wasmContext, { - dataSeries: observationSeries, - fill: `${appTheme.VividSkyBlue}CC`, - strokeThickness: 0, - dataPointWidth: 0.35, - }), - new FastColumnRenderableSeries(wasmContext, { - dataSeries: predictionSeries, - fill: `${appTheme.VividOrange}AA`, - strokeThickness: 0, - dataPointWidth: 0.35, - }), - ); - - return { - subChart, - observationSeries, - predictionSeries, - }; -}; - -const updateCrossSection = ( - observationSeries: XyDataSeries, - predictionSeries: XyDataSeries, - inputLayer: ResonanceLayerFrame | undefined, -) => { - observationSeries.clear(); - predictionSeries.clear(); - - if (inputLayer === undefined) { - return; - } - - for ( - let featureIndex = 0; - featureIndex < inputLayer.state.length; - featureIndex += 1 - ) { - const xPosition = featureIndex * 2; - observationSeries.append(xPosition, inputLayer.state[featureIndex] ?? 0); - predictionSeries.append( - xPosition + 0.65, - inputLayer.prediction[featureIndex] ?? 0, - ); - } -}; - -const replaceChannelLabels = ( - subChart: SciChartSubSurface, - labels: string[], - labelAnnotations: TextAnnotation[], -) => { - for (const annotation of labelAnnotations) { - subChart.annotations.remove(annotation); - } - - labelAnnotations.length = 0; - - for (let rowIndex = 0; rowIndex < labels.length; rowIndex += 1) { - const annotation = new TextAnnotation({ - text: labels[rowIndex] ?? "", - x1: 0.01, - y1: rowIndex, - xCoordinateMode: ECoordinateMode.Relative, - yCoordinateMode: ECoordinateMode.DataValue, - horizontalAnchorPoint: EHorizontalAnchorPoint.Left, - verticalAnchorPoint: EVerticalAnchorPoint.Center, - fontSize: 9, - textColor: "rgba(226,232,240,0.75)", - background: "rgba(11,15,20,0.55)", - }); - - subChart.annotations.add(annotation); - labelAnnotations.push(annotation); - } -}; - -export const initResonanceXRayChart = async ( - rootElement: string | HTMLDivElement, -) => { - await ensureSciChartWasm(); - - const { sciChartSurface, wasmContext } = await SciChartSurface.create( - rootElement, - { - padding: new Thickness(0, 0, 0, 0), - background: appTheme.Background, - freezeWhenOutOfView: false, - }, - ); - - const stateHeatmap = createHeatmapSubChart( - sciChartSurface, - STATE_RECT, - MAX_STATE_ROWS, - activationColorMap(), - ); - - const errorHeatmap = createHeatmapSubChart( - sciChartSurface, - ERROR_RECT, - MAX_ERROR_ROWS, - errorColorMap(), - ); - - const crossSection = createCrossSectionSubChart(sciChartSurface); - - sciChartSurface.xAxes.add( - new NumericAxis(wasmContext, { - isVisible: false, - autoRange: EAutoRange.Never, - visibleRange: new NumberRange(0, 1), - }), - ); - - sciChartSurface.yAxes.add( - new NumericAxis(wasmContext, { - isVisible: false, - autoRange: EAutoRange.Never, - visibleRange: new NumberRange(0, 1), - }), - ); - - const headerAnnotation = new TextAnnotation({ - text: "Resonance X-Ray", - x1: 0, - y1: 0, - xCoordinateMode: ECoordinateMode.Relative, - yCoordinateMode: ECoordinateMode.Relative, - horizontalAnchorPoint: EHorizontalAnchorPoint.Left, - verticalAnchorPoint: EVerticalAnchorPoint.Top, - fontSize: 11, - textColor: "rgba(226,232,240,0.85)", - background: "rgba(11,15,20,0.65)", - }); - - sciChartSurface.annotations.add(headerAnnotation); - - const channelLabelAnnotations: TextAnnotation[] = []; - let errorScale = 1; - let stateScale = 1; - - const addData = (raw: Record) => { - if (sciChartSurface.isDeleted) { - return; - } - - const universe = parseResonanceUniverseFrame(raw); - - if (universe === null) { - return; - } - - const frame = universe.focus; - const flattened = flattenResonanceStates(frame.layers); - const activeStateRows = Math.min(flattened.length, MAX_STATE_ROWS); - - stateScale = Math.max( - stateScale * 0.95, - ...flattened.map((value) => Math.abs(value)), - 1e-6, - ); - - for (let rowIndex = 0; rowIndex < activeStateRows; rowIndex += 1) { - const normalizedState = Math.min( - 1, - Math.max(-1, (flattened[rowIndex] ?? 0) / stateScale), - ); - - shiftHeatmapRow( - stateHeatmap.zValues[rowIndex], - normalizedState, - TIME_COLS, - ); - } - - const activeErrorRows = Math.min(frame.layers.length, MAX_ERROR_ROWS); - errorScale = Math.max( - errorScale * 0.95, - frame.surprise, - ...frame.layers.map((layer) => layer.errorNorm), - 1e-6, - ); - - for (let rowIndex = 0; rowIndex < activeErrorRows; rowIndex += 1) { - const normalizedError = - (frame.layers[rowIndex]?.errorNorm ?? 0) / errorScale; - - shiftHeatmapRow( - errorHeatmap.zValues[rowIndex], - Math.min(1, Math.max(0, normalizedError)), - TIME_COLS, - ); - } - - const timeRange = recentHeatmapTimeRange(TIME_COLS, TIME_WINDOW_COLS); - - stateHeatmap.xAxis.visibleRange = new NumberRange( - timeRange.start, - timeRange.end, - ); - errorHeatmap.xAxis.visibleRange = new NumberRange( - timeRange.start, - timeRange.end, - ); - stateHeatmap.yAxis.visibleRange = new NumberRange( - -0.5, - Math.max(activeStateRows, 1) - 0.5, - ); - errorHeatmap.yAxis.visibleRange = new NumberRange( - -0.5, - Math.max(activeErrorRows, 1) - 0.5, - ); - - stateHeatmap.dataSeries.setZValues(stateHeatmap.zValues); - errorHeatmap.dataSeries.setZValues(errorHeatmap.zValues); - errorHeatmap.series.colorMap.maximum = 1; - - replaceChannelLabels( - stateHeatmap.subChart, - resonanceChannelLabels(frame.layers).slice(0, activeStateRows), - channelLabelAnnotations, - ); - - updateCrossSection( - crossSection.observationSeries, - crossSection.predictionSeries, - frame.layers[0], - ); - - headerAnnotation.text = `${frame.symbol} · focus x-ray · ${frame.category || "resonance"} · surprise ${frame.surprise.toFixed(4)} · energy ${frame.energy.toFixed(4)} · conf ${(frame.confidence * 100).toFixed(1)}%`; - - sciChartSurface.invalidateElement(); - }; - - return { - sciChartSurface, - wasmContext, - addData, - }; -}; diff --git a/frontend/src/components/charts/resonance/latent-camera.test.ts b/frontend/src/components/charts/resonance/latent-camera.test.ts deleted file mode 100644 index 0afaf12f..00000000 --- a/frontend/src/components/charts/resonance/latent-camera.test.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { - constellationCameraFrame, - latentCameraFrame, - latentWorldCameraFrame, -} from "#/components/charts/resonance/latent-camera"; -import { latentMarkerSizes } from "#/components/charts/resonance/resonance-xray-frame"; - -describe("latentCameraFrame", () => { - it("centers the camera on the current head point", () => { - const frame = latentCameraFrame([ - { x: 0.1, y: 0.2, z: 0.3 }, - { x: 0.4, y: 0.5, z: 0.6 }, - ]); - - expect(frame?.target).toEqual({ x: 0.4, y: 0.5, z: 0.6 }); - }); - - it("expands orbit to keep the head marker inside the viewport", () => { - const frame = latentCameraFrame([{ x: 2.5, y: -1.25, z: 0.75 }]); - const markerSizes = latentMarkerSizes(frame?.orbit ?? 0); - - expect(frame?.orbit ?? 0).toBeGreaterThan(markerSizes.head * 2 + 0.75); - }); - - it("frames a multi-symbol constellation around the cloud centroid", () => { - const frame = constellationCameraFrame([ - { x: 0, y: 0, z: 0 }, - { x: 2, y: 1, z: -1 }, - { x: -1, y: 0.5, z: 1.5 }, - ]); - - expect(frame?.target.x).toBeCloseTo(0.5, 2); - expect(frame?.orbit ?? 0).toBeGreaterThan(1); - }); - - it("keeps an outlier symbol inside the visible orbit", () => { - const frame = constellationCameraFrame([ - { x: 0, y: 0, z: 0 }, - { x: 0.1, y: -0.1, z: 0.05 }, - { x: 40, y: 0, z: 0 }, - ]); - - expect(frame?.orbit ?? 0).toBeGreaterThan(20); - }); -}); - -describe("latentWorldCameraFrame", () => { - it("maps data-space targets into SciChart world coordinates", () => { - const frame = latentCameraFrame([{ x: 12, y: -4, z: 8 }]); - - expect(frame).not.toBeNull(); - - const worldFrame = latentWorldCameraFrame(frame as NonNullable); - - expect(worldFrame.worldCenter).toEqual({ - x: frame?.orbit, - y: frame?.orbit, - z: frame?.orbit, - }); - expect(worldFrame.cameraPosition.x).not.toBe(frame?.target.x); - expect(worldFrame.visibleRange.x.min).toBeCloseTo( - (frame?.target.x ?? 0) - (frame?.orbit ?? 0), - ); - }); -}); - -describe("latentMarkerSizes", () => { - it("keeps the head marker smaller than the visible orbit", () => { - const markerSizes = latentMarkerSizes(1); - - expect(markerSizes.head).toBeLessThan(0.05); - expect(markerSizes.trail).toBeLessThan(markerSizes.head); - }); -}); diff --git a/frontend/src/components/charts/resonance/latent-camera.ts b/frontend/src/components/charts/resonance/latent-camera.ts deleted file mode 100644 index e58c57a9..00000000 --- a/frontend/src/components/charts/resonance/latent-camera.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { - type LatentMarkerSizes, - type LatentPoint3D, - latentMarkerSizes, -} from "#/components/charts/resonance/resonance-xray-frame"; - -export type LatentCameraFrame = { - target: LatentPoint3D; - orbit: number; - markerSizes: LatentMarkerSizes; - cameraOffset: LatentPoint3D; -}; - -export type LatentWorldCameraFrame = { - visibleRange: { - x: { min: number; max: number }; - y: { min: number; max: number }; - z: { min: number; max: number }; - }; - worldCenter: LatentPoint3D; - worldDimensions: LatentPoint3D; - cameraPosition: LatentPoint3D; - markerSizes: LatentMarkerSizes; -}; - -const MARKER_MARGIN_FACTOR = 2.75; -const VIEWPORT_INSET_FACTOR = 0.32; -const ORBIT_PADDING_FACTOR = 1.48; - -const maxAxisExtentFromTarget = ( - points: LatentPoint3D[], - target: LatentPoint3D, -): number => { - let maxAxisExtent = 0; - - for (const point of points) { - maxAxisExtent = Math.max( - maxAxisExtent, - Math.abs(point.x - target.x), - Math.abs(point.y - target.y), - Math.abs(point.z - target.z), - ); - } - - return maxAxisExtent; -}; - -const cameraFrameFromTarget = ( - target: LatentPoint3D, - points: LatentPoint3D[], - minOrbitRadius: number, -): LatentCameraFrame => { - const halfExtent = Math.max( - maxAxisExtentFromTarget(points, target), - minOrbitRadius * 0.5, - ); - const provisionalOrbit = Math.max(halfExtent * 2, minOrbitRadius); - const provisionalMarkerSizes = latentMarkerSizes(provisionalOrbit); - const markerMargin = provisionalMarkerSizes.head * MARKER_MARGIN_FACTOR; - const viewportInset = halfExtent * VIEWPORT_INSET_FACTOR; - const orbit = - Math.max(halfExtent + markerMargin, minOrbitRadius) * ORBIT_PADDING_FACTOR + - viewportInset; - - return { - target, - orbit, - markerSizes: latentMarkerSizes(orbit), - cameraOffset: { - x: -0.68, - y: 0.48, - z: 0.68, - }, - }; -}; - -/* -latentCameraFrame keeps the current latent head centered with enough inset -for marker radius and perspective clipping. -*/ -export const latentCameraFrame = ( - points: LatentPoint3D[], - minOrbitRadius = 0.75, -): LatentCameraFrame | null => { - const head = points.at(-1); - - if (head === undefined) { - return null; - } - - return cameraFrameFromTarget(head, points, minOrbitRadius); -}; - -/* -constellationCameraFrame frames all symbols around the cloud centroid. -*/ -export const constellationCameraFrame = ( - points: LatentPoint3D[], - minOrbitRadius = 0.75, -): LatentCameraFrame | null => { - if (points.length === 0) { - return null; - } - - let minX = points[0].x; - let maxX = points[0].x; - let minY = points[0].y; - let maxY = points[0].y; - let minZ = points[0].z; - let maxZ = points[0].z; - - for (let pointIndex = 1; pointIndex < points.length; pointIndex += 1) { - const point = points[pointIndex]; - - minX = Math.min(minX, point.x); - maxX = Math.max(maxX, point.x); - minY = Math.min(minY, point.y); - maxY = Math.max(maxY, point.y); - minZ = Math.min(minZ, point.z); - maxZ = Math.max(maxZ, point.z); - } - - const target = { - x: (minX + maxX) / 2, - y: (minY + maxY) / 2, - z: (minZ + maxZ) / 2, - }; - - return cameraFrameFromTarget(target, points, minOrbitRadius); -}; - -/* -latentWorldCameraFrame maps data-space framing into SciChart world coordinates. -Camera position and target must be world-space, not raw latent values. -*/ -export const latentWorldCameraFrame = ( - frame: LatentCameraFrame, -): LatentWorldCameraFrame => { - const { target, orbit, markerSizes, cameraOffset } = frame; - const worldSpan = orbit * 2; - - return { - visibleRange: { - x: { min: target.x - orbit, max: target.x + orbit }, - y: { min: target.y - orbit, max: target.y + orbit }, - z: { min: target.z - orbit, max: target.z + orbit }, - }, - worldCenter: { x: orbit, y: orbit, z: orbit }, - worldDimensions: { x: worldSpan, y: worldSpan, z: worldSpan }, - cameraPosition: { - x: orbit + cameraOffset.x * orbit, - y: orbit + cameraOffset.y * orbit, - z: orbit + cameraOffset.z * orbit, - }, - markerSizes, - }; -}; diff --git a/frontend/src/components/charts/resonance/resonance-universe-frame.test.ts b/frontend/src/components/charts/resonance/resonance-universe-frame.test.ts deleted file mode 100644 index 3f7f7fc5..00000000 --- a/frontend/src/components/charts/resonance/resonance-universe-frame.test.ts +++ /dev/null @@ -1,130 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { - normalizedSurpriseReading, - parseResonanceUniverseFrame, - sortedUniverseSymbols, -} from "#/components/charts/resonance/resonance-universe-frame"; - -const sampleFocus = { - type: "resonance", - symbol: "ETH/USD", - surprise: 0.9, - energy: 1.2, - confidence: 0.5, - category: "turbulent_resonance", - layers: [ - { - state: [1, 2, 3, 4], - prediction: [0.9, 1.8, 2.9, 3.8], - error_norm: 0.05, - }, - { - state: [0.1, 0.2, 0.3], - prediction: [0.08, 0.18, 0.28], - error_norm: 0.02, - }, - ], -}; - -describe("parseResonanceUniverseFrame", () => { - it("accepts batched resonance universe wire frames", () => { - const frame = parseResonanceUniverseFrame({ - type: "resonance_universe", - ts: "2024-01-01T00:00:00Z", - symbol_count: 2, - focus_symbol: "ETH/USD", - symbols: [ - { - symbol: "BTC/USD", - surprise: 0.2, - energy: 0.4, - confidence: 0.8, - category: "laminar_resonance", - strength: 0.3, - latent: [0.1, 0.2, 0.3], - }, - { - symbol: "ETH/USD", - surprise: 0.9, - energy: 1.2, - confidence: 0.5, - category: "turbulent_resonance", - strength: 0.7, - latent: [0.4, 0.5, 0.6], - }, - ], - focus: { - ...sampleFocus, - symbol: "ETH/USD", - }, - }); - - expect(frame?.symbolCount).toBe(2); - expect(frame?.focusSymbol).toBe("ETH/USD"); - expect(frame?.symbols).toHaveLength(2); - expect(frame?.focus.symbol).toBe("ETH/USD"); - }); - - it("rejects frames with invalid latent vectors", () => { - const frame = parseResonanceUniverseFrame({ - type: "resonance_universe", - ts: "2024-01-01T00:00:00Z", - symbol_count: 1, - focus_symbol: "ETH/USD", - symbols: [ - { - symbol: "ETH/USD", - surprise: 0.9, - energy: 1.2, - confidence: 0.5, - category: "turbulent_resonance", - strength: 0.7, - latent: [0.4, 0.5], - }, - ], - focus: { - ...sampleFocus, - symbol: "ETH/USD", - }, - }); - - expect(frame).toBeNull(); - }); -}); - -describe("sortedUniverseSymbols", () => { - it("orders symbols by descending surprise", () => { - const sorted = sortedUniverseSymbols([ - { - symbol: "BTC/USD", - surprise: 0.2, - energy: 0, - confidence: 0, - category: "", - strength: 0, - latent: [0, 0, 0], - }, - { - symbol: "ETH/USD", - surprise: 0.9, - energy: 0, - confidence: 0, - category: "", - strength: 0, - latent: [0, 0, 0], - }, - ]); - - expect(sorted[0]?.symbol).toBe("ETH/USD"); - }); -}); - -describe("normalizedSurpriseReading", () => { - it("compresses heavy-tailed surprise values into zero-one range", () => { - const low = normalizedSurpriseReading(0.2, 1000); - const high = normalizedSurpriseReading(900, 1000); - - expect(high).toBeGreaterThan(low); - expect(high).toBeLessThanOrEqual(1); - }); -}); diff --git a/frontend/src/components/charts/resonance/resonance-universe-frame.ts b/frontend/src/components/charts/resonance/resonance-universe-frame.ts deleted file mode 100644 index cd4b0e9d..00000000 --- a/frontend/src/components/charts/resonance/resonance-universe-frame.ts +++ /dev/null @@ -1,221 +0,0 @@ -import { - type LatentPoint3D, - parseResonanceXRayFrame, - type ResonanceLayerFrame, - type ResonanceXRayFrame, -} from "#/components/charts/resonance/resonance-xray-frame"; - -export const RESONANCE_LATENT_WIDTH = 3; - -export type ResonanceSymbolSummary = { - symbol: string; - surprise: number; - energy: number; - confidence: number; - category: string; - strength: number; - latent: number[]; -}; - -export type ResonanceUniverseFrame = { - type: "resonance_universe"; - ts: string; - arch: number[]; - symbolCount: number; - focusSymbol: string; - symbols: ResonanceSymbolSummary[]; - focus: ResonanceXRayFrame; -}; - -const finiteNumber = (value: unknown): number | null => { - if (typeof value !== "number" || !Number.isFinite(value)) { - return null; - } - - return value; -}; - -const numberArray = (value: unknown): number[] => { - if (!Array.isArray(value)) { - return []; - } - - const output: number[] = []; - - for (const entry of value) { - const parsed = finiteNumber(entry); - - if (parsed === null) { - continue; - } - - output.push(parsed); - } - - return output; -}; - -/* -latentPointFromVector maps the three-mode latent vector into R3. -*/ -export const latentPointFromVector = ( - latent: number[], -): LatentPoint3D | null => { - if (latent.length !== RESONANCE_LATENT_WIDTH) { - return null; - } - - return { - x: latent[0], - y: latent[1], - z: latent[2], - }; -}; - -const parseSymbolSummary = (value: unknown): ResonanceSymbolSummary | null => { - if (typeof value !== "object" || value === null) { - return null; - } - - const row = value as Record; - const symbol = typeof row.symbol === "string" ? row.symbol.trim() : ""; - const surprise = finiteNumber(row.surprise); - const energy = finiteNumber(row.energy); - const confidence = finiteNumber(row.confidence); - const strength = finiteNumber(row.strength); - const category = typeof row.category === "string" ? row.category : ""; - const latent = numberArray(row.latent); - - if ( - symbol === "" || - surprise === null || - energy === null || - confidence === null || - strength === null || - latent.length !== RESONANCE_LATENT_WIDTH - ) { - return null; - } - - return { - symbol, - surprise, - energy, - confidence, - category, - strength, - latent, - }; -}; - -/* -parseResonanceUniverseFrame normalizes a batched resonance ui wire frame. -*/ -export const parseResonanceUniverseFrame = ( - raw: Record, -): ResonanceUniverseFrame | null => { - if (raw.type !== "resonance_universe") { - return null; - } - - const focusSymbolRaw = - typeof raw.focus_symbol === "string" ? raw.focus_symbol.trim() : ""; - - if (focusSymbolRaw === "") { - return null; - } - - const focusRaw = - typeof raw.focus === "object" && raw.focus !== null - ? (raw.focus as Record) - : null; - - if (focusRaw === null) { - return null; - } - - const focus = parseResonanceXRayFrame(focusRaw); - - if (focus === null || focus.symbol !== focusSymbolRaw) { - return null; - } - - const symbolsRaw = raw.symbols; - - if (!Array.isArray(symbolsRaw) || symbolsRaw.length === 0) { - return null; - } - - const symbols: ResonanceSymbolSummary[] = []; - - for (const symbolRaw of symbolsRaw) { - const summary = parseSymbolSummary(symbolRaw); - - if (summary === null) { - return null; - } - - symbols.push(summary); - } - - const symbolCount = finiteNumber(raw.symbol_count); - - if (symbolCount === null || symbolCount !== symbols.length) { - return null; - } - - const focusPresent = symbols.some( - (summary) => summary.symbol === focusSymbolRaw, - ); - - if (!focusPresent) { - return null; - } - - const ts = typeof raw.ts === "string" ? raw.ts : ""; - const arch = numberArray(raw.arch); - - return { - type: "resonance_universe", - ts, - arch, - symbolCount, - focusSymbol: focusSymbolRaw, - symbols, - focus, - }; -}; - -export const sortedUniverseSymbols = ( - symbols: ResonanceSymbolSummary[], -): ResonanceSymbolSummary[] => { - return [...symbols].sort((left, right) => right.surprise - left.surprise); -}; - -export const normalizedSurpriseReading = ( - surprise: number, - surpriseScale: number, -): number => { - const scale = Math.max(surpriseScale, 1e-6); - const normalized = Math.log1p(Math.max(surprise, 0)) / Math.log1p(scale); - - return Math.min(1, Math.max(0, normalized)); -}; - -export const categoryFill = (category: string): string => { - if (category === "turbulent_resonance") { - return "#ec4899"; - } - - if (category === "laminar_resonance") { - return "#4ade80"; - } - - return "#38bdf8"; -}; - -export const focusXRayLayers = ( - frame: ResonanceUniverseFrame, -): ResonanceLayerFrame[] => { - return frame.focus.layers; -}; diff --git a/frontend/src/components/charts/resonance/resonance-xray-frame.test.ts b/frontend/src/components/charts/resonance/resonance-xray-frame.test.ts deleted file mode 100644 index f1d9d062..00000000 --- a/frontend/src/components/charts/resonance/resonance-xray-frame.test.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { - latentPoint3D, - parseResonanceXRayFrame, - recentHeatmapTimeRange, -} from "#/components/charts/resonance/resonance-xray-frame"; - -describe("latentPoint3D", () => { - it("maps a 3D latent state into phase space", () => { - const point = latentPoint3D([ - { state: [1, 2, 3, 4], prediction: [], errorNorm: 0 }, - { state: [0.2, -0.4, 0.7], prediction: [], errorNorm: 0 }, - ]); - - expect(point).toEqual({ x: 0.2, y: -0.4, z: 0.7 }); - }); - - it("embeds 2D latent states in the xz plane", () => { - const point = latentPoint3D([ - { state: [0.5, -0.25], prediction: [], errorNorm: 0 }, - ]); - - expect(point).toEqual({ x: 0.5, y: 0, z: -0.25 }); - }); -}); - -describe("recentHeatmapTimeRange", () => { - it("anchors the visible window on the latest columns", () => { - const range = recentHeatmapTimeRange(120, 48); - - expect(range.start).toBe(72); - expect(range.end).toBe(120); - }); -}); - -describe("parseResonanceXRayFrame", () => { - it("accepts resonance wire frames with layer snapshots", () => { - const frame = parseResonanceXRayFrame({ - type: "resonance", - symbol: "PF_XBTUSD", - surprise: 0.12, - energy: 0.4, - confidence: 0.88, - category: "laminar_resonance", - layers: [ - { - state: [1, 2, 3, 4], - prediction: [0.9, 1.8, 2.9, 3.8], - error_norm: 0.05, - }, - { - state: [0.1, 0.2, 0.3], - prediction: [0.08, 0.18, 0.28], - error_norm: 0.02, - }, - ], - }); - - expect(frame?.symbol).toBe("PF_XBTUSD"); - expect(frame?.layers).toHaveLength(2); - }); -}); diff --git a/frontend/src/components/charts/resonance/resonance-xray-frame.ts b/frontend/src/components/charts/resonance/resonance-xray-frame.ts deleted file mode 100644 index 54ac0663..00000000 --- a/frontend/src/components/charts/resonance/resonance-xray-frame.ts +++ /dev/null @@ -1,234 +0,0 @@ -export type ResonanceLayerFrame = { - state: number[]; - prediction: number[]; - errorNorm: number; -}; - -export type ResonanceXRayFrame = { - symbol: string; - category: string; - surprise: number; - energy: number; - confidence: number; - layers: ResonanceLayerFrame[]; -}; - -const finiteNumber = (value: unknown): number | null => { - if (typeof value !== "number" || !Number.isFinite(value)) { - return null; - } - - return value; -}; - -const numberArray = (value: unknown): number[] => { - if (!Array.isArray(value)) { - return []; - } - - const output: number[] = []; - - for (const entry of value) { - const parsed = finiteNumber(entry); - - if (parsed === null) { - continue; - } - - output.push(parsed); - } - - return output; -}; - -const parseLayer = (value: unknown): ResonanceLayerFrame | null => { - if (typeof value !== "object" || value === null) { - return null; - } - - const layer = value as Record; - - return { - state: numberArray(layer.state), - prediction: numberArray(layer.prediction), - errorNorm: finiteNumber(layer.error_norm) ?? 0, - }; -}; - -/* -parseResonanceXRayFrame normalizes a resonance ui wire frame for chart ingestion. -*/ -export const parseResonanceXRayFrame = ( - raw: Record, -): ResonanceXRayFrame | null => { - const symbol = typeof raw.symbol === "string" ? raw.symbol.trim() : ""; - - if (symbol === "") { - return null; - } - - const layersRaw = raw.layers; - - if (!Array.isArray(layersRaw) || layersRaw.length === 0) { - return null; - } - - const layers: ResonanceLayerFrame[] = []; - - for (const layerRaw of layersRaw) { - const layer = parseLayer(layerRaw); - - if (layer === null || layer.state.length === 0) { - continue; - } - - layers.push(layer); - } - - if (layers.length === 0) { - return null; - } - - const surprise = finiteNumber(raw.surprise) ?? 0; - const energy = finiteNumber(raw.energy) ?? 0; - const confidence = finiteNumber(raw.confidence) ?? 0; - const category = typeof raw.category === "string" ? raw.category : ""; - - return { - symbol, - category, - surprise, - energy, - confidence, - layers, - }; -}; - -export const flattenResonanceStates = ( - layers: ResonanceLayerFrame[], -): number[] => { - const flattened: number[] = []; - - for (const layer of layers) { - for (const value of layer.state) { - flattened.push(value); - } - } - - return flattened; -}; - -export const resonanceChannelLabels = ( - layers: ResonanceLayerFrame[], -): string[] => { - const inputLabels = ["price", "spread", "volume", "chg"]; - const labels: string[] = []; - - for (let layerIndex = 0; layerIndex < layers.length; layerIndex += 1) { - const layer = layers[layerIndex]; - - for ( - let neuronIndex = 0; - neuronIndex < layer.state.length; - neuronIndex += 1 - ) { - if (layerIndex === 0 && neuronIndex < inputLabels.length) { - labels.push(inputLabels[neuronIndex] ?? `in${neuronIndex}`); - continue; - } - - if (layerIndex === layers.length - 1) { - labels.push(`z${neuronIndex}`); - continue; - } - - labels.push(`h${neuronIndex}`); - } - } - - return labels; -}; - -export const shiftHeatmapRow = ( - row: number[], - value: number, - columnCount: number, -) => { - for (let columnIndex = 0; columnIndex < columnCount - 1; columnIndex += 1) { - row[columnIndex] = row[columnIndex + 1]; - } - - row[columnCount - 1] = value; -}; - -/* -recentHeatmapTimeRange keeps the visible heatmap window on the latest columns. -*/ -export const recentHeatmapTimeRange = ( - columnCount: number, - windowColumns: number, -): { start: number; end: number } => { - const windowSpan = Math.min(Math.max(windowColumns, 1), columnCount); - const startColumn = Math.max(0, columnCount - windowSpan); - - return { start: startColumn, end: columnCount }; -}; - -export type LatentPoint3D = { - x: number; - y: number; - z: number; -}; - -/* -latentTopLayer returns the settled top latent layer from a resonance frame. -*/ -export const latentTopLayer = ( - layers: ResonanceLayerFrame[], -): ResonanceLayerFrame | undefined => { - return layers.at(-1); -}; - -/* -latentPoint3D maps the top latent state into R3 for phase-portrait rendering. -*/ -export const latentPoint3D = (layers: ResonanceLayerFrame[]): LatentPoint3D => { - const topLayer = latentTopLayer(layers); - - if (topLayer === undefined || topLayer.state.length === 0) { - return { x: 0, y: 0, z: 0 }; - } - - const state = topLayer.state; - - if (state.length === 1) { - return { x: state[0], y: 0, z: 0 }; - } - - if (state.length === 2) { - return { x: state[0], y: 0, z: state[1] }; - } - - return { - x: state[0], - y: state[1], - z: state[2], - }; -}; - -export type LatentMarkerSizes = { - head: number; - trail: number; -}; - -/* -latentMarkerSizes scales 3D point markers relative to the fitted camera orbit. -*/ -export const latentMarkerSizes = (orbitRadius: number): LatentMarkerSizes => { - const orbit = Math.max(orbitRadius, 1e-6); - - return { - head: orbit * 0.025, - trail: orbit * 0.01, - }; -}; diff --git a/frontend/src/components/charts/shared/financial-chart-utils.test.ts b/frontend/src/components/charts/shared/financial-chart-utils.test.ts deleted file mode 100644 index a694e640..00000000 --- a/frontend/src/components/charts/shared/financial-chart-utils.test.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { NumberRange, type OhlcDataSeries } from "scichart"; -import { describe, expect, it } from "vitest"; - -import { - candleChartXExtents, - isViewportFollowingLiveEdge, - priceLabelDecimals, - resolveFollowVisibleRange, - shiftTrailingVisibleRange, - visibleRangesMatch, -} from "#/components/charts/shared/financial-chart-utils"; - -const mockOhlc = (xValues: number[]): OhlcDataSeries => - ({ - count: () => xValues.length, - getNativeXValues: () => ({ - get: (index: number) => xValues[index], - }), - }) as OhlcDataSeries; - -describe("candleChartXExtents", () => { - it("pads a single live bar so candles have horizontal width", () => { - const sec = 1_747_000_000; - const { min, max } = candleChartXExtents(sec, sec, 1); - - expect(min).toBeLessThan(sec); - expect(max).toBeGreaterThan(sec); - expect(max - min).toBeGreaterThan(0); - }); -}); - -describe("shiftTrailingVisibleRange", () => { - it("preserves zoom span while keeping the latest bar in view", () => { - const shifted = shiftTrailingVisibleRange(1000, 1060, 1200, 60); - - expect(shifted.max - shifted.min).toBe(60); - expect(shifted.max).toBeGreaterThan(1200); - }); - - it("keeps earlier bars visible when the prior span was padded for one bar", () => { - const firstBarX = 1_780_627_020; - const secondBarX = firstBarX + 60; - const initialRange = candleChartXExtents(firstBarX, firstBarX, 1); - const shifted = shiftTrailingVisibleRange( - initialRange.min, - initialRange.max, - secondBarX, - 60, - ); - - expect(shifted.min).toBeLessThanOrEqual(firstBarX); - expect(shifted.max).toBeGreaterThanOrEqual(secondBarX); - }); -}); - -describe("isViewportFollowingLiveEdge", () => { - it("treats a trailing viewport as following live data", () => { - const priorLastX = 1_780_627_020; - const range = new NumberRange(priorLastX - 120, priorLastX + 30); - - expect(isViewportFollowingLiveEdge(range, priorLastX, 60)).toBe(true); - }); - - it("treats a historical viewport as user-controlled", () => { - const priorLastX = 1_780_627_020; - const range = new NumberRange(priorLastX - 600_000, priorLastX - 300_000); - - expect(isViewportFollowingLiveEdge(range, priorLastX, 60)).toBe(false); - }); -}); - -describe("visibleRangesMatch", () => { - it("matches programmatic viewport updates within epsilon", () => { - const left = new NumberRange(1000, 2000); - const right = new NumberRange(1000.5, 2000.5); - - expect(visibleRangesMatch(left, right)).toBe(true); - }); - - it("detects user viewport changes", () => { - const left = new NumberRange(1000, 2000); - const right = new NumberRange(1500, 2500); - - expect(visibleRangesMatch(left, right)).toBe(false); - }); -}); - -describe("resolveFollowVisibleRange", () => { - it("shifts the live viewport when a new bar arrives", () => { - const firstBarX = 1_780_627_020; - const secondBarX = firstBarX + 60; - const initialRange = resolveFollowVisibleRange( - mockOhlc([firstBarX]), - "initial", - ); - const liveRange = resolveFollowVisibleRange( - mockOhlc([firstBarX, secondBarX]), - "live", - initialRange ?? undefined, - ); - - expect(liveRange).not.toBeNull(); - expect(liveRange?.max).toBeGreaterThanOrEqual(secondBarX); - }); -}); - -describe("priceLabelDecimals", () => { - it("uses finer precision for narrow live price spans", () => { - expect(priceLabelDecimals(0.05)).toBe(4); - expect(priceLabelDecimals(5)).toBe(3); - expect(priceLabelDecimals(500)).toBe(1); - expect(priceLabelDecimals(5000)).toBe(0); - }); -}); diff --git a/frontend/src/components/charts/shared/financial-chart-utils.ts b/frontend/src/components/charts/shared/financial-chart-utils.ts deleted file mode 100644 index be709df9..00000000 --- a/frontend/src/components/charts/shared/financial-chart-utils.ts +++ /dev/null @@ -1,348 +0,0 @@ -import { - AnnotationHoverModifier, - DiscontinuousDateAxis, - EAutoRange, - EAxisAlignment, - ECursorStyle, - ENumericFormat, - EXyDirection, - FastCandlestickRenderableSeries, - FastColumnRenderableSeries, - MouseWheelZoomModifier, - NumberRange, - NumericAxis, - OhlcDataSeries, - SciChartSurface, - Thickness, - type TSciChart, - XyDataSeries, - ZoomExtentsModifier, -} from "scichart"; -import { SciTraderDarkTheme } from "scichart-financial-tools"; - -import { VolumePaletteProvider } from "#/components/charts/shared/volume-palette-provider"; - -export const Y_AXIS_VOLUME_ID = "Y_AXIS_VOLUME_ID"; -export const VISIBLE_CANDLE_COUNT = 300; -const TRADE_FIFO_CAPACITY = VISIBLE_CANDLE_COUNT * 2; -const DEFAULT_BAR_STEP_SEC = 60; -const DEFAULT_PAD_SEC = 60; -export const DEFAULT_RANGE_MATCH_EPSILON_SEC = 1; - -export const candleChartXExtents = ( - firstX: number, - lastX: number, - barCountInWindow: number, - priorBarX?: number, -): { min: number; max: number } => { - const barStep = - barCountInWindow > 1 && lastX > firstX - ? (lastX - firstX) / (barCountInWindow - 1) - : priorBarX !== undefined - ? lastX - priorBarX - : DEFAULT_BAR_STEP_SEC; - const pad = Math.max(barStep * 2, DEFAULT_PAD_SEC); - - return { min: firstX - pad, max: lastX + pad }; -}; - -export const shiftTrailingVisibleRange = ( - visibleMin: number, - visibleMax: number, - lastX: number, - barStep: number, -): { min: number; max: number } => { - const followTolerance = Math.max(barStep * 2, DEFAULT_PAD_SEC); - const span = visibleMax - visibleMin; - const pad = followTolerance / 2; - - return { min: lastX + pad - span, max: lastX + pad }; -}; - -/** - * Returns the live-follow tolerance in seconds. - * - * @param barStep Bar spacing in seconds. - * @returns The greater of barStep * 2 and DEFAULT_PAD_SEC, in seconds. - */ -export const liveFollowToleranceSec = (barStep: number): number => - Math.max(barStep * 2, DEFAULT_PAD_SEC); - -/** - * Reports whether the current viewport is still tracking the live edge. - * - * @param currentRange Visible x-axis range in seconds; currentRange.max is the visible right edge. - * @param priorLastX Previous final bar x value in seconds. - * @param barStep Bar spacing in seconds. - * @returns True when currentRange.max is within liveFollowToleranceSec(barStep) of priorLastX. - */ -export const isViewportFollowingLiveEdge = ( - currentRange: NumberRange, - priorLastX: number, - barStep: number, -): boolean => { - const followTolerance = liveFollowToleranceSec(barStep); - - return currentRange.max >= priorLastX - followTolerance; -}; - -export const visibleRangesMatch = ( - left: NumberRange, - right: NumberRange, - epsilon = DEFAULT_RANGE_MATCH_EPSILON_SEC, -): boolean => - Math.abs(left.min - right.min) <= epsilon && - Math.abs(left.max - right.max) <= epsilon; - -export const resolveFollowVisibleRange = ( - ohlc: OhlcDataSeries, - mode: "initial" | "live", - currentRange?: NumberRange, -): NumberRange | null => { - const barCount = ohlc.count(); - - if (barCount <= 0) { - return null; - } - - const nativeX = ohlc.getNativeXValues(); - const lastIndex = barCount - 1; - const lastX = nativeX.get(lastIndex); - const barStep = - lastIndex > 0 ? lastX - nativeX.get(lastIndex - 1) : DEFAULT_BAR_STEP_SEC; - - if (mode === "live" && currentRange !== undefined) { - const shifted = shiftTrailingVisibleRange( - currentRange.min, - currentRange.max, - lastX, - barStep, - ); - - return new NumberRange(shifted.min, shifted.max); - } - - const firstIndex = Math.max(0, lastIndex - VISIBLE_CANDLE_COUNT + 1); - const firstX = nativeX.get(firstIndex); - const priorBarX = lastIndex > 0 ? nativeX.get(lastIndex - 1) : undefined; - const { min, max } = candleChartXExtents( - firstX, - lastX, - lastIndex - firstIndex + 1, - priorBarX, - ); - - return new NumberRange(min, max); -}; - -const FOREGROUND_COLOR = "#F5F5F5"; -const VIVID_GREEN = "#67BDAF"; -const VIVID_RED = "#C52E60"; - -export type FinancialChartContext = { - sciChartSurface: SciChartSurface; - wasmContext: TSciChart; - xAxis: DiscontinuousDateAxis; - yAxis: NumericAxis; - candlestickSeries: FastCandlestickRenderableSeries; - volumeSeries: FastColumnRenderableSeries; - ohlc: OhlcDataSeries; - volume: XyDataSeries; -}; - -export const createFinancialChartSurface = async ( - rootElement: HTMLDivElement, - title: string, -): Promise => { - const { sciChartSurface, wasmContext } = await SciChartSurface.create( - rootElement, - { - theme: new SciTraderDarkTheme(), - padding: new Thickness(10, 10, 10, 10), - freezeWhenOutOfView: true, - }, - ); - - const xAxis = new DiscontinuousDateAxis(wasmContext, { - axisAlignment: EAxisAlignment.Bottom, - autoRange: EAutoRange.Always, - cursorLabelFormat: ENumericFormat.Date_HHMM, - drawMajorBands: false, - drawMinorGridLines: false, - useNativeText: true, - }); - - const yAxis = new NumericAxis(wasmContext, { - axisAlignment: EAxisAlignment.Right, - growBy: new NumberRange(0.1, 0.2), - labelFormat: ENumericFormat.Decimal, - labelPrefix: "$", - autoRange: EAutoRange.Always, - drawMajorBands: false, - drawMinorGridLines: false, - useNativeText: true, - }); - - sciChartSurface.xAxes.add(xAxis); - sciChartSurface.yAxes.add(yAxis); - sciChartSurface.yAxes.add( - new NumericAxis(wasmContext, { - id: Y_AXIS_VOLUME_ID, - axisAlignment: EAxisAlignment.Left, - growBy: new NumberRange(0, 4), - isVisible: false, - autoRange: EAutoRange.Always, - }), - ); - - const ohlc = new OhlcDataSeries(wasmContext, { - dataSeriesName: title, - dataIsSortedInX: true, - dataEvenlySpacedInX: true, - containsNaN: false, - fifoCapacity: TRADE_FIFO_CAPACITY, - capacity: TRADE_FIFO_CAPACITY, - }); - - const volume = new XyDataSeries(wasmContext, { - dataSeriesName: "Volume", - dataIsSortedInX: true, - dataEvenlySpacedInX: true, - containsNaN: false, - fifoCapacity: TRADE_FIFO_CAPACITY, - capacity: TRADE_FIFO_CAPACITY, - }); - - const candlestickSeries = new FastCandlestickRenderableSeries(wasmContext, { - id: "Candles", - dataSeries: ohlc, - stroke: FOREGROUND_COLOR, - strokeThickness: 1, - dataPointWidth: 0.8, - brushUp: `${VIVID_GREEN}CC`, - brushDown: `${VIVID_RED}CC`, - strokeUp: VIVID_GREEN, - strokeDown: VIVID_RED, - }); - - const volumeSeries = new FastColumnRenderableSeries(wasmContext, { - dataSeries: volume, - strokeThickness: 0, - dataPointWidth: 0.65, - yAxisId: Y_AXIS_VOLUME_ID, - paletteProvider: new VolumePaletteProvider( - ohlc, - `${VIVID_GREEN}66`, - `${VIVID_RED}66`, - ), - }); - - sciChartSurface.renderableSeries.add(candlestickSeries, volumeSeries); - addDefaultFinancialModifiers(sciChartSurface); - configureFinancialPriceAxis(yAxis, ohlc); - - return { - sciChartSurface, - wasmContext, - xAxis, - yAxis, - candlestickSeries, - volumeSeries, - ohlc, - volume, - }; -}; - -export const addDefaultFinancialModifiers = ( - sciChartSurface: SciChartSurface, -) => { - sciChartSurface.chartModifiers.add( - new MouseWheelZoomModifier({ xyDirection: EXyDirection.XDirection }), - new ZoomExtentsModifier({ xyDirection: EXyDirection.XDirection }), - new AnnotationHoverModifier({ - enableHover: true, - enableCursor: true, - idleCursor: ECursorStyle.Crosshair, - }), - ); -}; - -export const followLatestCandleRange = ( - xAxis: DiscontinuousDateAxis, - ohlc: OhlcDataSeries, - mode: "initial" | "live" = "live", -) => { - const nextRange = resolveFollowVisibleRange(ohlc, mode, xAxis.visibleRange); - - if (nextRange === null) { - return; - } - - xAxis.visibleRange = nextRange; -}; - -export const refreshFinancialPriceAxis = ( - yAxis: NumericAxis, - ohlc: OhlcDataSeries, -) => { - const barCount = ohlc.count(); - - if (barCount <= 0) { - return; - } - - // Scan only the VISIBLE window: this runs on every candle update - // (including in-place updates of the last bar), so a full-history scan was - // O(n) per tick and O(n²) over a session. The label precision only ever - // reflects what is on screen anyway — the chart follows the tail. - const nativeHigh = ohlc.getNativeHighValues(); - const nativeLow = ohlc.getNativeLowValues(); - const firstIndex = Math.max(0, barCount - VISIBLE_CANDLE_COUNT); - let minLow = Number.POSITIVE_INFINITY; - let maxHigh = Number.NEGATIVE_INFINITY; - - for (let index = firstIndex; index < barCount; index++) { - minLow = Math.min(minLow, nativeLow.get(index)); - maxHigh = Math.max(maxHigh, nativeHigh.get(index)); - } - - const span = Math.max(maxHigh - minLow, maxHigh * 1e-8); - const labelDecimals = priceLabelDecimals(span); - const cursorDecimals = labelDecimals + 1; - const formatPrice = (value: number) => `$${value.toFixed(labelDecimals)}`; - - yAxis.labelProvider.formatLabel = formatPrice; - yAxis.labelProvider.formatCursorLabel = (value: number) => - `$${value.toFixed(cursorDecimals)}`; -}; - -export const priceLabelDecimals = (span: number): number => { - if (span >= 1000) { - return 0; - } - - if (span >= 100) { - return 1; - } - - if (span >= 10) { - return 2; - } - - if (span >= 1) { - return 3; - } - - if (span >= 0.01) { - return 4; - } - - return 6; -}; - -const configureFinancialPriceAxis = ( - yAxis: NumericAxis, - ohlc: OhlcDataSeries, -) => { - refreshFinancialPriceAxis(yAxis, ohlc); -}; diff --git a/frontend/src/components/charts/shared/theme.ts b/frontend/src/components/charts/shared/theme.ts deleted file mode 100644 index 533fba92..00000000 --- a/frontend/src/components/charts/shared/theme.ts +++ /dev/null @@ -1,161 +0,0 @@ - -import type { IThemeProvider } from "scichart"; -import { SciChartJsNavyTheme } from "scichart"; - -const getCssColor = (cssVar: string, fallback: string): string => { - if (typeof document === "undefined") { - return fallback; - } - const cssValue = getComputedStyle(document.documentElement) - .getPropertyValue(cssVar) - .trim(); - return cssValue || fallback; -}; - -type TRgbColor = { r: number; g: number; b: number }; - -const parseCssColorToRgb = (color: string): TRgbColor | undefined => { - const trimmed = color.trim(); - - if (trimmed.startsWith("#")) { - let hex = trimmed.slice(1); - if (hex.length === 3 || hex.length === 4) { - hex = hex - .slice(0, 3) - .split("") - .map((channel) => channel + channel) - .join(""); - } else if (hex.length === 6 || hex.length === 8) { - hex = hex.slice(0, 6); - } else { - return undefined; - } - - if (!/^[0-9a-fA-F]{6}$/.test(hex)) { - return undefined; - } - - return { - r: Number.parseInt(hex.slice(0, 2), 16), - g: Number.parseInt(hex.slice(2, 4), 16), - b: Number.parseInt(hex.slice(4, 6), 16), - }; - } - - const rgbMatch = trimmed.match(/^rgba?\((.+)\)$/i); - if (!rgbMatch) { - return undefined; - } - - const channels = rgbMatch[1] - .split(",") - .slice(0, 3) - .map((channel) => Number.parseFloat(channel.trim())); - - if ( - channels.length !== 3 || - channels.some((channel) => !Number.isFinite(channel)) - ) { - return undefined; - } - - const clamp = (value: number) => Math.max(0, Math.min(255, value)); - - return { - r: clamp(channels[0]), - g: clamp(channels[1]), - b: clamp(channels[2]), - }; -}; - -const getPerceivedBrightness = (color: string): number | undefined => { - const rgb = parseCssColorToRgb(color); - if (!rgb) return undefined; - - // WCAG-adjacent perceptual weighting for quick dark/light detection. - return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000; -}; - -export interface AppThemeBase { - SciChartJsTheme: IThemeProvider; - - // general colors - isDark: boolean; - ForegroundColor: string; - Background: string; - - // Series colors - VividSkyBlue: string; - VividPink: string; - VividTeal: string; - VividOrange: string; - VividBlue: string; - VividPurple: string; - VividGreen: string; - VividRed: string; - - MutedSkyBlue: string; - MutedPink: string; - MutedTeal: string; - MutedOrange: string; - MutedBlue: string; - MutedPurple: string; - MutedRed: string; - - PaleSkyBlue: string; - PalePink: string; - PaleTeal: string; - PaleOrange: string; - PaleBlue: string; - PalePurple: string; -} - -export class SciChart2022AppTheme implements AppThemeBase { - SciChartJsTheme = new SciChartJsNavyTheme(); - - // Dynamic colors - get isDark() { - const brightness = getPerceivedBrightness(this.Background); - return brightness === undefined || brightness < 128; - } - get TextColor() { - return this.ForegroundColor; - } - get ForegroundColor() { - return getCssColor("--text", "#F5F5F5"); - } - get Background() { - return getCssColor("--bg-chart", this.SciChartJsTheme.sciChartBackground); - } - - // Series colors - VividSkyBlue = "#50C7E0"; - VividPink = "#EC0F6C"; - VividTeal = "#30BC9A"; - VividOrange = "#F48420"; - VividBlue = "#364BA0"; - VividPurple = "#882B91"; - VividGreen = "#67BDAF"; - VividRed = "#C52E60"; - - DarkIndigo = "#14233C"; - Indigo = "#264B93"; - - MutedSkyBlue = "#83D2F5"; - MutedPink = "#DF69A8"; - MutedTeal = "#7BCAAB"; - MutedOrange = "#E7C565"; - MutedBlue = "#537ABD"; - MutedPurple = "#A16DAE"; - MutedRed = "#DC7969"; - - PaleSkyBlue = "#E4F5FC"; - PalePink = "#EEB3D2"; - PaleTeal = "#B9E0D4"; - PaleOrange = "#F1CFB5"; - PaleBlue = "#B5BEDF"; - PalePurple = "#CFB4D5"; -} - -export const appTheme = new SciChart2022AppTheme(); - diff --git a/frontend/src/components/charts/shared/volume-palette-provider.ts b/frontend/src/components/charts/shared/volume-palette-provider.ts deleted file mode 100644 index a39cfccc..00000000 --- a/frontend/src/components/charts/shared/volume-palette-provider.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { - EBaseType, - EFillPaletteMode, - EPaletteProviderType, - type IFillPaletteProvider, - type IPointMetadata, - type IRenderableSeries, - type OhlcDataSeries, - parseColorToUIntArgb, - registerType, - type TPaletteProviderDefinition, -} from "scichart"; - -const VOLUME_PALETTE_PROVIDER_TYPE = "TradingAnnotationVolumePaletteProvider"; -const VIVID_GREEN = "#67BDAF"; -const VIVID_RED = "#C52E60"; - -export class VolumePaletteProvider implements IFillPaletteProvider { - public readonly fillPaletteMode: EFillPaletteMode = EFillPaletteMode.SOLID; - private readonly ohlc: OhlcDataSeries; - private readonly upColorArgb: number; - private readonly downColorArgb: number; - - constructor(ohlc: OhlcDataSeries, upColor: string, downColor: string) { - this.ohlc = ohlc; - this.upColorArgb = parseColorToUIntArgb(upColor); - this.downColorArgb = parseColorToUIntArgb(downColor); - } - - public onAttached(_parentSeries: IRenderableSeries): void {} - - public onDetached(): void {} - - public overrideFillArgb( - _xValue: number, - _yValue: number, - index: number, - _opacity?: number, - _metadata?: IPointMetadata, - ): number { - const nativeOpen = this.ohlc.getNativeOpenValues(); - const nativeClose = this.ohlc.getNativeCloseValues(); - const open = nativeOpen.get(index); - const close = nativeClose.get(index); - - if (close >= open) { - return this.upColorArgb; - } - - return this.downColorArgb; - } - - public overrideStrokeArgb( - xValue: number, - yValue: number, - index: number, - opacity?: number, - metadata?: IPointMetadata, - ): number { - return this.overrideFillArgb(xValue, yValue, index, opacity, metadata); - } - - public toJSON(): TPaletteProviderDefinition { - const barCount = this.ohlc.count(); - const nativeOpen = this.ohlc.getNativeOpenValues(); - const nativeClose = this.ohlc.getNativeCloseValues(); - const isUpByIndex = Array.from({ length: barCount }, (_, pointIndex) => { - const open = nativeOpen.get(pointIndex); - const close = nativeClose.get(pointIndex); - - return close >= open; - }); - - return { - type: EPaletteProviderType.Custom, - customType: VOLUME_PALETTE_PROVIDER_TYPE, - options: { - isUpByIndex, - upColor: `${VIVID_GREEN}66`, - downColor: `${VIVID_RED}66`, - }, - }; - } -} - -class DeserializedVolumePaletteProvider implements IFillPaletteProvider { - public readonly fillPaletteMode: EFillPaletteMode = EFillPaletteMode.SOLID; - private readonly isUpByIndex: boolean[]; - private readonly upColorArgb: number; - private readonly downColorArgb: number; - - constructor(isUpByIndex: boolean[], upColor: string, downColor: string) { - this.isUpByIndex = isUpByIndex; - this.upColorArgb = parseColorToUIntArgb(upColor); - this.downColorArgb = parseColorToUIntArgb(downColor); - } - - public onAttached(_parentSeries: IRenderableSeries): void {} - - public onDetached(): void {} - - public overrideFillArgb( - _xValue: number, - _yValue: number, - index: number, - _opacity?: number, - _metadata?: IPointMetadata, - ): number { - if (this.isUpByIndex[index]) { - return this.upColorArgb; - } - - return this.downColorArgb; - } - - public overrideStrokeArgb( - xValue: number, - yValue: number, - index: number, - opacity?: number, - metadata?: IPointMetadata, - ): number { - return this.overrideFillArgb(xValue, yValue, index, opacity, metadata); - } - - public toJSON(): TPaletteProviderDefinition { - return { - type: EPaletteProviderType.Custom, - customType: VOLUME_PALETTE_PROVIDER_TYPE, - options: { - isUpByIndex: this.isUpByIndex, - upColor: `${VIVID_GREEN}66`, - downColor: `${VIVID_RED}66`, - }, - }; - } -} - -registerType( - EBaseType.PaletteProvider, - VOLUME_PALETTE_PROVIDER_TYPE, - (options?: { isUpByIndex?: boolean[] }) => { - const isUpByIndex = options?.isUpByIndex ?? []; - - return new DeserializedVolumePaletteProvider( - isUpByIndex, - `${VIVID_GREEN}66`, - `${VIVID_RED}66`, - ); - }, - true, -); diff --git a/frontend/src/components/charts/spider/init.ts b/frontend/src/components/charts/spider/init.ts deleted file mode 100644 index 56135108..00000000 --- a/frontend/src/components/charts/spider/init.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { - EAutoRange, - EColor, - ENumericFormat, - EPolarAxisMode, - EPolarGridlineMode, - EPolarLabelMode, - NumberRange, - PolarCategoryAxis, - PolarMountainRenderableSeries, - PolarNumericAxis, - SciChartPolarSurface, - XyDataSeries, -} from "scichart"; -import { appTheme } from "#/components/charts/spider/theme"; -import { ensureSciChartWasm } from "#/lib/utils"; - -const REGIME_MARKET_SYMBOL = "market"; - -/* -drawSignalSpider renders a live radar of cross-section mean regime strengths: -volatility, trend, bullish, bearish, and choppiness on a 0-100 radius. -*/ -export const drawSignalSpider = async ( - rootElement: string | HTMLDivElement, - labels: string[], - axes: string[], -) => { - await ensureSciChartWasm(); - - const { sciChartSurface, wasmContext } = await SciChartPolarSurface.create( - rootElement, - { - theme: appTheme.SciChartJsTheme, - freezeWhenOutOfView: false, - }, - ); - - const radialYAxis = new PolarNumericAxis(wasmContext, { - polarAxisMode: EPolarAxisMode.Radial, - gridlineMode: EPolarGridlineMode.Polygons, - useNativeText: true, - autoRange: EAutoRange.Never, - visibleRange: new NumberRange(0, 100), - majorGridLineStyle: { - color: EColor.BackgroundColor, - strokeThickness: 1, - strokeDashArray: [5, 5], - }, - drawLabels: false, - drawMinorGridLines: false, - drawMajorTickLines: false, - drawMinorTickLines: false, - startAngle: Math.PI / 2, - innerRadius: 0, - }); - sciChartSurface.yAxes.add(radialYAxis); - - const angularXAxis = new PolarCategoryAxis(wasmContext, { - polarAxisMode: EPolarAxisMode.Angular, - labels, - majorGridLineStyle: { - color: EColor.BackgroundColor, - strokeThickness: 1, - strokeDashArray: [5, 5], - }, - flippedCoordinates: true, - drawMinorGridLines: false, - useNativeText: true, - polarLabelMode: EPolarLabelMode.Horizontal, - labelFormat: ENumericFormat.NoFormat, - startAngle: Math.PI / 2, - }); - sciChartSurface.xAxes.add(angularXAxis); - - // +1 closes the loop so the first and last petal join without overlap. - const xValues = Array.from( - { length: labels.length + 1 }, - (_, index) => index, - ); - const dataSeries = new XyDataSeries(wasmContext, { - xValues, - yValues: new Array(labels.length + 1).fill(0), - dataSeriesName: "Confidence", - dataIsSortedInX: true, - dataEvenlySpacedInX: true, - containsNaN: false, - }); - - sciChartSurface.renderableSeries.add( - new PolarMountainRenderableSeries(wasmContext, { - dataSeries, - stroke: appTheme.VividSkyBlue, - fill: `${appTheme.VividSkyBlue}30`, - strokeThickness: 3, - }), - ); - - sciChartSurface.background = "transparent"; - - const addData = (frame: Record) => { - const symbol = frame.symbol; - - if (typeof symbol === "string" && symbol !== REGIME_MARKET_SYMBOL) { - return; - } - - if (sciChartSurface.isDeleted) { - return; - } - - const values = axes.map((axis) => { - const value = frame[axis]; - - return ( - (typeof value === "number" && Number.isFinite(value) ? value : 0) * 100 - ); - }); - const closed = [...values, values[0] ?? 0]; - const nativeY = dataSeries.getNativeYValues(); - - for (let index = 0; index < closed.length; index++) { - nativeY.set(index, closed[index]); - } - - sciChartSurface.invalidateElement(); - }; - - return { - sciChartSurface, - wasmContext, - addData, - }; -}; diff --git a/frontend/src/components/charts/spider/spider.tsx b/frontend/src/components/charts/spider/spider.tsx deleted file mode 100644 index 98edcbe6..00000000 --- a/frontend/src/components/charts/spider/spider.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { memo } from "react"; -import { SciChartReact } from "scichart-react"; -import { appStore } from "#/collections/app"; -import { drawSignalSpider } from "#/components/charts/spider/init"; - -export const SpiderChart = memo(function SpiderChart({ - sources, - labels, -}: { - sources: string[]; - labels: Record; -}) { - return ( - - drawSignalSpider( - rootElement, - sources.map((source) => labels[source] ?? source), - sources, - ) - } - onInit={(result) => { - appStore.actions.updateRegimeUpdater(result.addData); - - return () => appStore.actions.updateRegimeUpdater(null); - }} - className="h-full w-full" - style={{ width: "100%", height: "100%" }} - /> - ); -}); diff --git a/frontend/src/components/charts/spider/theme.ts b/frontend/src/components/charts/spider/theme.ts deleted file mode 100644 index e0aa62f6..00000000 --- a/frontend/src/components/charts/spider/theme.ts +++ /dev/null @@ -1,159 +0,0 @@ -import type { IThemeProvider } from "scichart"; -import { SciChartJsNavyTheme } from "scichart"; - -const getCssColor = (cssVar: string, fallback: string): string => { - if (typeof document === "undefined") { - return fallback; - } - const cssValue = getComputedStyle(document.documentElement) - .getPropertyValue(cssVar) - .trim(); - return cssValue || fallback; -}; - -type TRgbColor = { r: number; g: number; b: number }; - -const parseCssColorToRgb = (color: string): TRgbColor | undefined => { - const trimmed = color.trim(); - - if (trimmed.startsWith("#")) { - let hex = trimmed.slice(1); - if (hex.length === 3 || hex.length === 4) { - hex = hex - .slice(0, 3) - .split("") - .map((channel) => channel + channel) - .join(""); - } else if (hex.length === 6 || hex.length === 8) { - hex = hex.slice(0, 6); - } else { - return undefined; - } - - if (!/^[0-9a-fA-F]{6}$/.test(hex)) { - return undefined; - } - - return { - r: Number.parseInt(hex.slice(0, 2), 16), - g: Number.parseInt(hex.slice(2, 4), 16), - b: Number.parseInt(hex.slice(4, 6), 16), - }; - } - - const rgbMatch = trimmed.match(/^rgba?\((.+)\)$/i); - if (!rgbMatch) { - return undefined; - } - - const channels = rgbMatch[1] - .split(",") - .slice(0, 3) - .map((channel) => Number.parseFloat(channel.trim())); - - if ( - channels.length !== 3 || - channels.some((channel) => !Number.isFinite(channel)) - ) { - return undefined; - } - - const clamp = (value: number) => Math.max(0, Math.min(255, value)); - - return { - r: clamp(channels[0]), - g: clamp(channels[1]), - b: clamp(channels[2]), - }; -}; - -const getPerceivedBrightness = (color: string): number | undefined => { - const rgb = parseCssColorToRgb(color); - if (!rgb) return undefined; - - // WCAG-adjacent perceptual weighting for quick dark/light detection. - return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000; -}; - -export interface AppThemeBase { - SciChartJsTheme: IThemeProvider; - - // general colors - isDark: boolean; - ForegroundColor: string; - Background: string; - - // Series colors - VividSkyBlue: string; - VividPink: string; - VividTeal: string; - VividOrange: string; - VividBlue: string; - VividPurple: string; - VividGreen: string; - VividRed: string; - - MutedSkyBlue: string; - MutedPink: string; - MutedTeal: string; - MutedOrange: string; - MutedBlue: string; - MutedPurple: string; - MutedRed: string; - - PaleSkyBlue: string; - PalePink: string; - PaleTeal: string; - PaleOrange: string; - PaleBlue: string; - PalePurple: string; -} - -export class SciChart2022AppTheme implements AppThemeBase { - SciChartJsTheme = new SciChartJsNavyTheme(); - - // Dynamic colors - get isDark() { - const brightness = getPerceivedBrightness(this.Background); - return brightness === undefined || brightness < 128; - } - get TextColor() { - return this.ForegroundColor; - } - get ForegroundColor() { - return getCssColor("--text", "#F5F5F5"); - } - get Background() { - return getCssColor("--bg-chart", this.SciChartJsTheme.sciChartBackground); - } - - // Series colors - VividSkyBlue = "#50C7E0"; - VividPink = "#EC0F6C"; - VividTeal = "#30BC9A"; - VividOrange = "#F48420"; - VividBlue = "#364BA0"; - VividPurple = "#882B91"; - VividGreen = "#67BDAF"; - VividRed = "#C52E60"; - - DarkIndigo = "#14233C"; - Indigo = "#264B93"; - - MutedSkyBlue = "#83D2F5"; - MutedPink = "#DF69A8"; - MutedTeal = "#7BCAAB"; - MutedOrange = "#E7C565"; - MutedBlue = "#537ABD"; - MutedPurple = "#A16DAE"; - MutedRed = "#DC7969"; - - PaleSkyBlue = "#E4F5FC"; - PalePink = "#EEB3D2"; - PaleTeal = "#B9E0D4"; - PaleOrange = "#F1CFB5"; - PaleBlue = "#B5BEDF"; - PalePurple = "#CFB4D5"; -} - -export const appTheme = new SciChart2022AppTheme(); diff --git a/frontend/src/components/charts/tabbed.test.tsx b/frontend/src/components/charts/tabbed.test.tsx deleted file mode 100644 index b4606e27..00000000 --- a/frontend/src/components/charts/tabbed.test.tsx +++ /dev/null @@ -1,54 +0,0 @@ -/** @vitest-environment jsdom */ - -import { fireEvent, render, screen } from "@testing-library/react"; -import { describe, expect, it, vi } from "vitest"; -import { TabbedChart } from "#/components/charts/tabbed"; - -describe("TabbedChart", () => { - it("reports active tab changes", () => { - const onActiveTabChange = vi.fn(); - - render( - first-icon, - component:
first-panel
, - }, - { - label: "Second", - icon: second-icon, - component:
second-panel
, - }, - ]} - />, - ); - - expect(onActiveTabChange).toHaveBeenCalledWith("First"); - - fireEvent.click(screen.getByRole("tab", { name: /second-icon/i })); - - expect(onActiveTabChange).toHaveBeenCalledWith("Second"); - }); - - it("applies a className to the root tabs container", () => { - const { container } = render( - only-icon, - component:
only-panel
, - }, - ]} - />, - ); - - expect( - (container.firstChild as HTMLElement).classList.contains("hidden"), - ).toBe(true); - }); -}); diff --git a/frontend/src/components/charts/tabbed.tsx b/frontend/src/components/charts/tabbed.tsx deleted file mode 100644 index 6247c5b7..00000000 --- a/frontend/src/components/charts/tabbed.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { useEffect, useState } from "react"; -import { Tabs } from "#/components/ui/tabs"; -import { cn } from "@/lib/utils"; - -interface TabbedChartProps { - tabs: { - label: string; - icon: React.ReactNode; - component: React.ReactNode; - }[]; - className?: string; - onActiveTabChange?: (label: string) => void; -} - -export const TabbedChart = ({ - tabs, - className, - onActiveTabChange, -}: TabbedChartProps) => { - const defaultTab = tabs[0]?.label ?? ""; - const [activeTab, setActiveTab] = useState(defaultTab); - - useEffect(() => { - onActiveTabChange?.(activeTab); - }, [activeTab, onActiveTabChange]); - - return ( - -
- - {tabs.map((tab) => ( - - {tab.icon} - - ))} - -
-
- {tabs.map((tab) => ( -
- {tab.component} -
- ))} -
-
- ); -}; diff --git a/frontend/src/components/charts/trade/TradeChart.tsx b/frontend/src/components/charts/trade/TradeChart.tsx deleted file mode 100644 index 74e71e11..00000000 --- a/frontend/src/components/charts/trade/TradeChart.tsx +++ /dev/null @@ -1,97 +0,0 @@ -import { useSelector } from "@tanstack/react-store"; -import { memo, useEffect, useRef } from "react"; -import { SciChartReact } from "scichart-react"; -import { appStore } from "#/collections/app"; -import { statusStore } from "#/collections/status"; -import { - initTradeChart, - normalizeSymbol, -} from "#/components/charts/trade/init-trade-chart"; -import { stopLossOverlayFromPosition } from "#/components/charts/trade/stop-loss-annotation"; -import { cn } from "#/lib/utils"; - -type TradeChartProps = { - symbol: string; -}; - -type TradeChartHandle = { - addData: (frame: Record) => void; - updateStopLoss: ( - overlay: { avgEntry: number; stopPrice: number } | null, - ) => void; -}; - -export const TradeChart = memo(({ symbol }: TradeChartProps) => { - const normalizedSymbol = normalizeSymbol(symbol); - const position = useSelector(statusStore, (state) => - state.positionViews.find( - (row) => normalizeSymbol(row.symbol) === normalizedSymbol, - ), - ); - const chartRef = useRef(null); - - const avgEntry = position?.avgEntry; - const stopPrice = position?.stopPrice; - - useEffect(() => { - chartRef.current?.updateStopLoss( - stopLossOverlayFromPosition( - avgEntry === undefined ? undefined : { avgEntry, stopPrice }, - ), - ); - }, [avgEntry, stopPrice]); - - return ( -
-
- {symbol} -
- initTradeChart(rootElement, symbol)} - onInit={(result) => { - chartRef.current = result; - result.updateStopLoss(stopLossOverlayFromPosition(position)); - appStore.actions.updateCandleUpdater(symbol, result.addData); - - return () => { - chartRef.current = null; - appStore.actions.updateCandleUpdater(symbol, null); - }; - }} - /> -
- ); -}); - -export const PositionTradeCharts = () => { - const positions = useSelector(statusStore, (state) => state.positionViews); - const symbols = positions.map((position) => position.symbol); - - if (symbols.length === 0) { - return ( -
- No open positions -
- ); - } - - return ( -
- {symbols.map((symbol) => ( -
- -
- ))} -
- ); -}; diff --git a/frontend/src/components/charts/trade/init-trade-chart.bench.ts b/frontend/src/components/charts/trade/init-trade-chart.bench.ts deleted file mode 100644 index 62c6b738..00000000 --- a/frontend/src/components/charts/trade/init-trade-chart.bench.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { bench, describe } from "vitest"; - -import { parseCandleFrame } from "#/components/charts/trade/init-trade-chart"; - -describe("trade candle frames", () => { - const frame = { - symbol: "LTC/USD", - sec: 1_780_627_020, - open: 42.1, - high: 42.3, - low: 42, - close: 42.2, - volume: 14, - }; - - bench("parse candle frame", () => { - parseCandleFrame(frame); - }); -}); diff --git a/frontend/src/components/charts/trade/init-trade-chart.test.ts b/frontend/src/components/charts/trade/init-trade-chart.test.ts deleted file mode 100644 index 6664cdf0..00000000 --- a/frontend/src/components/charts/trade/init-trade-chart.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { describe, expect, it } from "vitest"; - -import { - latestCandleTime, - parseCandleFrame, -} from "#/components/charts/trade/init-trade-chart"; - -describe("parseCandleFrame", () => { - it("normalizes valid OHLC frames by symbol", () => { - const candle = parseCandleFrame({ - symbol: "ltc/usd", - sec: 1_780_627_020, - open: 42.1, - high: 42.3, - low: 42, - close: 42.2, - volume: 14, - }); - - expect(candle).toEqual({ - symbol: "LTC/USD", - sec: 1_780_627_020, - open: 42.1, - high: 42.3, - low: 42, - close: 42.2, - volume: 14, - }); - }); - - it("rejects partial frames", () => { - expect( - parseCandleFrame({ - symbol: "LTC/USD", - sec: 1_780_627_020, - open: 42.1, - }), - ).toBeNull(); - }); -}); - -describe("latestCandleTime", () => { - it("reads the last candle timestamp", () => { - const ohlc = { - count: () => 2, - getNativeXValues: () => ({ - get: (index: number) => [100, 160][index], - }), - }; - - expect(latestCandleTime(ohlc as never)).toBe(160); - }); - - it("returns null for an empty series", () => { - const ohlc = { - count: () => 0, - getNativeXValues: () => ({ - get: () => 0, - }), - }; - - expect(latestCandleTime(ohlc as never)).toBeNull(); - }); -}); diff --git a/frontend/src/components/charts/trade/init-trade-chart.ts b/frontend/src/components/charts/trade/init-trade-chart.ts deleted file mode 100644 index 6bc1d938..00000000 --- a/frontend/src/components/charts/trade/init-trade-chart.ts +++ /dev/null @@ -1,174 +0,0 @@ -import type { OhlcDataSeries } from "scichart"; -import type { StopLossTakeProfitAnnotation } from "scichart-financial-tools"; -import { - createFinancialChartSurface, - followLatestCandleRange, - refreshFinancialPriceAxis, - type FinancialChartContext, -} from "#/components/charts/shared/financial-chart-utils"; -import { - type StopLossOverlayInput, - syncStopLossAnnotation, -} from "#/components/charts/trade/stop-loss-annotation"; - -export type CandleFrame = { - symbol: string; - sec: number; - open: number; - high: number; - low: number; - close: number; - volume: number; -}; - -const finiteNumber = (value: unknown): number | null => - typeof value === "number" && Number.isFinite(value) ? value : null; - -export const normalizeSymbol = (symbol: string): string => - symbol.trim().toUpperCase(); - -export const parseCandleFrame = ( - frame: Record, -): CandleFrame | null => { - const symbol = typeof frame.symbol === "string" ? normalizeSymbol(frame.symbol) : ""; - const sec = finiteNumber(frame.sec); - const open = finiteNumber(frame.open); - const high = finiteNumber(frame.high); - const low = finiteNumber(frame.low); - const close = finiteNumber(frame.close); - const volume = finiteNumber(frame.volume) ?? 0; - - if ( - symbol === "" || - sec === null || - open === null || - high === null || - low === null || - close === null - ) { - return null; - } - - return { - symbol, - sec, - open, - high, - low, - close, - volume, - }; -}; - -export const latestCandleTime = (ohlc: OhlcDataSeries): number | null => { - const count = ohlc.count(); - - if (count <= 0) { - return null; - } - - return ohlc.getNativeXValues().get(count - 1); -}; - -export const applyCandleFrame = ( - chart: FinancialChartContext, - candle: CandleFrame, -) => { - const count = chart.ohlc.count(); - const latest = latestCandleTime(chart.ohlc); - - if (latest !== null && candle.sec < latest) { - return; - } - - if (latest !== null && candle.sec === latest) { - chart.ohlc.update( - count - 1, - candle.open, - candle.high, - candle.low, - candle.close, - ); - chart.volume.update(count - 1, candle.volume); - refreshFinancialPriceAxis(chart.yAxis, chart.ohlc); - return; - } - - chart.ohlc.append( - candle.sec, - candle.open, - candle.high, - candle.low, - candle.close, - ); - chart.volume.append(candle.sec, candle.volume); - followLatestCandleRange(chart.xAxis, chart.ohlc, count === 0 ? "initial" : "live"); - refreshFinancialPriceAxis(chart.yAxis, chart.ohlc); -}; - -const chartElement = (rootElement: string | HTMLDivElement): HTMLDivElement => { - if (typeof rootElement !== "string") { - return rootElement; - } - - const element = document.getElementById(rootElement); - - if (element instanceof HTMLDivElement) { - return element; - } - - throw new Error("trade chart root element not found"); -}; - -export const initTradeChart = async ( - rootElement: string | HTMLDivElement, - symbol: string, -) => { - const normalizedSymbol = normalizeSymbol(symbol); - const chart = await createFinancialChartSurface( - chartElement(rootElement), - normalizedSymbol, - ); - - let stopAnnotation: StopLossTakeProfitAnnotation | null = null; - let stopPrevious: { - overlay: StopLossOverlayInput; - x0: number; - x1: number; - } | null = null; - let stopOverlay: StopLossOverlayInput | null = null; - - const refreshStopLoss = () => { - const synced = syncStopLossAnnotation( - chart, - stopAnnotation, - stopOverlay, - stopPrevious, - ); - - stopAnnotation = synced.annotation; - stopPrevious = synced.previous; - }; - - const addData = (frame: Record) => { - const candle = parseCandleFrame(frame); - - if (candle === null || candle.symbol !== normalizedSymbol) { - return; - } - - applyCandleFrame(chart, candle); - refreshStopLoss(); - }; - - const updateStopLoss = (overlay: StopLossOverlayInput | null) => { - stopOverlay = overlay; - refreshStopLoss(); - }; - - return { - ...chart, - addData, - updateStopLoss, - }; -}; diff --git a/frontend/src/components/charts/trade/stop-loss-annotation.test.ts b/frontend/src/components/charts/trade/stop-loss-annotation.test.ts deleted file mode 100644 index a11d5804..00000000 --- a/frontend/src/components/charts/trade/stop-loss-annotation.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { describe, expect, it } from "vitest"; - -import { - stopLossAnnotationPoints, - stopLossOverlayFromPosition, -} from "#/components/charts/trade/stop-loss-annotation"; - -describe("stopLossOverlayFromPosition", () => { - it("returns overlay when stop and entry are present", () => { - expect( - stopLossOverlayFromPosition({ - avgEntry: 100, - stopPrice: 95, - }), - ).toEqual({ - avgEntry: 100, - stopPrice: 95, - }); - }); - - it("returns null when stop is missing", () => { - expect( - stopLossOverlayFromPosition({ - avgEntry: 100, - }), - ).toBeNull(); - }); -}); - -describe("stopLossAnnotationPoints", () => { - it("spans the loaded candle range from entry to stop", () => { - const ohlc = { - count: () => 3, - getNativeXValues: () => ({ - get: (index: number) => [1_000, 1_060, 1_120][index], - }), - }; - - expect( - stopLossAnnotationPoints(ohlc as never, { - avgEntry: 42.5, - stopPrice: 41.8, - }), - ).toEqual({ - x0: 1_000, - y0: 42.5, - x1: 1_120, - y1: 41.8, - }); - }); - - it("returns null before candles arrive", () => { - const ohlc = { - count: () => 0, - getNativeXValues: () => ({ - get: () => 0, - }), - }; - - expect( - stopLossAnnotationPoints(ohlc as never, { - avgEntry: 42.5, - stopPrice: 41.8, - }), - ).toBeNull(); - }); -}); diff --git a/frontend/src/components/charts/trade/stop-loss-annotation.ts b/frontend/src/components/charts/trade/stop-loss-annotation.ts deleted file mode 100644 index 4fde474c..00000000 --- a/frontend/src/components/charts/trade/stop-loss-annotation.ts +++ /dev/null @@ -1,166 +0,0 @@ -import type { OhlcDataSeries } from "scichart"; -import { - EAnnotationVisibilityMode, - EAxisLabelDrawMode, - EMultiPointLabelAnchorMode, - StopLossTakeProfitAnnotation, -} from "scichart-financial-tools"; - -import type { FinancialChartContext } from "#/components/charts/shared/financial-chart-utils"; - -export type StopLossOverlayInput = { - avgEntry: number; - stopPrice: number; -}; - -export const STOP_LOSS_ANNOTATION_ID = "symm-stop-loss"; - -const STOP_LOSS_COLOR = "#C52E60"; -const TAKE_PROFIT_COLOR = "#67BDAF"; - -export const stopLossAnnotationPoints = ( - ohlc: OhlcDataSeries, - position: StopLossOverlayInput, -): { x0: number; y0: number; x1: number; y1: number } | null => { - if (position.avgEntry <= 0 || position.stopPrice <= 0) { - return null; - } - - const barCount = ohlc.count(); - - if (barCount <= 0) { - return null; - } - - const nativeX = ohlc.getNativeXValues(); - - return { - x0: nativeX.get(0), - y0: position.avgEntry, - x1: nativeX.get(barCount - 1), - y1: position.stopPrice, - }; -}; - -export const stopLossOverlayFromPosition = ( - position: - | { - avgEntry: number; - stopPrice?: number; - } - | undefined, -): StopLossOverlayInput | null => { - if (position === undefined) { - return null; - } - - if (position.avgEntry <= 0 || position.stopPrice === undefined) { - return null; - } - - if (position.stopPrice <= 0) { - return null; - } - - return { - avgEntry: position.avgEntry, - stopPrice: position.stopPrice, - }; -}; - -const stopLossPointsEqual = ( - left: StopLossOverlayInput, - right: StopLossOverlayInput, - previousX0: number, - previousX1: number, - nextX0: number, - nextX1: number, -): boolean => - left.avgEntry === right.avgEntry && - left.stopPrice === right.stopPrice && - previousX0 === nextX0 && - previousX1 === nextX1; - -export const syncStopLossAnnotation = ( - chart: FinancialChartContext, - annotation: StopLossTakeProfitAnnotation | null, - overlay: StopLossOverlayInput | null, - previous: { - overlay: StopLossOverlayInput; - x0: number; - x1: number; - } | null, -): { - annotation: StopLossTakeProfitAnnotation | null; - previous: { overlay: StopLossOverlayInput; x0: number; x1: number } | null; -} => { - const points = overlay ? stopLossAnnotationPoints(chart.ohlc, overlay) : null; - - if (points === null || overlay === null) { - if (annotation !== null) { - chart.sciChartSurface.annotations.remove(annotation, true); - } - - return { annotation: null, previous: null }; - } - - if ( - annotation !== null && - previous !== null && - stopLossPointsEqual( - previous.overlay, - overlay, - previous.x0, - previous.x1, - points.x0, - points.x1, - ) - ) { - return { annotation, previous }; - } - - const nextPoints = [ - { x: points.x0, y: points.y0 }, - { x: points.x1, y: points.y1 }, - ]; - - if (annotation === null) { - const created = new StopLossTakeProfitAnnotation({ - id: STOP_LOSS_ANNOTATION_ID, - isEditable: false, - points: nextPoints, - strokeThickness: 2, - strokeDashArray: [6, 3], - stopLossColor: STOP_LOSS_COLOR, - takeProfitColor: TAKE_PROFIT_COLOR, - fillOpacity: 0.18, - axisSpanFillOpacity: 0.2, - axisLabelVisibility: EAnnotationVisibilityMode.Always, - axisLabelStroke: "#FFFFFF", - labels: [ - { - id: "stop-axis", - anchorMode: EMultiPointLabelAnchorMode.Axis, - axisLabelDrawMode: EAxisLabelDrawMode.Y, - pointIndex: 1, - text: "Stop", - }, - ], - }); - - chart.sciChartSurface.annotations.add(created); - - return { - annotation: created, - previous: { overlay, x0: points.x0, x1: points.x1 }, - }; - } - - annotation.points = nextPoints; - chart.sciChartSurface.invalidateElement(); - - return { - annotation, - previous: { overlay, x0: points.x0, x1: points.x1 }, - }; -}; diff --git a/frontend/src/components/charts/trade/theme.ts b/frontend/src/components/charts/trade/theme.ts deleted file mode 100644 index d6ff159b..00000000 --- a/frontend/src/components/charts/trade/theme.ts +++ /dev/null @@ -1,158 +0,0 @@ -import { type IThemeProvider, SciChartJsNavyTheme } from "scichart"; - -const getCssColor = (cssVar: string, fallback: string): string => { - if (typeof document === "undefined") { - return fallback; - } - const cssValue = getComputedStyle(document.documentElement) - .getPropertyValue(cssVar) - .trim(); - return cssValue || fallback; -}; - -type TRgbColor = { r: number; g: number; b: number }; - -const parseCssColorToRgb = (color: string): TRgbColor | undefined => { - const trimmed = color.trim(); - - if (trimmed.startsWith("#")) { - let hex = trimmed.slice(1); - if (hex.length === 3 || hex.length === 4) { - hex = hex - .slice(0, 3) - .split("") - .map((channel) => channel + channel) - .join(""); - } else if (hex.length === 6 || hex.length === 8) { - hex = hex.slice(0, 6); - } else { - return undefined; - } - - if (!/^[0-9a-fA-F]{6}$/.test(hex)) { - return undefined; - } - - return { - r: Number.parseInt(hex.slice(0, 2), 16), - g: Number.parseInt(hex.slice(2, 4), 16), - b: Number.parseInt(hex.slice(4, 6), 16), - }; - } - - const rgbMatch = trimmed.match(/^rgba?\((.+)\)$/i); - if (!rgbMatch) { - return undefined; - } - - const channels = rgbMatch[1] - .split(",") - .slice(0, 3) - .map((channel) => Number.parseFloat(channel.trim())); - - if ( - channels.length !== 3 || - channels.some((channel) => !Number.isFinite(channel)) - ) { - return undefined; - } - - const clamp = (value: number) => Math.max(0, Math.min(255, value)); - - return { - r: clamp(channels[0]), - g: clamp(channels[1]), - b: clamp(channels[2]), - }; -}; - -const getPerceivedBrightness = (color: string): number | undefined => { - const rgb = parseCssColorToRgb(color); - if (!rgb) return undefined; - - // WCAG-adjacent perceptual weighting for quick dark/light detection. - return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000; -}; - -export interface AppThemeBase { - SciChartJsTheme: IThemeProvider; - - // general colors - isDark: boolean; - ForegroundColor: string; - Background: string; - - // Series colors - VividSkyBlue: string; - VividPink: string; - VividTeal: string; - VividOrange: string; - VividBlue: string; - VividPurple: string; - VividGreen: string; - VividRed: string; - - MutedSkyBlue: string; - MutedPink: string; - MutedTeal: string; - MutedOrange: string; - MutedBlue: string; - MutedPurple: string; - MutedRed: string; - - PaleSkyBlue: string; - PalePink: string; - PaleTeal: string; - PaleOrange: string; - PaleBlue: string; - PalePurple: string; -} - -export class SciChart2022AppTheme implements AppThemeBase { - SciChartJsTheme = new SciChartJsNavyTheme(); - - // Dynamic colors - get isDark() { - const brightness = getPerceivedBrightness(this.Background); - return brightness === undefined || brightness < 128; - } - get TextColor() { - return this.ForegroundColor; - } - get ForegroundColor() { - return getCssColor("--text", "#F5F5F5"); - } - get Background() { - return getCssColor("--bg-chart", this.SciChartJsTheme.sciChartBackground); - } - - // Series colors - VividSkyBlue = "#50C7E0"; - VividPink = "#EC0F6C"; - VividTeal = "#30BC9A"; - VividOrange = "#F48420"; - VividBlue = "#364BA0"; - VividPurple = "#882B91"; - VividGreen = "#67BDAF"; - VividRed = "#C52E60"; - - DarkIndigo = "#14233C"; - Indigo = "#264B93"; - - MutedSkyBlue = "#83D2F5"; - MutedPink = "#DF69A8"; - MutedTeal = "#7BCAAB"; - MutedOrange = "#E7C565"; - MutedBlue = "#537ABD"; - MutedPurple = "#A16DAE"; - MutedRed = "#DC7969"; - - PaleSkyBlue = "#E4F5FC"; - PalePink = "#EEB3D2"; - PaleTeal = "#B9E0D4"; - PaleOrange = "#F1CFB5"; - PaleBlue = "#B5BEDF"; - PalePurple = "#CFB4D5"; -} - -export const appTheme = new SciChart2022AppTheme(); diff --git a/frontend/src/components/dashboard/canvas.tsx b/frontend/src/components/dashboard/canvas.tsx new file mode 100644 index 00000000..2d6047ba --- /dev/null +++ b/frontend/src/components/dashboard/canvas.tsx @@ -0,0 +1,41 @@ +import type { ReactNode } from "react"; + +export const Canvas = ({ + title, + meta, + topRight, + legend, + footer, + children, + className, +}: { + title: string; + meta: string; + topRight?: ReactNode; + legend?: ReactNode; + footer?: ReactNode; + children: ReactNode; + className: string; +}) => ( +
+
{children}
+
+
+
+ {title} +
+
{meta}
+
+ {topRight ? ( +
+ {topRight} +
+ ) : null} + {legend} + {footer ? ( +
+ {footer} +
+ ) : null} +
+); diff --git a/frontend/src/components/dashboard/fluid.tsx b/frontend/src/components/dashboard/fluid.tsx new file mode 100644 index 00000000..d69d8207 --- /dev/null +++ b/frontend/src/components/dashboard/fluid.tsx @@ -0,0 +1,16 @@ +export const FluidLegend = () => ( +
+ + + whale carrier + + + + laminar + + + + turbulent + +
+); diff --git a/frontend/src/components/dashboard/header.tsx b/frontend/src/components/dashboard/header.tsx new file mode 100644 index 00000000..9d47f012 --- /dev/null +++ b/frontend/src/components/dashboard/header.tsx @@ -0,0 +1,18 @@ +import type { ReactNode } from "react"; + +export const ColumnHeader = ({ + title, + meta, +}: { + title: string; + meta?: ReactNode; +}) => ( +
+ + {title} + + {meta ? ( + {meta} + ) : null} +
+); diff --git a/frontend/src/components/dashboard/pulse.tsx b/frontend/src/components/dashboard/pulse.tsx new file mode 100644 index 00000000..6d93c410 --- /dev/null +++ b/frontend/src/components/dashboard/pulse.tsx @@ -0,0 +1,49 @@ +import { useSelector } from "@tanstack/react-store"; +import { actionStore } from "#/collections/actions"; +import { appStore } from "#/collections/app"; +import { tickStore } from "#/collections/tick"; +import { whyLabel } from "#/components/terminal/decision-format"; + +export const Pulse = () => { + const app = useSelector(appStore, (state) => state); + const tick = useSelector(tickStore, (state) => state); + const denied = useSelector(actionStore, (state) => + Object.values(state.actions) + .flatMap((actions) => actions.values()) + .filter((action) => action.verdict !== "allow"), + ); + const latestDenied = denied.at(-1); + const rejectText = + latestDenied === undefined + ? "" + : `reject ${String(latestDenied.reasonSource)} ${whyLabel( + latestDenied.reason, + )} x${denied.length}`; + + return ( +
+ + #{String(tick?.frame?.count ?? 0)} + + + phase{" "} + + {app.online ? String(tick?.frame?.phase ?? "stream") : "offline"} + + + meas {String(tick?.frame?.measurements ?? "—")} + cand {String(tick?.frame?.candidates ?? "—")} + open {String(tick?.frame?.open ?? "—")} + + quotes{" "} + {tick?.frame?.quotes_ready !== undefined && + tick?.frame?.quotes_total !== undefined + ? `${String(tick?.frame?.quotes_ready)}/${String(tick?.frame?.quotes_total)}` + : "—"} + + {rejectText === "" ? null : ( + {rejectText} + )} +
+ ); +}; diff --git a/frontend/src/components/decisions.tsx b/frontend/src/components/decisions.tsx deleted file mode 100644 index 8db73888..00000000 --- a/frontend/src/components/decisions.tsx +++ /dev/null @@ -1,279 +0,0 @@ - -import { - useSymmConnected, - useSymmDecisionTrace, - useSymmEnginePulse, - useSymmEntryLine, - useSymmEvaluations, - useSymmScanProgress, -} from "#/lib/symm/use-symm-ui"; -import { SidebarSection } from "./sidebar-section"; -import { - whyLabel, - type DecisionTraceEvent, - type EvaluationRow, -} from "#/lib/symm/events"; -import { EmptyHint } from "./hint"; -import { VerdictBadge } from "#/components/verdict"; - -export const DecisionsPanel = () => { - const connected = useSymmConnected(); - const decisionTrace = useSymmDecisionTrace(); - const pulse = useSymmEnginePulse(); - const scan = useSymmScanProgress(); - const evaluations = useSymmEvaluations(); - const entryLine = useSymmEntryLine(); - - const hasEvaluations = evaluations.length > 0; - const quotesReady = scan.quotesReady || pulse?.ticker_ready || 0; - const symbolsTotal = scan.symbolsTotal ?? pulse?.symbols_total; - const fluidSampled = scan.fluidSampled || pulse?.fluid_sampled || 0; - - return ( - - {pulse ? ( - - ) : connected ? ( -
- Scanning — quotes {quotesReady}/{symbolsTotal ?? "?"} · fluid{" "} - {fluidSampled} -
- ) : null} - {entryLine.line > 0 ? ( - - ) : null} - {hasEvaluations ? ( - - ) : decisionTrace?.decisions?.length ? ( - - ) : pulse?.signals?.length ? ( - - ) : ( - - )} -
- ); -}; - -const EntryLineStrip = ({ - line, - median, - mad, -}: { - line: number; - median: number; - mad: number; -}) => ( -
- line {line.toFixed(3)} · median {median.toFixed(3)} · mad {mad.toFixed(3)} -
-); - -const EnginePulseStrip = ({ - pulse, - connected, - quotesReady, - symbolsTotal, - fluidSampled, -}: { - pulse: NonNullable>; - connected: boolean; - quotesReady: number; - symbolsTotal?: number; - fluidSampled: number; -}) => { - if (!connected) { - return null; - } - - return ( -
- #{pulse.seq}{" "} - {pulse.phase} · meas {pulse.measurements} · cand {pulse.candidates} · open{" "} - {pulse.open} - <> - {" "} - · quotes {quotesReady}/{symbolsTotal ?? "?"} · fluid {fluidSampled} - {(pulse.fluid_warming ?? 0) > 0 ? `+${pulse.fluid_warming} warm` : ""} - - {forecastRejectSummary(pulse.forecast_rejects)} -
- ); -}; - -const forecastRejectSummary = ( - rejections: Record | undefined, -) => { - const entries = Object.entries(rejections ?? {}).sort( - (left, right) => right[1] - left[1], - ); - - if (entries.length === 0) { - return ""; - } - - const [key, count] = entries[0]; - const [source, reason] = key.split(":"); - - return ` · reject ${source} ${whyLabel(reason)} ×${count}`; -}; - -const formatPct = (value: number | undefined) => { - if (typeof value !== "number" || !Number.isFinite(value)) { - return "—"; - } - - return `${(value * 100).toFixed(2)}%`; -}; - -interface Props { - decisions: DecisionTraceEvent["decisions"]; -} - -export const DecisionTable = ({ decisions }: Props) => { - return ( -
- - - - - - - - - - - {decisions.map((row) => ( - - - - - - - ))} - -
SymbolScoreVerdict - Why -
{row.symbol} - {row.score.toFixed(3)} - - - - {whyLabel(row.why)} -
-
- ); -}; - -const EvaluationTable = ({ evaluations }: { evaluations: EvaluationRow[] }) => ( -
- - - - - - - - - - - - - {evaluations.map((row) => ( - - - - - - - - - ))} - -
SymbolCombined - Edge - - Signals - VerdictWhy
{row.symbol} - {row.combined.toFixed(3)} - {(row.support ?? 0) > 1 ? ( - ×{row.support} - ) : null} - - {formatPct(row.expected_return)} - / {formatPct(row.required_edge)} - - {(row.signals ?? []) - .map( - (reading) => - `${reading.source} ${reading.confidence.toFixed(2)}`, - ) - .join(" · ")} - - - - {whyLabel(row.why)} -
-
-); - -const SignalTable = ({ - signals, -}: { - signals: Array<{ - symbol: string; - source: string; - score: number; - regime: string; - reason: string; - }>; -}) => ( -
- - - - - - - - - - {signals.map((row) => ( - - - - - - ))} - -
SymbolSourceScore
{row.symbol}{row.source} - {row.score.toFixed(3)} -
-
-); - diff --git a/frontend/src/components/diagnostics/SignalSparkline.tsx b/frontend/src/components/diagnostics/SignalSparkline.tsx deleted file mode 100644 index 84e689b8..00000000 --- a/frontend/src/components/diagnostics/SignalSparkline.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import { memo } from "react"; -import { - EAutoRange, - FastLineRenderableSeries, - NumberRange, - NumericAxis, - SciChartSurface, - XyDataSeries, -} from "scichart"; -import { SciChartReact } from "scichart-react"; -import { signalStore } from "#/collections/signals"; -import { appTheme } from "#/components/charts/shared/theme"; -import { ensureSciChartWasm } from "#/lib/utils"; - -const HISTORY = 120; - -/* -A compact rolling confidence sparkline driven by the same per-source gauge feed -the dashboard gauges use. Presentation only — it registers against the existing -appStore.gaugeUpdaters[source] hook and replays incoming frames. -*/ -const initSparkline = async (rootElement: string | HTMLDivElement) => { - await ensureSciChartWasm(); - - const { sciChartSurface, wasmContext } = await SciChartSurface.create( - rootElement, - { freezeWhenOutOfView: true }, - ); - - sciChartSurface.background = "transparent"; - - const xValues = Array.from({ length: HISTORY }, (_, index) => index); - const yValues = Array.from({ length: HISTORY }, () => 0); - - sciChartSurface.xAxes.add( - new NumericAxis(wasmContext, { - isVisible: false, - autoRange: EAutoRange.Never, - visibleRange: new NumberRange(0, HISTORY - 1), - }), - ); - - sciChartSurface.yAxes.add( - new NumericAxis(wasmContext, { - isVisible: false, - autoRange: EAutoRange.Never, - visibleRange: new NumberRange(0, 1), - }), - ); - - const dataSeries = new XyDataSeries(wasmContext, { xValues, yValues }); - - sciChartSurface.renderableSeries.add( - new FastLineRenderableSeries(wasmContext, { - dataSeries, - stroke: appTheme.VividSkyBlue, - strokeThickness: 2, - }), - ); - - const addData = (confidence: number) => { - for (let index = 0; index < HISTORY - 1; index += 1) { - yValues[index] = yValues[index + 1]; - } - - yValues[HISTORY - 1] = Math.min(1, Math.max(0, confidence)); - dataSeries.clear(); - dataSeries.appendRange(xValues, yValues); - sciChartSurface.invalidateElement(); - }; - - return { sciChartSurface, wasmContext, addData }; -}; - -/* -Drive the sparkline from signalStore — the same readings the panels show. We -track the per-source updatedAt so we only push genuinely new frames. -*/ -const subscribeSparkline = ( - source: string, - addData: (confidence: number) => void, -) => { - let lastUpdatedAt = 0; - - const push = () => { - const reading = signalStore.state.readings[source]; - - if (reading === undefined || reading.updatedAt === lastUpdatedAt) { - return; - } - - lastUpdatedAt = reading.updatedAt; - addData(reading.confidence); - }; - - push(); - - const subscription = signalStore.subscribe(push); - - return () => { - subscription.unsubscribe(); - }; -}; - -export const SignalSparkline = memo(function SignalSparkline({ - source, -}: { - source: string; -}) { - return ( - subscribeSparkline(source, result.addData)} - className="h-full w-full" - style={{ width: "100%", height: "100%" }} - /> - ); -}); diff --git a/frontend/src/components/diagnostics/SystemHealthCell.tsx b/frontend/src/components/diagnostics/SystemHealthCell.tsx deleted file mode 100644 index 8d619ae5..00000000 --- a/frontend/src/components/diagnostics/SystemHealthCell.tsx +++ /dev/null @@ -1,213 +0,0 @@ -import { useSelector } from "@tanstack/react-store"; -import { - confidenceMeterValue, - SIGNAL_SOURCES, - type SignalHealthStatus, - signalHealthStatus, - signalStore, - surpriseMeterValue, -} from "#/collections/signals"; -import { cn } from "#/lib/utils"; - -type Rollup = { - total: number; - healthy: number; - calibrating: number; - degraded: number; - thin: number; - waiting: number; - avgConfidence: number; - firing: number; - overall: SignalHealthStatus; -}; - -const DEGRADED: SignalHealthStatus[] = ["fault", "stale"]; - -const computeRollup = (): Rollup => { - const readings = signalStore.state.readings; - let healthy = 0; - let calibrating = 0; - let degraded = 0; - let thin = 0; - let waiting = 0; - let firing = 0; - let confidenceSum = 0; - let confidenceCount = 0; - - for (const source of SIGNAL_SOURCES) { - const reading = readings[source] ?? null; - const status = signalHealthStatus(reading); - - if (status === "healthy") { - healthy += 1; - } else if (status === "calibrating") { - calibrating += 1; - } else if (status === "waiting") { - waiting += 1; - } else if (status === "flat") { - thin += 1; - } else if (DEGRADED.includes(status)) { - degraded += 1; - } - - if (reading !== null && status !== "waiting") { - confidenceSum += confidenceMeterValue(reading); - confidenceCount += 1; - - if (surpriseMeterValue(reading) >= 100) { - firing += 1; - } - } - } - - const total = SIGNAL_SOURCES.length; - const avgConfidence = - confidenceCount > 0 ? confidenceSum / confidenceCount : 0; - - let overall: SignalHealthStatus = "healthy"; - - if (degraded > 0) { - overall = "fault"; - } else if (healthy === 0 && calibrating === 0) { - overall = "waiting"; - } else if (calibrating > healthy) { - overall = "calibrating"; - } else if (healthy < total / 2) { - overall = "flat"; - } - - return { - total, - healthy, - calibrating, - degraded, - thin, - waiting, - avgConfidence, - firing, - overall, - }; -}; - -const OVERALL_TONE: Record = { - healthy: "border-emerald-500/50 bg-emerald-500/10 text-emerald-300", - calibrating: "border-amber-500/50 bg-amber-500/10 text-amber-300", - fault: "border-red-500/50 bg-red-500/10 text-red-300", - stale: "border-red-500/50 bg-red-500/10 text-red-300", - flat: "border-amber-500/50 bg-amber-500/10 text-amber-300", - waiting: "border-zinc-500/40 bg-zinc-500/10 text-zinc-400", -}; - -const OVERALL_LABEL: Record = { - healthy: "Nominal", - calibrating: "Warming up", - fault: "Degraded", - stale: "Degraded", - flat: "Thin", - waiting: "Standby", -}; - -const StatBar = ({ - label, - count, - total, - tone, -}: { - label: string; - count: number; - total: number; - tone: string; -}) => { - const pct = total > 0 ? (count / total) * 100 : 0; - - return ( -
- - {label} - -
-
-
- - {count} - -
- ); -}; - -export const SystemHealthCell = () => { - const rollup = useSelector(signalStore, computeRollup); - - return ( -
-
- System Health - - {OVERALL_LABEL[rollup.overall]} - -
- -
-
- - {rollup.healthy} - - /{rollup.total} - - - - signals healthy - -
-
- - {Math.round(rollup.avgConfidence)}% - - - avg confidence - -
-
- 0 ? "text-sky-300" : "", - )} - > - {rollup.firing} - - firing now -
-
- -
- - - -
-
- ); -}; diff --git a/frontend/src/components/diagnostics/signal-panel.tsx b/frontend/src/components/diagnostics/signal-panel.tsx deleted file mode 100644 index 856865e1..00000000 --- a/frontend/src/components/diagnostics/signal-panel.tsx +++ /dev/null @@ -1,222 +0,0 @@ -import { useSelector } from "@tanstack/react-store"; -import { - confidenceMeterValue, - evidenceMeterValue, - freshnessMeterValue, - healthMeterValue, - SIGNAL_LABELS, - signalHealthStatus, - signalStore, - surpriseMeterValue, - warmupProgress, -} from "#/collections/signals"; -import { - Meter, - MeterIndicator, - MeterLabel, - MeterTrack, - MeterValue, -} from "#/components/ui/meter"; -import { cn } from "@/lib/utils"; - -const STATUS_TONE: Record = { - waiting: "bg-zinc-500/15 text-zinc-400 border-zinc-500/30", - calibrating: "bg-amber-500/15 text-amber-400 border-amber-500/30", - fault: "bg-red-500/15 text-red-400 border-red-500/30", - stale: "bg-red-500/15 text-red-400 border-red-500/30", - flat: "bg-amber-500/15 text-amber-400 border-amber-500/30", - healthy: "bg-emerald-500/15 text-emerald-400 border-emerald-500/30", -}; - -const STATUS_LABEL: Record = { - waiting: "Waiting", - calibrating: "Calibrating", - fault: "Fault", - stale: "Stale", - flat: "Flat", - healthy: "Healthy", -}; - -const formatPercent = (value: number): string => `${Math.round(value)}%`; - -const formatRatio = (value: number, threshold: number): string => { - if (threshold <= 0) { - return "-"; - } - - return `${value.toFixed(2)}× threshold`; -}; - -const formatObservedAge = ( - observedAt: number | null, - updatedAt: number, -): string => { - if (observedAt === null) { - return "missing"; - } - - const elapsed = Math.max(0, updatedAt - observedAt); - - if (elapsed < 1000) { - return `${Math.round(elapsed)}ms`; - } - - return `${(elapsed / 1000).toFixed(1)}s`; -}; - -const formatElapsed = (elapsed: number): string => { - if (elapsed <= 0) { - return "missing"; - } - - return `${elapsed.toFixed(1)}s`; -}; - -const formatActiveReadings = ( - activeReadings: number, - readingsCapacity: number, - category: string, -): string => { - if (readingsCapacity > 0) { - return `${activeReadings.toLocaleString()} / ${readingsCapacity.toLocaleString()}`; - } - - if (category !== "") { - return category; - } - - return "none"; -}; - -const DiagnosticMeter = ({ - label, - value, - valueLabel, -}: { - label: string; - value: number; - valueLabel?: string; -}) => ( - -
- {label} - {valueLabel ?? formatPercent(value)} -
- - - -
-); - -export const SignalPanel = ({ source }: { source: string }) => { - const reading = useSelector( - signalStore, - (state) => state.readings[source] ?? null, - ); - const label = SIGNAL_LABELS[source] ?? source; - const status = signalHealthStatus(reading); - const evidenceValue = reading === null ? 0 : evidenceMeterValue(reading); - const freshnessValue = reading === null ? 0 : freshnessMeterValue(reading); - const gapLabel = - reading === null - ? "" - : reading.gapReason || (reading.bestEffort ? "best_effort" : "none"); - - return ( -
-
-
-

{label}

-

- Live confidence, surprise, strength, and publishable evidence. -

-
- - {STATUS_LABEL[status]} - -
- - {reading === null ? ( -

- No gauge frames received yet for{" "} - {source}. -

- ) : ( -
- - - - 0 ? "Ready" : "Missing"} - /> - 0 ? "Live" : "Stale"} - /> - {reading.calibrating ? ( - - ) : ( - - )} -
-
- Active - - {formatActiveReadings( - reading.activeReadings, - reading.readingsCapacity, - reading.category, - )} - -
-
- Strength - - {reading.strength.toFixed(4)} - -
-
- Observed - - {formatObservedAge(reading.observedAt, reading.updatedAt)} /{" "} - {formatElapsed(reading.elapsed)} - -
-
- Gap - - {gapLabel} - -
-
-
- )} -
- ); -}; diff --git a/frontend/src/components/header.tsx b/frontend/src/components/header.tsx deleted file mode 100644 index 0284ce5f..00000000 --- a/frontend/src/components/header.tsx +++ /dev/null @@ -1,64 +0,0 @@ - -import { memo } from "react"; - -import ThemeToggle from "#/components/ThemeToggle"; -import { Metric } from "./metric"; -import { - useSymmConnected, - useSymmTelemetryStatus, - useSymmTick, - useSymmWallet, -} from "#/lib/symm/use-dashboard-data"; -import { formatEur } from "#/lib/utils"; - -export const DashboardHeader = memo(function DashboardHeader() { - const connected = useSymmConnected(); - const wallet = useSymmWallet(); - const tick = useSymmTick(); - const telemetry = useSymmTelemetryStatus(); - const cash = wallet.balance + wallet.reservedEur; - - return ( -
-
- - SYMM -
- - - {connected ? "live" : "offline"} - - - - {wallet.openCount} open position{wallet.openCount === 1 ? "" : "s"} - - - {connected && telemetry.throttled ? ( - - chart throttled - - ) : null} - -
- - - - - -
-
- ); -}); - diff --git a/frontend/src/components/hint.tsx b/frontend/src/components/hint.tsx deleted file mode 100644 index 338dfdb1..00000000 --- a/frontend/src/components/hint.tsx +++ /dev/null @@ -1,17 +0,0 @@ - -interface Props { - connected: boolean; - message?: string; -} - -export const EmptyHint = ({ connected, message }: Props) => { - return ( -

- {message ?? - (connected - ? "Waiting for engine events…" - : "Connect telemetry WebSocket")} -

- ); -}; - diff --git a/frontend/src/components/kernel/detail.tsx b/frontend/src/components/kernel/detail.tsx new file mode 100644 index 00000000..f8d6b167 --- /dev/null +++ b/frontend/src/components/kernel/detail.tsx @@ -0,0 +1,258 @@ +import { useSelector } from "@tanstack/react-store"; +import { appStore } from "#/collections/app"; +import { measurementsStore } from "#/collections/measurements"; +import { terminalStore } from "#/collections/terminal"; +import { + kernelCopy, + kernelStatusMeta, + type SignalHealthStatus, +} from "#/components/terminal/kernel-meta"; +import { InspectorMeter } from "./meter"; + +const clampPercent = (value: number) => + Math.max(0, Math.min(100, value * 100)); + +const finite = (value: unknown): number => { + const number = typeof value === "number" ? value : Number(value); + + return Number.isFinite(number) ? number : 0; +}; + +const heatColor = (value: number): [number, number, number] => { + const stops: Array<[number, [number, number, number]]> = [ + [0, [14, 12, 10]], + [0.4, [26, 34, 50]], + [0.6, [42, 106, 129]], + [0.8, [232, 163, 61]], + [1, [246, 214, 159]], + ]; + const t = Math.max(0, Math.min(1, value)); + + for (let index = 0; index < stops.length - 1; index += 1) { + const left = stops[index]; + const right = stops[index + 1]; + + if (t <= right[0]) { + const span = right[0] - left[0]; + const mix = span === 0 ? 0 : (t - left[0]) / span; + + return [ + left[1][0] + (right[1][0] - left[1][0]) * mix, + left[1][1] + (right[1][1] - left[1][1]) * mix, + left[1][2] + (right[1][2] - left[1][2]) * mix, + ]; + } + } + + return stops[stops.length - 1][1]; +}; + +const stampOf = (frame: { at?: string | number } | undefined): number => { + const at = frame?.at; + + if (typeof at === "number") { + return at; + } + + if (typeof at === "string" && at.trim() !== "") { + return Date.parse(at); + } + + return Number.NaN; +}; + +const ageText = (stamp: number): string => { + if (!Number.isFinite(stamp)) { + return "—"; + } + + const age = Math.max(0, Date.now() - stamp); + + if (age < 1000) { + return `${Math.round(age)}ms`; + } + + return `${(age / 1000).toFixed(1)}s`; +}; + +export const SignalDetail = () => { + const selectedSource = useSelector( + terminalStore, + (state) => state.selectedSource, + ); + const focusSymbol = useSelector(appStore, (state) => state.focusSymbol); + const measurements = useSelector(measurementsStore, (state) => state); + const source = selectedSource; + const history = measurements.measurements[focusSymbol]?.[source]?.values() ?? []; + const measurement = history.at(-1); + const category = measurement?.categories.at(0); + const metrics = measurement?.metrics ?? {}; + const confidence = finite(category?.confidence); + const surprise = finite(category?.surprisal); + const strength = finite(category?.strength); + const backendStatus = measurement?.status ?? ""; + const status = ( + measurement === undefined + ? "waiting" + : backendStatus === "fault" || + backendStatus === "ambiguous" || + backendStatus === "calibrating" + ? backendStatus + : "measured" + ) as SignalHealthStatus; + const categoryType = + typeof category?.type === "string" ? category.type : selectedSource; + const copy = kernelCopy(selectedSource, categoryType); + const statusMeta = kernelStatusMeta(status); + const observedStamp = stampOf(measurement); + const active = Object.values(measurements.measurements).reduce( + (sum, sources) => sum + (sources[source]?.values().length ?? 0), + 0, + ); + const total = Object.values(measurements.measurements).reduce( + (sum, sources) => + sum + + Object.values(sources).reduce( + (sourceSum, sourceHistory) => sourceSum + sourceHistory.values().length, + 0, + ), + 0, + ); + const heatmap = Object.entries(measurements.measurements).flatMap( + ([symbol, sources]) => { + const frame = sources[source]?.values().at(-1); + const value = finite(frame?.categories.at(0)?.confidence); + + return frame === undefined ? [] : [{ symbol, value }]; + }, + ); + + return ( +
+
+
+

+ {copy.name} +

+
+ {copy.sub} +
+
+ + {statusMeta.label} + +
+

+ {copy.blurb} +

+ {measurement === undefined ? ( +
+ waiting for backend {selectedSource} measurement +
+ ) : null} + {measurement === undefined ? null : ( +
+ + = 1 ? "var(--acc)" : "var(--info)"} + /> + + + + +
+ )} +
+
+ Active readings + + {active.toLocaleString()} / {total.toLocaleString()} + +
+
+ Strength + {strength.toFixed(4)} +
+
+ Observed + + {Number.isFinite(observedStamp) + ? `${new Date(observedStamp).toLocaleTimeString("en-US", { + hour12: false, + })} / ${ageText(observedStamp)}` + : "— / —"} + +
+
+ Gap + + {String(metrics.gap ?? "none")} + +
+
+
+
+ Cross-section · confidence heatmap +
+
+ {heatmap.slice(0, 24).map((cell) => { + const percent = Math.round(clampPercent(cell.value)); + const label = cell.symbol.split("/")[0] ?? cell.symbol; + const [red, green, blue] = heatColor(cell.value); + + return ( +
0.62 ? "#14110f" : "var(--f3)", + }} + > + {label} +
+ ); + })} +
+
+
+ ); +}; diff --git a/frontend/src/components/kernel/inspector.tsx b/frontend/src/components/kernel/inspector.tsx new file mode 100644 index 00000000..5b4fbc41 --- /dev/null +++ b/frontend/src/components/kernel/inspector.tsx @@ -0,0 +1,181 @@ +import { useSelector } from "@tanstack/react-store"; +import { measurementsStore } from "#/collections/measurements"; +import { terminalStore } from "#/collections/terminal"; +import { + kernelCopy, + kernelStatusMeta, + type SignalHealthStatus, +} from "#/components/terminal/kernel-meta"; +import { InspectorMeter } from "./meter"; + +export const KernelInspector = () => { + const inspectorSource = useSelector( + terminalStore, + (state) => state.inspectorSource, + ); + const focusSymbol = useSelector(terminalStore, (state) => state.focusSymbol); + const { closeInspect, inspectSource } = terminalStore.actions; + const source = inspectorSource ?? ""; + const history = useSelector(measurementsStore, (state) => { + if (source === "") { + return []; + } + + if (focusSymbol !== "stream") { + return state.measurements[focusSymbol]?.[source]?.values() ?? []; + } + + return Object.values(state.measurements).flatMap( + (symbols) => symbols[source]?.values() ?? [], + ); + }); + const frame = history.at(-1); + const category = frame?.categories.at(0); + const metrics = frame?.metrics ?? {}; + const confidence = category?.confidence ?? 0; + const surprise = category?.surprisal ?? 0; + const strength = category?.strength ?? confidence; + const status: SignalHealthStatus = + metrics.error !== undefined + ? "fault" + : ((frame?.status ?? "standby") as SignalHealthStatus); + if (inspectorSource === null || frame === undefined) { + return null; + } + + const copy = kernelCopy(source, category?.type ?? source); + const statusMeta = kernelStatusMeta(status); + const width = 150; + const baseline = 29; + const scale = 26; + const values = history.slice(-40).flatMap((measurement) => { + const value = measurement.categories.at(0)?.confidence; + + return typeof value === "number" && Number.isFinite(value) ? [value] : []; + }); + const points = values + .map( + (value, index) => + `${((index / Math.max(values.length - 1, 1)) * width).toFixed( + 1, + )},${(baseline - value * scale).toFixed(1)}`, + ) + .join(" "); + const observedAt = frame.at; + const observed = + typeof observedAt === "number" || typeof observedAt === "string" + ? new Date(observedAt).toLocaleTimeString("en-US", { hour12: false }) + : "—"; + + return ( +
+ +
+

+ {copy.blurb} +

+
+
+ signal history + 40 ticks +
+ + Signal history + + +
+
+ + + +
+
+
+
active {frame.symbol}
+
+ observed {observed} · {history.length} samples +
+
+ +
+
+
+
+ ); +}; diff --git a/frontend/src/components/kernel/meter.tsx b/frontend/src/components/kernel/meter.tsx new file mode 100644 index 00000000..e9aee053 --- /dev/null +++ b/frontend/src/components/kernel/meter.tsx @@ -0,0 +1,24 @@ +export const InspectorMeter = ({ + label, + value, + percent, + color, +}: { + label: string; + value: string; + percent: number; + color: string; +}) => ( +
+
+ {label} + {value} +
+
+
+
+
+); diff --git a/frontend/src/components/kernel/row.tsx b/frontend/src/components/kernel/row.tsx new file mode 100644 index 00000000..144df014 --- /dev/null +++ b/frontend/src/components/kernel/row.tsx @@ -0,0 +1,95 @@ +import { measurementsStore } from "#/collections/measurements"; +import { terminalStore } from "#/collections/terminal"; +import { useSelector } from "@tanstack/react-store"; + +export const KernelRow = ({ source }: { source: string }) => { + const focusSymbol = useSelector(terminalStore, (state) => state.focusSymbol); + const history = useSelector(measurementsStore, (state) => + state.measurements[focusSymbol]?.[source]?.values() ?? [], + ); + const measurement = history.at(-1); + const confidence = measurement?.categories.at(0)?.confidence ?? 0; + const points = + history.length === 1 + ? `0,${(1 - confidence).toFixed(3)} 1,${(1 - confidence).toFixed(3)}` + : history + .map( + (item, index) => + `${(index / (history.length - 1)).toFixed(3)},${( + 1 - + (item.categories.at(0)?.confidence ?? 0) + ).toFixed(3)}`, + ) + .join(" "); + + return ( + + ); +}; diff --git a/frontend/src/components/layout/mode-toggle.tsx b/frontend/src/components/layout/mode-toggle.tsx deleted file mode 100644 index d90f204a..00000000 --- a/frontend/src/components/layout/mode-toggle.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { Contrast, Layers, Monitor, Moon, Sun, SunDim } from "lucide-react"; -import { Button } from "#/components/ui/button"; -import { - Menu, - MenuCheckboxItem, - MenuItem, - MenuPopup, - MenuSeparator, - MenuTrigger, -} from "#/components/ui/menu"; -import { - type ColorMode, - VISUAL_THEME_OPTIONS, - type VisualTheme, -} from "#/lib/appearance"; -import { useTheme } from "#/providers/theme"; - -const modeIcons: Record = { - light: , - dim: , - dark: , - system: , -}; - -/* -ModeToggle exposes color mode (light/dim/dark/system), high contrast, and -visual theme styles. Modes set document classes; visual themes load optional -stylesheets. -*/ -export const ModeToggle = () => { - const { mode, setMode, contrast, setContrast, visualTheme, setVisualTheme } = - useTheme(); - - const selectVisualTheme = (next: VisualTheme) => { - if (next === visualTheme) return; - setVisualTheme(next); - }; - - return ( - - - } - > - {modeIcons[mode]} - - - setMode("light")}> - - Light - - setMode("dim")}> - - Dim - - setMode("dark")}> - - Dark - - setMode("system")}> - - System - - - - - - High Contrast - - - -
- - Visual Theme -
- {VISUAL_THEME_OPTIONS.map((themeId) => ( - selectVisualTheme(themeId)}> - {themeId} - {visualTheme === themeId ? " ✓" : ""} - - ))} -
-
- ); -}; diff --git a/frontend/src/components/layout/navigation.tsx b/frontend/src/components/layout/navigation.tsx deleted file mode 100644 index b55cbc84..00000000 --- a/frontend/src/components/layout/navigation.tsx +++ /dev/null @@ -1,144 +0,0 @@ -import { Link } from "@tanstack/react-router"; -import { useSelector } from "@tanstack/react-store"; -import { - ActivityIcon, - ArrowDownRightIcon, - ArrowUpRightIcon, - BanIcon, - CheckCircle2Icon, - HomeIcon, - LoaderIcon, - NetworkIcon, -} from "lucide-react"; -import { statusStore } from "#/collections/status"; -import { TradeHistoryPanel } from "#/components/trade-history"; - -const PAGES: { to: string; label: string; Icon: typeof HomeIcon }[] = [ - { to: "/", label: "Dashboard", Icon: HomeIcon }, - { to: "/diagnostics", label: "Signal Insight", Icon: ActivityIcon }, - { to: "/decisions", label: "Decision Tree", Icon: NetworkIcon }, -]; - -const ACTION_LABELS: Record = { - limit: "Limit", - market: "Market", - iceberg: "Iceberg", - stop_loss: "Stop Loss", - stop_loss_limit: "Stop Loss Limit", - take_profit: "Take Profit", - take_profit_limit: "Take Profit Limit", - trailing_stop: "Trailing Stop", - trailing_stop_limit: "Trailing Stop Limit", - settle_position: "Settle", -}; - -const EXIT_TYPES = new Set([ - "settle_position", - "stop_loss", - "stop_loss_limit", - "take_profit", - "take_profit_limit", - "trailing_stop", - "trailing_stop_limit", -]); - -const relativeTime = (ts: number) => { - const seconds = Math.max(0, Math.round((Date.now() - ts) / 1000)); - - if (seconds < 60) { - return `${seconds}s ago`; - } - - return `${Math.round(seconds / 60)}m ago`; -}; - -const VERDICT_META: Record< - string, - { Icon: typeof BanIcon; tone: string; label: string } -> = { - filled: { Icon: CheckCircle2Icon, tone: "text-emerald-400", label: "filled" }, - submitted: { Icon: LoaderIcon, tone: "text-sky-400", label: "submitted" }, - rejected: { Icon: BanIcon, tone: "text-rose-400", label: "blocked" }, -}; - -const ActionCard = ({ - action, -}: { - action: { - type: string; - symbol: string; - reason?: string; - verdict: string; - ts: number; - }; -}) => { - const isExit = EXIT_TYPES.has(action.type); - const DirectionIcon = isExit ? ArrowDownRightIcon : ArrowUpRightIcon; - const verdict = VERDICT_META[action.verdict] ?? VERDICT_META.rejected; - - return ( -
-
- ); -}; - -export const Navigation = ({ onNavigate }: { onNavigate?: () => void }) => { - const { actions } = useSelector(statusStore, (state) => state); - - return ( -
-

- Pages -

- {PAGES.map((page) => ( - - - {page.label} - - ))} -

- Decisions -

- {actions.length === 0 ? ( -

No decisions yet

- ) : ( - actions.map((action) => ( - - )) - )} - -
- ); -}; diff --git a/frontend/src/components/layout/not-found.tsx b/frontend/src/components/layout/not-found.tsx deleted file mode 100644 index c967954a..00000000 --- a/frontend/src/components/layout/not-found.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export const NotFoundPage = () => { - return ( -
- Page not found -
- ); -}; diff --git a/frontend/src/components/layout/page.tsx b/frontend/src/components/layout/page.tsx deleted file mode 100644 index d84ad04e..00000000 --- a/frontend/src/components/layout/page.tsx +++ /dev/null @@ -1,216 +0,0 @@ -import { Link, useLocation, useRouterState } from "@tanstack/react-router"; -import { Menu as MenuIcon } from "lucide-react"; -import type React from "react"; -import { useState } from "react"; -import { - Breadcrumb, - BreadcrumbItem, - BreadcrumbLink, - BreadcrumbList, - BreadcrumbPage, - BreadcrumbSeparator, -} from "#/components/ui/breadcrumb"; -import { Button } from "#/components/ui/button"; -import { - Sheet, - SheetDescription, - SheetHeader, - SheetPanel, - SheetPopup, - SheetTitle, - SheetTrigger, -} from "#/components/ui/sheet"; -import { cn } from "#/lib/utils"; -import { Flex } from "../ui/flex"; -import { Navigation } from "./navigation"; - -const UUID_PATTERN = - /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; - -const humanize = (segment: string) => { - const decoded = decodeURIComponent(segment); - - if (UUID_PATTERN.test(decoded)) { - return `${decoded.slice(0, 8)}…${decoded.slice(-4)}`; - } - - return decoded - .replace(/[-_]+/g, " ") - .replace(/\b\w/g, (character) => character.toUpperCase()); -}; - -/* -PageContentWidth selects how routed main content is sized in the shell. -full: span the main grid column. -contained: centered column with a max width (document-style layouts). -*/ -export type PageContentWidth = "full" | "contained"; - -type PageContentWidthStatic = { - pageContentWidth?: PageContentWidth; -}; - -/* -resolvePageContentWidth walks active matches from leaf to root; the first -explicit pageContentWidth wins so child routes can override layout parents. -*/ -export function resolvePageContentWidth( - matches: ReadonlyArray<{ staticData?: unknown }>, -): PageContentWidth { - for (let index = matches.length - 1; index >= 0; index--) { - const data = matches[index]?.staticData as - | PageContentWidthStatic - | undefined; - const width = data?.pageContentWidth; - - if (width === "contained" || width === "full") { - return width; - } - } - - return "full"; -} - -const useRouteCrumbs = () => { - const { pathname } = useLocation(); - const segments = pathname.split("/").filter(Boolean); - - return segments.map((segment, index) => { - const href = `/${segments.slice(0, index + 1).join("/")}`; - - return { - href, - label: humanize(segment), - }; - }); -}; - -const RouteCrumb = ({ - href, - label, - isLast, -}: { - href: string; - label: string; - isLast: boolean; -}) => { - return ( - <> - - - {isLast ? ( - {label} - ) : ( - {label} - )} - - - ); -}; - -export const Page = ({ children }: { children?: React.ReactNode }) => { - return <>{children ?? null}; -}; - -Page.Header = ({ children }: { children?: React.ReactNode }) => { - return {children}; -}; - -const PageHeaderBody = ({ children }: { children?: React.ReactNode }) => { - const [navOpen, setNavOpen] = useState(false); - - return ( -
- - - - - }> - - - - - Symm - - ...Like somebody 'bout to pay ya - - - - setNavOpen(false)} /> - - - - - - }>Home - - {useRouteCrumbs().map((crumb, index, all) => ( - - ))} - - - - {children ?? null} -
- ); -}; - -Page.Nav = ({ children }: { children?: React.ReactNode[] }) => { - return ; -}; - -Page.Main = ({ children }: { children?: React.ReactNode }) => { - return ( -
- {children ?? null} -
- ); -}; - -/* -Page.MainBody wraps routed outlet content and honors each route staticData -pageContentWidth. Use it once inside Page.Main in the root shell. -*/ -Page.MainBody = ({ children }: { children?: React.ReactNode }) => { - const contentWidth = useRouterState({ - select: (state) => resolvePageContentWidth(state.matches), - }); - - if (contentWidth === "contained") { - return ( -
-
- {children ?? null} -
-
- ); - } - - return ( - - {children ?? null} - - ); -}; - -Page.Section = ({ children }: { children?: React.ReactNode }) => { - return
{children ?? null}
; -}; - -Page.Aside = ({ children }: { children?: React.ReactNode }) => { - return ; -}; - -Page.Footer = ({ children: _children }: { children?: React.ReactNode }) => { - return
; -}; diff --git a/frontend/src/components/metric.tsx b/frontend/src/components/metric.tsx deleted file mode 100644 index f4866388..00000000 --- a/frontend/src/components/metric.tsx +++ /dev/null @@ -1,20 +0,0 @@ - -interface Props { - label: string; - value: string; - tone?: string; -} - -export const Metric = ({ label, value, tone }: Props) => { - return ( -
- - {label} - - - {value} - -
- ); -}; - diff --git a/frontend/src/components/panels/data/audit-data-provider.bench.ts b/frontend/src/components/panels/data/audit-data-provider.bench.ts deleted file mode 100644 index 5b6ce3b1..00000000 --- a/frontend/src/components/panels/data/audit-data-provider.bench.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { bench, describe } from "vitest"; - -import { AuditDataProvider } from "#/components/panels/data/audit-data-provider"; - -describe("AuditDataProvider", () => { - bench("ingests realtime audit frames", () => { - AuditDataProvider.reset(); - - for (let index = 0; index < 64; index++) { - AuditDataProvider.ingest({ - event: "audit", - audit_event: "trade_entry_fill", - seq: index, - ts: "2026-05-29T01:02:03Z", - symbol: "BTC/EUR", - slot_eur: 10, - confidence: 0.9, - }); - } - }); -}); diff --git a/frontend/src/components/panels/data/audit-data-provider.test.ts b/frontend/src/components/panels/data/audit-data-provider.test.ts deleted file mode 100644 index 69091cbe..00000000 --- a/frontend/src/components/panels/data/audit-data-provider.test.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { beforeEach, describe, expect, it } from "vitest"; - -import { AuditDataProvider } from "#/components/panels/data/audit-data-provider"; - -describe("AuditDataProvider", () => { - beforeEach(() => { - AuditDataProvider.reset(); - }); - - it("keeps newest audit rows first with compact summaries", () => { - AuditDataProvider.ingest({ - event: "audit", - audit_event: "trade_entry_fill", - seq: 1, - ts: "2026-05-29T01:02:03Z", - symbol: "BTC/EUR", - source: "cvd", - edge: 0.012345, - confidence: 0.72, - }); - - const row = AuditDataProvider.snapshot()[0]; - - expect(row).toMatchObject({ - seq: 1, - event: "trade entry fill", - symbol: "BTC/EUR", - source: "cvd", - }); - expect(row?.summary).toContain("edge=0.01235"); - expect(row?.summary).toContain("confidence=0.7200"); - }); - - it("surfaces entry why, playbook, and perspectives in the summary", () => { - AuditDataProvider.ingest({ - event: "audit", - audit_event: "entry_submit", - seq: 2, - ts: "2026-05-29T01:02:04Z", - symbol: "LOFI/EUR", - source: "trader", - reason: "pumpdump.vertical_ignition", - why: "pumpdump.vertical_ignition", - playbook: "pump", - perspectives: ["pump"], - conviction: 2.4, - edge: 0.8, - slot_eur: 3.13, - }); - - const row = AuditDataProvider.snapshot()[0]; - - expect(row?.event).toBe("Entry submit"); - expect(row?.reason).toBe("pumpdump.vertical_ignition"); - expect(row?.summary).toContain("why=pumpdump.vertical_ignition"); - expect(row?.summary).toContain("playbook=pump"); - expect(row?.summary).toContain("perspectives=pump"); - }); - - it("labels exit events with the desk reason", () => { - AuditDataProvider.ingest({ - event: "audit", - audit_event: "exit", - seq: 3, - ts: "2026-05-29T01:02:05Z", - symbol: "BOBA/EUR", - source: "trader", - reason: "perspective TTL elapsed", - why: "perspective TTL elapsed", - actual_return: -0.0973, - success: false, - }); - - const row = AuditDataProvider.snapshot()[0]; - - expect(row?.event).toBe("Exit filled"); - expect(row?.reason).toBe("perspective TTL elapsed"); - expect(row?.summary).toContain("actual_return=-0.09730"); - }); - - it("ignores non-audit frames", () => { - AuditDataProvider.ingest({ - event: "tick", - ts: "2026-05-29T01:02:03Z", - }); - - expect(AuditDataProvider.snapshot()).toEqual([]); - }); -}); diff --git a/frontend/src/components/panels/data/audit-data-provider.ts b/frontend/src/components/panels/data/audit-data-provider.ts deleted file mode 100644 index fa364812..00000000 --- a/frontend/src/components/panels/data/audit-data-provider.ts +++ /dev/null @@ -1,173 +0,0 @@ - -import type { AuditEvent } from "#/lib/symm/events"; -import { isAuditEvent } from "#/lib/symm/events"; - -export type AuditRow = { - key: string; - seq: number; - event: string; - ts: string; - symbol?: string; - source?: string; - reason?: string; - summary: string; -}; - -type Listener = () => void; - -const MAX_ROWS = 120; - -const SUMMARY_KEYS = [ - "why", - "playbook", - "perspectives", - "conviction", - "edge", - "confidence", - "predicted_return", - "actual_return", - "net_return", - "forward_return", - "error", - "urgency", - "success", - "held_ms", - "slot_eur", - "spread_bps", - "fill_price", -] as const; - -const formatValue = (value: unknown): string => { - if (typeof value === "number") { - return Number.isInteger(value) ? value.toString() : value.toPrecision(4); - } - - if (typeof value === "boolean") { - return value ? "true" : "false"; - } - - if (typeof value === "string") { - return value; - } - - if (Array.isArray(value)) { - return value - .map((entry) => formatValue(entry)) - .filter(Boolean) - .join("+"); - } - - return ""; -}; - -const summarize = (event: AuditEvent): string => { - const parts: string[] = []; - - for (const key of SUMMARY_KEYS) { - const value = event[key]; - - if (value === undefined || value === null) { - continue; - } - - const formatted = formatValue(value); - - if (formatted === "") { - continue; - } - - parts.push(`${key}=${formatted}`); - } - - return parts.join(" · "); -}; - -const eventLabel = (event: string): string => { - switch (event) { - case "entry_submit": - return "Entry submit"; - case "entry": - return "Entry filled"; - case "exit_submit": - return "Exit submit"; - case "exit": - return "Exit filled"; - case "forward": - return "Forward matured"; - case "order_reject": - return "Order rejected"; - case "gate_reject": - return "Gate rejected"; - default: - return event.replaceAll("_", " "); - } -}; - -class AuditDataProviderImpl { - private rows: AuditRow[] = []; - private listeners = new Set(); - - subscribe(listener: Listener) { - this.listeners.add(listener); - - return () => { - this.listeners.delete(listener); - }; - } - - snapshot(): readonly AuditRow[] { - return this.rows; - } - - private notify() { - for (const listener of this.listeners) { - listener(); - } - } - - ingest(raw: unknown) { - if (!isAuditEvent(raw)) { - return; - } - - this.rows = [ - { - key: `${raw.seq}:${raw.audit_event}`, - seq: raw.seq, - event: eventLabel(raw.audit_event), - ts: raw.ts, - symbol: raw.symbol, - source: raw.source, - reason: raw.reason, - summary: summarize(raw), - }, - ...this.rows, - ].slice(0, MAX_ROWS); - this.notify(); - } - - reset() { - this.rows = []; - this.notify(); - } -} - -const shared = createAuditDataProviderImpl(); - -export const createAuditDataProvider = () => createAuditDataProviderImpl(); - -function createAuditDataProviderImpl() { - const impl = new AuditDataProviderImpl(); - - return { - subscribe: (listener: Listener) => impl.subscribe(listener), - snapshot: () => impl.snapshot(), - ingest: (raw: unknown) => impl.ingest(raw), - reset: () => impl.reset(), - }; -} - -export type AuditStore = ReturnType; - -export const AuditDataProvider = shared; - diff --git a/frontend/src/components/panels/data/decisions-data-provider.ts b/frontend/src/components/panels/data/decisions-data-provider.ts deleted file mode 100644 index ad7967b4..00000000 --- a/frontend/src/components/panels/data/decisions-data-provider.ts +++ /dev/null @@ -1,63 +0,0 @@ - -import type { DecisionTraceEvent } from "#/lib/symm/events"; -import { isDecisionTraceEvent } from "#/lib/symm/events"; - -type Listener = () => void; - -class DecisionsDataProviderImpl { - private latest: DecisionTraceEvent | undefined; - private listeners = new Set(); - - subscribe(listener: Listener) { - this.listeners.add(listener); - - return () => { - this.listeners.delete(listener); - }; - } - - snapshot(): DecisionTraceEvent | undefined { - return this.latest; - } - - private notify() { - for (const listener of this.listeners) { - listener(); - } - } - - ingest(raw: unknown) { - if (!isDecisionTraceEvent(raw)) { - return; - } - - this.latest = raw; - this.notify(); - } - - reset() { - this.latest = undefined; - this.notify(); - } -} - -const shared = createDecisionsDataProviderImpl(); - -export const createDecisionsDataProvider = () => - createDecisionsDataProviderImpl(); - -function createDecisionsDataProviderImpl() { - const impl = new DecisionsDataProviderImpl(); - - return { - subscribe: (listener: Listener) => impl.subscribe(listener), - snapshot: () => impl.snapshot(), - ingest: (raw: unknown) => impl.ingest(raw), - reset: () => impl.reset(), - }; -} - -export type DecisionsStore = ReturnType; - -export const DecisionsDataProvider = shared; - diff --git a/frontend/src/components/panels/data/trade-history-data-provider.bench.ts b/frontend/src/components/panels/data/trade-history-data-provider.bench.ts deleted file mode 100644 index 650c9764..00000000 --- a/frontend/src/components/panels/data/trade-history-data-provider.bench.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { bench, describe } from "vitest"; - -import { TradeHistoryDataProvider } from "#/components/panels/data/trade-history-data-provider"; - -describe("TradeHistoryDataProvider", () => { - bench("tracks inventory open and close cycles", () => { - TradeHistoryDataProvider.reset(); - - for (let index = 0; index < 8; index += 1) { - const base = `SYM${index}`; - - TradeHistoryDataProvider.ingestBalance({ - type: "balances", - Currency: "EUR", - Inventory: { [base]: 10 + index }, - AvgEntry: { [base]: 0.2 + index * 0.01 }, - Unrealized: { [base]: index % 2 === 0 ? 0.05 : -0.03 }, - }); - - TradeHistoryDataProvider.ingestBalance({ - type: "balances", - Currency: "EUR", - Inventory: {}, - }); - } - - if (TradeHistoryDataProvider.snapshot().length !== 8) { - throw new Error("expected eight closed trades"); - } - }); -}); diff --git a/frontend/src/components/panels/data/trade-history-data-provider.test.ts b/frontend/src/components/panels/data/trade-history-data-provider.test.ts deleted file mode 100644 index 49c9fe9c..00000000 --- a/frontend/src/components/panels/data/trade-history-data-provider.test.ts +++ /dev/null @@ -1,101 +0,0 @@ -import { beforeEach, describe, expect, it } from "vitest"; - -import { TradeHistoryDataProvider } from "#/components/panels/data/trade-history-data-provider"; - -describe("TradeHistoryDataProvider", () => { - beforeEach(() => { - TradeHistoryDataProvider.reset(); - }); - - it("records a closed trade when inventory drops to zero", () => { - TradeHistoryDataProvider.ingestBalance({ - type: "balances", - Currency: "EUR", - Inventory: { H: 26.29 }, - AvgEntry: { H: 0.24 }, - Unrealized: { H: 0.13145 }, - }); - - TradeHistoryDataProvider.ingestBalance({ - type: "balances", - Currency: "EUR", - Inventory: {}, - }); - - const row = TradeHistoryDataProvider.snapshot()[0]; - - expect(row).toMatchObject({ - symbol: "H/EUR", - qty: 26.29, - entryPrice: 0.24, - realizedEur: 0.13145, - outcome: "profit", - reason: "position closed", - }); - }); - - it("finalizes audit exit rows with actual return", () => { - TradeHistoryDataProvider.ingestBalance({ - type: "balances", - Currency: "EUR", - Inventory: { BOBA: 20 }, - AvgEntry: { BOBA: 0.05 }, - }); - - TradeHistoryDataProvider.ingestAudit({ - event: "audit", - audit_event: "exit", - seq: 3, - ts: "2026-05-29T01:02:05Z", - symbol: "BOBA/EUR", - reason: "perspective TTL elapsed", - actual_return: -0.0973, - success: false, - slot_eur: 1, - }); - - const row = TradeHistoryDataProvider.snapshot()[0]; - - expect(row).toMatchObject({ - symbol: "BOBA/EUR", - outcome: "loss", - reason: "perspective TTL elapsed", - }); - expect(row?.realizedEur).toBeCloseTo(-0.0973, 8); - expect(row?.realizedPct).toBeCloseTo(-9.73, 8); - }); - - it("keeps newest closed trades first", () => { - TradeHistoryDataProvider.ingestBalance({ - type: "balances", - Currency: "EUR", - Inventory: { A: 1 }, - AvgEntry: { A: 1 }, - Unrealized: { A: 0.1 }, - }); - TradeHistoryDataProvider.ingestBalance({ - type: "balances", - Currency: "EUR", - Inventory: {}, - }); - - TradeHistoryDataProvider.ingestBalance({ - type: "balances", - Currency: "EUR", - Inventory: { B: 2 }, - AvgEntry: { B: 2 }, - Unrealized: { B: -0.2 }, - }); - TradeHistoryDataProvider.ingestBalance({ - type: "balances", - Currency: "EUR", - Inventory: {}, - }); - - const rows = TradeHistoryDataProvider.snapshot(); - - expect(rows).toHaveLength(2); - expect(rows[0]?.symbol).toBe("B/EUR"); - expect(rows[1]?.symbol).toBe("A/EUR"); - }); -}); diff --git a/frontend/src/components/panels/data/trade-history-data-provider.ts b/frontend/src/components/panels/data/trade-history-data-provider.ts deleted file mode 100644 index 4a28896f..00000000 --- a/frontend/src/components/panels/data/trade-history-data-provider.ts +++ /dev/null @@ -1,373 +0,0 @@ -import type { AuditEvent } from "#/lib/symm/events"; -import { isAuditEvent, walletPayloadFromFrame } from "#/lib/symm/events"; - -export type TradeHistoryOutcome = "profit" | "loss" | "flat"; - -export type TradeHistoryRow = { - key: string; - symbol: string; - qty?: number; - entryPrice?: number; - exitPrice?: number; - realizedEur: number; - realizedPct?: number; - outcome: TradeHistoryOutcome; - reason?: string; - closedAt: string; -}; - -type OpenTrade = { - symbol: string; - qty: number; - entryPrice: number; - markPrice?: number; - unrealizedEur?: number; - unrealizedPct?: number; - openedAt: string; -}; - -type PositionSnapshot = { - symbol: string; - qty: number; - entryPrice: number; - markPrice?: number; - unrealizedEur?: number; - unrealizedPct?: number; -}; - -type Listener = () => void; - -const MAX_ROWS = 120; - -const outcomeFromValue = (value: number): TradeHistoryOutcome => { - if (value > 0) { - return "profit"; - } - - if (value < 0) { - return "loss"; - } - - return "flat"; -}; - -const nowIso = () => new Date().toISOString(); - -const finiteNumber = (value: unknown): number | undefined => { - if (typeof value !== "number" || !Number.isFinite(value)) { - return undefined; - } - - return value; -}; - -const positionFromMonitorRow = (value: unknown): PositionSnapshot | null => { - if (typeof value !== "object" || value === null || Array.isArray(value)) { - return null; - } - - const record = value as Record; - const symbol = typeof record.symbol === "string" ? record.symbol.trim() : ""; - const qty = finiteNumber(record.qty); - const entryPrice = finiteNumber(record.avg_entry) ?? 0; - const markPrice = finiteNumber(record.mark); - const unrealizedEur = finiteNumber(record.unrealized); - const unrealizedPct = finiteNumber(record.unrealized_pct); - - if (symbol === "" || qty === undefined || qty <= 0) { - return null; - } - - return { - symbol, - qty, - entryPrice, - markPrice, - unrealizedEur, - unrealizedPct, - }; -}; - -/* -TradeHistoryDataProvider records closed trades and their final profit or loss. -Inventory drops and audit exit events both finalize rows. -*/ -class TradeHistoryDataProviderImpl { - private openBySymbol = new Map(); - private rows: readonly TradeHistoryRow[] = []; - private listeners = new Set(); - - subscribe(listener: Listener) { - this.listeners.add(listener); - - return () => { - this.listeners.delete(listener); - }; - } - - snapshot(): readonly TradeHistoryRow[] { - return this.rows; - } - - private notify() { - for (const listener of this.listeners) { - listener(); - } - } - - private pushRow(row: TradeHistoryRow) { - this.rows = [row, ...this.rows].slice(0, MAX_ROWS); - this.notify(); - } - - private syncOpenPositions(positions: PositionSnapshot[]) { - const seen = new Set(); - - for (const position of positions) { - seen.add(position.symbol); - - const existing = this.openBySymbol.get(position.symbol); - - if (existing === undefined) { - this.openBySymbol.set(position.symbol, { - symbol: position.symbol, - qty: position.qty, - entryPrice: position.entryPrice, - markPrice: position.markPrice, - unrealizedEur: position.unrealizedEur, - unrealizedPct: position.unrealizedPct, - openedAt: nowIso(), - }); - continue; - } - - existing.qty = position.qty; - existing.entryPrice = position.entryPrice; - existing.markPrice = position.markPrice; - existing.unrealizedEur = position.unrealizedEur; - existing.unrealizedPct = position.unrealizedPct; - } - - for (const [symbol, openTrade] of this.openBySymbol.entries()) { - if (seen.has(symbol)) { - continue; - } - - this.openBySymbol.delete(symbol); - this.finalizeOpenTrade(openTrade, openTrade.unrealizedEur ?? 0, { - realizedPct: openTrade.unrealizedPct, - reason: "position closed", - closedAt: nowIso(), - }); - } - } - - private finalizeOpenTrade( - openTrade: OpenTrade, - realizedEur: number, - details: { - realizedPct?: number; - exitPrice?: number; - reason?: string; - closedAt: string; - }, - ) { - const exitPrice = - details.exitPrice ?? - (openTrade.qty > 0 - ? openTrade.entryPrice + realizedEur / openTrade.qty - : undefined); - - this.pushRow({ - key: `${openTrade.symbol}:${details.closedAt}`, - symbol: openTrade.symbol, - qty: openTrade.qty, - entryPrice: openTrade.entryPrice, - exitPrice, - realizedEur, - realizedPct: details.realizedPct, - outcome: outcomeFromValue(realizedEur), - reason: details.reason, - closedAt: details.closedAt, - }); - } - - private positionsFromBalance( - raw: Record, - ): PositionSnapshot[] { - const payload = walletPayloadFromFrame(raw); - const currency = payload.Currency ?? "EUR"; - const inventory = payload.Inventory ?? {}; - const avgEntry = payload.AvgEntry ?? {}; - const unrealized = payload.Unrealized ?? {}; - const marks = payload.Marks ?? {}; - const positions: PositionSnapshot[] = []; - - for (const [base, qty] of Object.entries(inventory)) { - if (qty <= 0) { - continue; - } - - const symbol = `${base}/${currency}`; - const entryPrice = avgEntry[base] ?? 0; - const markPrice = marks[symbol]; - const unrealizedEur = unrealized[base]; - const entryCost = qty * entryPrice; - const unrealizedPct = - entryCost > 0 && unrealizedEur !== undefined - ? (unrealizedEur / entryCost) * 100 - : undefined; - - positions.push({ - symbol, - qty, - entryPrice, - markPrice, - unrealizedEur, - unrealizedPct, - }); - } - - return positions; - } - - ingestBalance(raw: Record) { - this.syncOpenPositions(this.positionsFromBalance(raw)); - } - - ingestPositions(raw: Record) { - const rows = Array.isArray(raw.positions) ? raw.positions : []; - const positions = rows - .map((row) => positionFromMonitorRow(row)) - .filter((row): row is PositionSnapshot => row !== null); - - this.syncOpenPositions(positions); - } - - ingestAudit(raw: unknown) { - if (!isAuditEvent(raw)) { - return; - } - - const auditEvent = raw.audit_event; - - if (auditEvent === "entry" || auditEvent === "trade_entry_fill") { - this.recordAuditEntry(raw); - return; - } - - if (auditEvent !== "exit" && auditEvent !== "trade_exit_fill") { - return; - } - - this.recordAuditExit(raw); - } - - private recordAuditEntry(event: AuditEvent) { - const symbol = event.symbol?.trim(); - - if (symbol === undefined || symbol === "") { - return; - } - - const fillPrice = event.fill_price; - const existing = this.openBySymbol.get(symbol); - - if (existing !== undefined) { - if (fillPrice !== undefined && fillPrice > 0) { - existing.entryPrice = fillPrice; - } - - return; - } - - this.openBySymbol.set(symbol, { - symbol, - qty: 0, - entryPrice: fillPrice ?? 0, - openedAt: event.ts, - }); - } - - private recordAuditExit(event: AuditEvent) { - const symbol = event.symbol?.trim(); - - if (symbol === undefined || symbol === "") { - return; - } - - const openTrade = this.openBySymbol.get(symbol); - const actualReturn = event.actual_return; - const entryCost = - openTrade !== undefined && openTrade.qty > 0 && openTrade.entryPrice > 0 - ? openTrade.qty * openTrade.entryPrice - : event.slot_eur; - const realizedEur = - actualReturn !== undefined && entryCost !== undefined - ? entryCost * actualReturn - : (openTrade?.unrealizedEur ?? 0); - const realizedPct = - actualReturn !== undefined - ? actualReturn * 100 - : openTrade?.unrealizedPct; - const exitPrice = event.fill_price; - - if (openTrade !== undefined) { - this.openBySymbol.delete(symbol); - this.finalizeOpenTrade(openTrade, realizedEur, { - realizedPct, - exitPrice, - reason: event.reason ?? event.why, - closedAt: event.ts, - }); - return; - } - - this.pushRow({ - key: `${symbol}:${event.seq}`, - symbol, - exitPrice, - realizedEur, - realizedPct, - outcome: - event.success === true - ? "profit" - : event.success === false - ? "loss" - : outcomeFromValue(realizedEur), - reason: event.reason ?? event.why, - closedAt: event.ts, - }); - } - - reset() { - this.openBySymbol.clear(); - this.rows = []; - this.notify(); - } -} - -const shared = createTradeHistoryDataProviderImpl(); - -export const createTradeHistoryDataProvider = () => - createTradeHistoryDataProviderImpl(); - -function createTradeHistoryDataProviderImpl() { - const impl = new TradeHistoryDataProviderImpl(); - - return { - subscribe: (listener: Listener) => impl.subscribe(listener), - snapshot: () => impl.snapshot(), - ingestBalance: (raw: Record) => impl.ingestBalance(raw), - ingestPositions: (raw: Record) => - impl.ingestPositions(raw), - ingestAudit: (raw: unknown) => impl.ingestAudit(raw), - reset: () => impl.reset(), - }; -} - -export type TradeHistoryStore = ReturnType< - typeof createTradeHistoryDataProvider ->; - -export const TradeHistoryDataProvider = shared; diff --git a/frontend/src/components/panels/data/trades-data-provider.bench.ts b/frontend/src/components/panels/data/trades-data-provider.bench.ts deleted file mode 100644 index 6ad504f1..00000000 --- a/frontend/src/components/panels/data/trades-data-provider.bench.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { bench, describe } from "vitest"; - -import { TradesDataProvider } from "#/components/panels/data/trades-data-provider"; - -const CURRENCY = "EUR"; -const PAPER_BALANCE_EUR = 193.69; - -const TRADE_FIXTURES = [ - { - base: "H", - symbol: "H/EUR", - qty: 26.29, - entryPrice: 0.24, - markPrice: 0.245, - }, - { - base: "GFI", - symbol: "GFI/EUR", - qty: 62.5, - entryPrice: 0.1129, - markPrice: 0.1131, - }, - { - base: "PEAQ", - symbol: "PEAQ/EUR", - qty: 20, - entryPrice: 0.0286, - markPrice: 0.0285, - }, - { - base: "XLM", - symbol: "XLM/EUR", - qty: 45, - entryPrice: 0.1451, - markPrice: 0.1457, - }, -] as const; - -const ingestFills = () => { - for (const trade of TRADE_FIXTURES) { - TradesDataProvider.ingest({ - OrderID: `entry-${trade.base}`, - Symbol: trade.symbol, - Side: "buy", - Qty: trade.qty, - Price: trade.entryPrice, - }); - } -}; - -const ingestInventory = () => { - TradesDataProvider.ingest({ - Type: "paper", - Currency: CURRENCY, - Balance: PAPER_BALANCE_EUR, - Inventory: Object.fromEntries( - TRADE_FIXTURES.map((trade) => [trade.base, trade.qty]), - ), - AvgEntry: Object.fromEntries( - TRADE_FIXTURES.map((trade) => [trade.base, trade.entryPrice]), - ), - Marks: Object.fromEntries( - TRADE_FIXTURES.map((trade) => [trade.symbol, trade.entryPrice]), - ), - }); -}; - -const refreshMarks = () => { - for (const trade of TRADE_FIXTURES) { - TradesDataProvider.setMark(trade.symbol, trade.markPrice); - } -}; - -describe("TradesDataProvider", () => { - bench("syncs open rows and ignores fills", () => { - TradesDataProvider.reset(); - ingestFills(); - ingestInventory(); - refreshMarks(); - - const rows = TradesDataProvider.snapshot(); - - if (rows.length !== TRADE_FIXTURES.length) { - throw new Error(`expected ${TRADE_FIXTURES.length} visible rows`); - } - }); -}); diff --git a/frontend/src/components/panels/data/trades-data-provider.test.ts b/frontend/src/components/panels/data/trades-data-provider.test.ts deleted file mode 100644 index 28277a41..00000000 --- a/frontend/src/components/panels/data/trades-data-provider.test.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { beforeEach, describe, expect, it } from "vitest"; - -import { TradesDataProvider } from "#/components/panels/data/trades-data-provider"; - -describe("TradesDataProvider", () => { - beforeEach(() => { - TradesDataProvider.reset(); - }); - - it("prefers live ticker marks over stale wallet marks", () => { - TradesDataProvider.setMark("MNT/EUR", 0.57); - - TradesDataProvider.ingest({ - Type: "paper", - Currency: "EUR", - Balance: 198.9, - Inventory: { MNT: 10 }, - AvgEntry: { MNT: 0.55 }, - Marks: { "MNT/EUR": 0.55 }, - }); - - const open = TradesDataProvider.snapshot().find( - (row) => row.kind === "open", - ); - - expect(open?.markPrice).toBe(0.57); - expect(open?.unrealizedPct).toBeCloseTo(((0.57 - 0.55) / 0.55) * 100, 5); - }); - - it("shows only open cards and never renders entry fills", () => { - TradesDataProvider.ingest({ - OrderID: "entry-1", - Symbol: "H/EUR", - Side: "buy", - Qty: 26.29, - Price: 0.24, - }); - - TradesDataProvider.ingest({ - Type: "paper", - Currency: "EUR", - Balance: 193.69, - Inventory: { H: 26.29 }, - AvgEntry: { H: 0.24 }, - Marks: { "H/EUR": 0.24 }, - }); - - const rows = TradesDataProvider.snapshot(); - - expect(rows).toHaveLength(1); - expect(rows[0]?.kind).toBe("open"); - expect(rows[0]?.symbol).toBe("H/EUR"); - }); - - it("does not show standalone entry fills", () => { - TradesDataProvider.ingest({ - OrderID: "entry-1", - Symbol: "MASK/EUR", - Side: "buy", - Qty: 10, - Price: 0.42, - }); - - expect(TradesDataProvider.snapshot()).toEqual([]); - }); - - it("refreshes open-card profit and loss from live marks", () => { - TradesDataProvider.ingest({ - Type: "paper", - Currency: "EUR", - Balance: 193.69, - Inventory: { H: 26.29 }, - AvgEntry: { H: 0.24 }, - Marks: { "H/EUR": 0.24 }, - }); - - TradesDataProvider.setMark("H/EUR", 0.245); - - const open = TradesDataProvider.snapshot()[0]; - - expect(open?.kind).toBe("open"); - expect(open?.markPrice).toBe(0.245); - expect(open?.unrealizedEur).toBeCloseTo(26.29 * 0.005, 8); - expect(open?.unrealizedPct).toBeCloseTo((0.005 / 0.24) * 100, 8); - }); - - it("returns a stable snapshot reference until data changes", () => { - TradesDataProvider.ingest({ - Type: "paper", - Currency: "EUR", - Balance: 193.69, - Inventory: { H: 26.29 }, - AvgEntry: { H: 0.24 }, - Marks: { "H/EUR": 0.24 }, - }); - - const first = TradesDataProvider.snapshot(); - const second = TradesDataProvider.snapshot(); - - expect(second).toBe(first); - - TradesDataProvider.setMark("H/EUR", 0.245); - - expect(TradesDataProvider.snapshot()).not.toBe(first); - }); - - it("ingests positions frames and populates open trade rows with authoritative P&L metrics", () => { - TradesDataProvider.ingest({ - type: "positions", - currency: "USD", - cash: 149.87, - open_positions: 1, - priced_positions: 1, - exit_value: 50.63, - exit_balance: 0.5, - liquidation_balance: 200.5, - liquidation_complete: true, - in_profit: true, - positions: [ - { - symbol: "BTC/USD", - qty: 0.001, - avg_entry: 50130, - mark: 50630, - exit_value: 50.63, - unrealized: 0.5, - unrealized_pct: 0.9974077, - priced: true, - stop_price: 49870, - peak_price: 50700, - offset: 0.015, - mark_source: "stop_monitor", - }, - ], - }); - - const rows = TradesDataProvider.snapshot(); - expect(rows).toHaveLength(1); - expect(rows[0]?.kind).toBe("open"); - expect(rows[0]?.symbol).toBe("BTC/USD"); - expect(rows[0]?.qty).toBe(0.001); - expect(rows[0]?.entryPrice).toBe(50130); - expect(rows[0]?.markPrice).toBe(50630); - expect(rows[0]?.unrealizedEur).toBe(0.5); - expect(rows[0]?.unrealizedPct).toBe(0.9974077); - }); -}); diff --git a/frontend/src/components/panels/data/trades-data-provider.ts b/frontend/src/components/panels/data/trades-data-provider.ts deleted file mode 100644 index f9e65374..00000000 --- a/frontend/src/components/panels/data/trades-data-provider.ts +++ /dev/null @@ -1,284 +0,0 @@ -import type { ExecutionFill, WalletPayload } from "#/lib/symm/events"; -import { - isExecutionFill, - isWalletPayload, - walletPayloadFromFrame, -} from "#/lib/symm/events"; - -export type TradePanelRow = { - key: string; - kind: "enter" | "exit" | "open"; - symbol: string; - side?: string; - qty?: number; - price?: number; - notionalEur?: number; - entryPrice?: number; - markPrice?: number; - unrealizedEur?: number; - unrealizedPct?: number; -}; - -type Listener = () => void; - -const MAX_OPEN = 12; - -const positionEconomics = ( - symbol: string, - base: string, - qty: number, - payload: WalletPayload, -) => { - const entryPrice = payload.AvgEntry?.[base]; - const markPrice = payload.Marks?.[symbol]; - - if (entryPrice === undefined || markPrice === undefined || qty <= 0) { - return { - entryPrice, - markPrice, - unrealizedEur: undefined, - unrealizedPct: undefined, - }; - } - - const unrealizedEur = qty * (markPrice - entryPrice); - const unrealizedPct = ((markPrice - entryPrice) / entryPrice) * 100; - - return { - entryPrice, - markPrice, - unrealizedEur, - unrealizedPct, - }; -}; - -/* -TradesDataProvider tracks open positions and recent fill history for the sidebar panel. -Open positions are driven by wallet snapshots; fills come from execution events. -*/ -class TradesDataProviderImpl { - private openRows: TradePanelRow[] = []; - private panelRows: readonly TradePanelRow[] = []; - private listeners = new Set(); - private markFallback = new Map(); - - subscribe(listener: Listener) { - this.listeners.add(listener); - - return () => { - this.listeners.delete(listener); - }; - } - - snapshot(): readonly TradePanelRow[] { - return this.panelRows; - } - - private rebuildPanelRows() { - this.panelRows = [...this.openRows]; - } - - setMark(symbol: string, markPrice: number) { - if (markPrice <= 0) { - return; - } - - this.markFallback.set(symbol, markPrice); - this.refreshOpenMarks(); - } - - private notify() { - for (const listener of this.listeners) { - listener(); - } - } - - private refreshOpenMarks() { - let changed = false; - - this.openRows = this.openRows.map((row) => { - if (row.kind !== "open" || row.qty === undefined) { - return row; - } - - const markPrice = this.markFallback.get(row.symbol) ?? row.markPrice; - - if (markPrice === undefined || row.entryPrice === undefined) { - return row; - } - - const unrealizedEur = row.qty * (markPrice - row.entryPrice); - const unrealizedPct = - ((markPrice - row.entryPrice) / row.entryPrice) * 100; - - if ( - row.markPrice === markPrice && - row.unrealizedEur === unrealizedEur && - row.unrealizedPct === unrealizedPct - ) { - return row; - } - - changed = true; - - return { - ...row, - markPrice, - unrealizedEur, - unrealizedPct, - }; - }); - - if (!changed) { - return; - } - - this.rebuildPanelRows(); - this.notify(); - } - - private syncInventory(payload: WalletPayload) { - const inventory = payload.Inventory ?? {}; - const next: TradePanelRow[] = []; - - for (const [base, qty] of Object.entries(inventory)) { - if (qty <= 0) { - continue; - } - - const symbol = `${base}/${payload.Currency ?? "EUR"}`; - const economics = positionEconomics(symbol, base, qty, payload); - const liveMark = this.markFallback.get(symbol); - const markPrice = liveMark ?? economics.markPrice; - - let unrealizedEur = economics.unrealizedEur; - let unrealizedPct = economics.unrealizedPct; - - if (markPrice !== undefined && economics.entryPrice !== undefined) { - unrealizedEur = qty * (markPrice - economics.entryPrice); - unrealizedPct = - ((markPrice - economics.entryPrice) / economics.entryPrice) * 100; - } - - next.push({ - key: `open:${base}`, - kind: "open", - symbol, - qty, - entryPrice: economics.entryPrice, - markPrice, - unrealizedEur, - unrealizedPct, - }); - } - - this.openRows = next.slice(0, MAX_OPEN); - this.rebuildPanelRows(); - this.notify(); - } - - private syncPositions(frame: Record) { - const positionsList = Array.isArray(frame.positions) ? frame.positions : []; - const next: TradePanelRow[] = []; - const checkFinite = (value: unknown): number | null => { - if (typeof value !== "number" || !Number.isFinite(value)) { - return null; - } - return value; - }; - - for (const pos of positionsList) { - if (typeof pos !== "object" || pos === null) { - continue; - } - - const record = pos as Record; - const symbol = typeof record.symbol === "string" ? record.symbol : ""; - const qty = checkFinite(record.qty); - const avgEntry = checkFinite(record.avg_entry); - const mark = checkFinite(record.mark) ?? 0; - const unrealized = checkFinite(record.unrealized); - const unrealizedPct = checkFinite(record.unrealized_pct); - - if (symbol === "" || qty === null || qty <= 0) { - continue; - } - - next.push({ - key: `open:${symbol}`, - kind: "open", - symbol, - qty, - entryPrice: avgEntry ?? undefined, - markPrice: mark, - unrealizedEur: unrealized ?? undefined, - unrealizedPct: unrealizedPct ?? undefined, - }); - } - - this.openRows = next.slice(0, MAX_OPEN); - this.rebuildPanelRows(); - this.notify(); - } - - ingestFill(_fill: ExecutionFill) { - // Open cards are derived from wallet inventory snapshots. Execution fills can - // arrive before the wallet frame and be used to create duplicate transient rows, - // so the sidebar keeps fills out of the visible snapshot. - } - - ingest(raw: unknown) { - if (isExecutionFill(raw)) { - this.ingestFill(raw); - return; - } - - if (typeof raw === "object" && raw !== null && !Array.isArray(raw)) { - const frame = raw as Record; - - if (frame.type === "balances" || frame.type === "wallet") { - this.syncInventory(walletPayloadFromFrame(frame)); - return; - } - - if (frame.type === "positions") { - this.syncPositions(frame); - return; - } - } - - if (!isWalletPayload(raw)) { - return; - } - - this.syncInventory(raw); - } - - reset() { - this.openRows = []; - this.panelRows = []; - this.markFallback.clear(); - this.notify(); - } -} - -const shared = createTradesDataProviderImpl(); - -export const createTradesDataProvider = () => createTradesDataProviderImpl(); - -function createTradesDataProviderImpl() { - const impl = new TradesDataProviderImpl(); - - return { - subscribe: (listener: Listener) => impl.subscribe(listener), - snapshot: () => impl.snapshot(), - ingest: (raw: unknown) => impl.ingest(raw), - setMark: (symbol: string, markPrice: number) => - impl.setMark(symbol, markPrice), - reset: () => impl.reset(), - }; -} - -export type TradesStore = ReturnType; - -export const TradesDataProvider = shared; diff --git a/frontend/src/components/panels/data/wallet-data-provider.ts b/frontend/src/components/panels/data/wallet-data-provider.ts deleted file mode 100644 index 14fbccf3..00000000 --- a/frontend/src/components/panels/data/wallet-data-provider.ts +++ /dev/null @@ -1,97 +0,0 @@ - -import type { WalletPayload } from "#/lib/symm/events"; -import { isWalletPayload } from "#/lib/symm/events"; - -export type WalletView = { - currency: string; - balance: number; - reservedEur: number; - feePct: number; - inventory: Record; - openCount: number; -}; - -const emptyWallet = (): WalletView => ({ - currency: "EUR", - balance: 0, - reservedEur: 0, - feePct: 0, - inventory: {}, - openCount: 0, -}); - -type Listener = () => void; - -/* -WalletDataProvider mirrors hub wallet snapshots for the header. -*/ -class WalletDataProviderImpl { - private latest = emptyWallet(); - private listeners = new Set(); - - subscribe(listener: Listener) { - this.listeners.add(listener); - - return () => { - this.listeners.delete(listener); - }; - } - - snapshot(): WalletView { - return this.latest; - } - - private notify() { - for (const listener of this.listeners) { - listener(); - } - } - - private toView(payload: WalletPayload): WalletView { - const inventory = payload.Inventory ?? {}; - let openCount = 0; - - for (const qty of Object.values(inventory)) { - if (qty > 0) { - openCount++; - } - } - - return { - currency: payload.Currency ?? "EUR", - balance: payload.Balance ?? 0, - reservedEur: payload.ReservedEUR ?? 0, - feePct: payload.FeePct ?? 0, - inventory, - openCount, - }; - } - - ingest(raw: unknown) { - if (!isWalletPayload(raw)) { - return; - } - - this.latest = this.toView(raw); - this.notify(); - } -} - -const shared = createWalletDataProviderImpl(); - -export const createWalletDataProvider = () => createWalletDataProviderImpl(); - -function createWalletDataProviderImpl() { - const impl = new WalletDataProviderImpl(); - - return { - subscribe: (listener: Listener) => impl.subscribe(listener), - snapshot: () => impl.snapshot(), - ingest: (raw: unknown) => impl.ingest(raw), - }; -} - -export type WalletStore = ReturnType; - -export const WalletDataProvider = shared; - diff --git a/frontend/src/components/panels/positions.test.tsx b/frontend/src/components/panels/positions.test.tsx deleted file mode 100644 index df00b982..00000000 --- a/frontend/src/components/panels/positions.test.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { describe, expect, it } from "vitest"; -import { - positionMoney, - positionPercent, - positionPrice, - positionQuantity, - signedPositionMoney, - unsignedPositionPercent, -} from "#/components/panels/positions"; - -describe("position dropdown precision", () => { - it("keeps low-priced assets visible below one cent", () => { - expect(positionPrice(0.00383512, "$")).toBe("$0.00383512"); - expect(positionPrice(0.31987654, "$")).toBe("$0.31987654"); - }); - - it("keeps higher-priced marks precise without overextending the row", () => { - expect(positionPrice(1.23456789, "$")).toBe("$1.234568"); - expect(positionPrice(43.052341, "$")).toBe("$43.0523"); - expect(positionPrice(1673.204321, "$")).toBe("$1673.2043"); - }); - - it("shows sub-cent position deltas and quantities", () => { - expect(positionQuantity(0.024)).toBe("0.02400000"); - expect(positionMoney(-0.32004321, "$")).toBe("-$0.3200"); - expect(signedPositionMoney(0.0054321, "$")).toBe("+$0.0054"); - }); - - it("shows percent precision for P&L and unsigned fees", () => { - expect(positionPercent(-0.804321)).toBe("-0.8043%"); - expect(positionPercent(1.312345)).toBe("+1.3123%"); - expect(unsignedPositionPercent(0.4)).toBe("0.4000%"); - }); -}); diff --git a/frontend/src/components/panels/positions.tsx b/frontend/src/components/panels/positions.tsx deleted file mode 100644 index 8c56900e..00000000 --- a/frontend/src/components/panels/positions.tsx +++ /dev/null @@ -1,156 +0,0 @@ -import { useSelector } from "@tanstack/react-store"; -import { balanceStore } from "#/collections/balance"; -import { statusStore } from "#/collections/status"; -import { Flex } from "#/components/ui/flex"; - -const POSITION_QUANTITY_DIGITS = 8; -const POSITION_MONEY_DIGITS = 4; -const POSITION_PERCENT_DIGITS = 4; -const SMALL_PRICE_DIGITS = 8; -const MID_PRICE_DIGITS = 6; -const LARGE_PRICE_DIGITS = 4; -const MID_PRICE_THRESHOLD = 1; -const LARGE_PRICE_THRESHOLD = 10; - -export const positionQuantity = (value: number) => { - return value.toFixed(POSITION_QUANTITY_DIGITS); -}; - -export const positionPriceDigits = (value: number) => { - const absolute = Math.abs(value); - - if (absolute >= LARGE_PRICE_THRESHOLD) { - return LARGE_PRICE_DIGITS; - } - - if (absolute >= MID_PRICE_THRESHOLD) { - return MID_PRICE_DIGITS; - } - - return SMALL_PRICE_DIGITS; -}; - -export const positionMoney = ( - value: number, - symbol: string, - fractionDigits = POSITION_MONEY_DIGITS, -) => { - const prefix = value < 0 ? "-" : ""; - const absolute = Math.abs(value).toFixed(fractionDigits); - - if (symbol.length === 1) { - return `${prefix}${symbol}${absolute}`; - } - - return `${prefix}${absolute} ${symbol}`; -}; - -export const positionPrice = (value: number, symbol: string) => { - return positionMoney(value, symbol, positionPriceDigits(value)); -}; - -export const signedPositionMoney = (value: number, symbol: string) => { - const sign = value >= 0 ? "+" : "-"; - - return `${sign}${positionMoney(Math.abs(value), symbol)}`; -}; - -export const positionPercent = (value: number) => { - const sign = value >= 0 ? "+" : ""; - - return `${sign}${value.toFixed(POSITION_PERCENT_DIGITS)}%`; -}; - -export const unsignedPositionPercent = (value: number) => { - return `${value.toFixed(POSITION_PERCENT_DIGITS)}%`; -}; - -/* -PositionsPanel lists the open book with live expected liquidation P&L from the -bid side. Rendered as a dropdown from the wallet button. -*/ -export const PositionsPanel = () => { - const { positionViews } = useSelector(statusStore, (state) => state); - const { symbol } = useSelector(balanceStore, (state) => state); - - return ( - -

- Open positions -

- - {positionViews.length === 0 ? ( -

- No open positions -

- ) : ( - positionViews.map((position) => { - const positive = position.priced && position.unrealized >= 0; - - return ( -
-
- {position.symbol} - - {position.priced - ? signedPositionMoney(position.unrealized, symbol) - : "pricing"} - -
-
- - {positionQuantity(position.qty)} @{" "} - {positionPrice(position.avgEntry, symbol)} - - {position.priced ? ( - - {positionPercent(position.unrealizedPct)} - - ) : null} -
-
- mark - - {position.priced - ? positionPrice(position.mark, symbol) - : "waiting"} - -
- {position.stopPrice !== undefined && position.stopPrice > 0 ? ( -
- stop - - {positionPrice(position.stopPrice, symbol)} - -
- ) : null} - {position.priced && position.exitFeeRate > 0 ? ( -
- exit fee - - {unsignedPositionPercent(position.exitFeeRate * 100)} - -
- ) : null} -
- ); - }) - )} -
- ); -}; diff --git a/frontend/src/components/sidebar-section.tsx b/frontend/src/components/sidebar-section.tsx deleted file mode 100644 index b83f3b6a..00000000 --- a/frontend/src/components/sidebar-section.tsx +++ /dev/null @@ -1,26 +0,0 @@ - -export const SidebarSection = ({ - title, - children, - className = "", - fill = false, -}: { - title: string; - children: React.ReactNode; - className?: string; - fill?: boolean; -}) => { - return ( -
-

- {title} -

-
- {children} -
-
- ); -}; - diff --git a/frontend/src/components/terminal/allocation-side.bench.ts b/frontend/src/components/terminal/allocation-side.bench.ts new file mode 100644 index 00000000..4ce59444 --- /dev/null +++ b/frontend/src/components/terminal/allocation-side.bench.ts @@ -0,0 +1,82 @@ +import { bench, describe } from "vitest"; +import type { Action } from "#/collections/actions"; +import { Circular } from "#/collections/circular"; +import { allocationSummary } from "./allocation-side"; + +const history = (frame: T) => { + const frames = Circular(8); + frames.push(frame); + + return frames; +}; + +const action = (symbol: string, score: number): Action => ({ + id: `1:${symbol}`, + tick: 1, + symbol, + type: "entry", + side: "buy", + verdict: "allow", + reason: "matched_branch", + score, + entryLine: 0, + entryScore: score, + entryConfidence: score, + fraction: 0.05, + price: 100, + branchKey: "field/resonance/causal", + reasonSource: "causal", + reasonCategory: "edge", + decisionAt: "2026-07-06T10:00:00Z", +}); + +const symbols = Array.from({ length: 24 }, (_, index) => `SYM${index}/USD`); +const actions = Object.fromEntries( + symbols + .filter((_, index) => index % 7 === 0) + .map((symbol, index) => [symbol, history(action(symbol, 0.65 + index / 100))]), +); +const causal = Object.fromEntries( + symbols.map((symbol, index) => [ + symbol, + history({ + source: "causal", + symbol, + at: "2026-07-06T10:00:00Z", + strength: 0.2 + index / 40, + baseline: 0.25, + }), + ]), +); +const manifold = Object.fromEntries( + symbols.map((symbol) => [ + symbol, + history({ source: "manifold", symbol, at: "2026-07-06T10:00:00Z" }), + ]), +); +const resonance = Object.fromEntries( + symbols.map((symbol, index) => [ + symbol, + history({ + source: "resonance", + symbol, + at: "2026-07-06T10:00:00Z", + confidence: 0.3 + index / 50, + }), + ]), +); + +describe("allocationSummary", () => { + bench("sizes a live allocation cross-section", () => { + allocationSummary({ + focusSymbol: "BTC/USD", + symbols, + actions, + balances: [{ asset: "USD", balance: 1200, available: 1000, reserved: 50 }], + causal, + manifold, + positions: [], + resonance, + }); + }); +}); diff --git a/frontend/src/components/terminal/allocation-side.test.ts b/frontend/src/components/terminal/allocation-side.test.ts new file mode 100644 index 00000000..c7467bf0 --- /dev/null +++ b/frontend/src/components/terminal/allocation-side.test.ts @@ -0,0 +1,74 @@ +import { describe, expect, it } from "vitest"; +import type { Action } from "#/collections/actions"; +import { Circular } from "#/collections/circular"; +import { allocationSummary } from "./allocation-side"; + +const action = (symbol: string, entryScore: number): Action => ({ + id: `1:${symbol}`, + tick: 1, + symbol, + type: "entry", + side: "buy", + verdict: "allow", + reason: "matched_branch", + score: entryScore, + entryLine: 0, + entryScore, + entryConfidence: 1, + fraction: 0.05, + price: 100, + branchKey: "field/resonance/causal", + reasonSource: "causal", + reasonCategory: "edge", + decisionAt: "2026-07-06T10:00:00Z", +}); + +const history = (frame: T) => { + const frames = Circular(4); + frames.push(frame); + + return frames; +}; + +describe("allocationSummary", () => { + it("sizes the live ladder cross-section and keeps the instrument order stable", () => { + const summary = allocationSummary({ + focusSymbol: "BTC/USD", + symbols: ["BTC/USD", "ETH/USD", "SOL/USD"], + actions: { + "SOL/USD": history(action("SOL/USD", 0.95)), + }, + balances: [{ asset: "USD", balance: 1200, available: 1000, reserved: 50 }], + causal: { + "BTC/USD": history({ source: "causal", symbol: "BTC/USD", at: "1", strength: 0.2, baseline: 0.3 }), + "ETH/USD": history({ source: "causal", symbol: "ETH/USD", at: "1", strength: 0.6, baseline: 0.3 }), + "SOL/USD": history({ source: "causal", symbol: "SOL/USD", at: "1", strength: 0.95, baseline: 0.3 }), + }, + manifold: { + "BTC/USD": history({ source: "manifold", symbol: "BTC/USD", at: "1" }), + "ETH/USD": history({ source: "manifold", symbol: "ETH/USD", at: "1" }), + "SOL/USD": history({ source: "manifold", symbol: "SOL/USD", at: "1" }), + }, + positions: [ + { symbol: "BTC/USD", qty: 0.5, entry_price: 100, mark: 120, pnl: 10, return_pct: 0.2 }, + ], + resonance: { + "BTC/USD": history({ source: "resonance", symbol: "BTC/USD", at: "1", confidence: 0.2 }), + "ETH/USD": history({ source: "resonance", symbol: "ETH/USD", at: "1", confidence: 0.6 }), + "SOL/USD": history({ source: "resonance", symbol: "SOL/USD", at: "1", confidence: 0.95 }), + }, + }); + + expect(summary.rows.map((row) => row.symbol)).toEqual([ + "BTC/USD", + "ETH/USD", + "SOL/USD", + ]); + expect(summary.deployable).toBe(1000); + expect(summary.deployed).toBe(60); + expect(summary.reserved).toBe(50); + expect(summary.rows[1]?.inPlay).toBe(true); + expect(summary.rows[2]?.allocated).toBe(true); + expect(summary.rows[2]?.notional).toBeGreaterThan(0); + }); +}); diff --git a/frontend/src/components/terminal/allocation-side.tsx b/frontend/src/components/terminal/allocation-side.tsx new file mode 100644 index 00000000..b6d50998 --- /dev/null +++ b/frontend/src/components/terminal/allocation-side.tsx @@ -0,0 +1,400 @@ +import type { ReactNode } from "react"; +import type { Action } from "#/collections/actions"; +import type { Balance } from "#/collections/balances"; +import type { CausalFrame } from "#/collections/causal"; +import type { ManifoldFrame } from "#/collections/manifold"; +import type { Order } from "#/collections/orders"; +import type { Position } from "#/collections/positions"; +import type { ResonanceFrame } from "#/collections/resonance"; + +type History = { values: () => T[] }; + +type AllocationInput = { + focusSymbol: string; + symbols: string[]; + actions: Record>; + balances: Balance[]; + causal: Record>; + manifold: Record>; + positions: Position[]; + resonance: Record>; +}; + +type AllocationRow = { + action?: Action; + allocated: boolean; dotColor: string; inPlay: boolean; symbol: string; + edge: number; edgeLeft: number; edgeWidth: number; + notional: number; share: number; support: number; + thesis: number; xPct: number; +}; + +export type AllocationSummary = { + deployable: number; deployed: number; positionCount: number; + mad: number; median: number; medianPct: number; + quote: string; reserved: number; + rows: AllocationRow[]; + threshold: number; thresholdPct: number; +}; + +const latest = (history?: History): T | undefined => + history?.values().at(-1); + +const finite = (value: unknown): number => { + const number = typeof value === "number" ? value : Number(value); + + return Number.isFinite(number) ? number : 0; +}; + +const probability = (value: unknown): number => + Math.min(1, Math.max(0, finite(value))); + +const median = (values: number[]): number => { + if (values.length === 0) { + return 0; + } + + const order = [...values].sort((left, right) => left - right); + + return order[Math.floor(order.length / 2)] ?? 0; +}; + +const quoteAsset = (symbol: string): string => symbol.split("/")[1] ?? ""; + +const money = (value: number, quote: string): string => + `${value.toFixed(2)} ${quote}`; + +const balanceAmount = ( + balances: Balance[], + quote: string, + field: "available" | "balance" | "reserved", +): number => + balances.reduce( + (sum, balance) => + String(balance.asset).toUpperCase() === quote.toUpperCase() + ? sum + finite(balance[field]) + : sum, + 0, + ); + +export const allocationSummary = ({ + focusSymbol, + symbols, + actions, + balances, + causal, + manifold, + positions, + resonance, +}: AllocationInput): AllocationSummary => { + const known = new Set([ + ...Object.keys(actions), + ...Object.keys(causal), + ...Object.keys(manifold), + ...Object.keys(resonance), + ]); + const orderedSymbols = [ + ...symbols.filter((symbol) => known.has(symbol)), + ...[...known].filter((symbol) => !symbols.includes(symbol)).sort(), + ]; + const quote = quoteAsset(focusSymbol); + const deployable = balanceAmount(balances, quote, "available"); + const reserved = balanceAmount(balances, quote, "reserved"); + const deployed = positions + .filter((position) => quoteAsset(position.symbol) === quote) + .reduce((sum, position) => sum + position.qty * position.mark, 0); + const rows = orderedSymbols.map((symbol) => { + const action = latest(actions[symbol]); + const causalFrame = latest(causal[symbol]); + const manifoldFrame = latest(manifold[symbol]); + const resonanceFrame = latest(resonance[symbol]); + const support = [causalFrame, manifoldFrame, resonanceFrame].filter( + Boolean, + ).length; + const score = + action?.entryScore ?? + causalFrame?.strength ?? + Math.min( + probability(resonanceFrame?.confidence), + probability(causalFrame?.confidence), + ); + const thesis = probability(score) * Math.sqrt(Math.max(1, support)); + + return { + action, + allocated: false, + dotColor: "var(--f4)", + edge: 0, + edgeLeft: 0, + edgeWidth: 0, + inPlay: + support >= 2 && + finite(causalFrame?.strength) >= finite(causalFrame?.baseline), + notional: 0, + share: 0, + support, + symbol, + thesis, + xPct: 0, + }; + }); + const scores = rows.map((row) => row.thesis); + const med = median(scores); + const dispersion = + scores.length > 0 + ? scores.reduce((sum, score) => sum + Math.abs(score - med), 0) / + scores.length + : 0; + const threshold = med + dispersion; + const sumPositive = scores.reduce((sum, score) => sum + Math.max(0, score), 0); + const lo = Math.min(...scores, threshold) * 0.92; + const hi = Math.max(...scores, threshold) * 1.04; + const span = hi - lo || 1; + const pct = (value: number) => + Math.min(100, Math.max(0, ((value - lo) / span) * 100)); + const thresholdPct = pct(threshold); + const medianPct = pct(med); + + for (const row of rows) { + row.edge = row.thesis - threshold; + row.share = + row.edge > 0 && row.thesis + sumPositive > 0 + ? row.edge / (row.thesis + sumPositive) + : 0; + row.allocated = row.action?.verdict === "allow" && row.edge > 0; + row.notional = row.allocated ? deployable * row.share : 0; + row.inPlay = row.inPlay || row.edge > 0; + row.xPct = pct(row.thesis); + row.edgeLeft = Math.min(thresholdPct, row.xPct); + row.edgeWidth = row.edge > 0 ? Math.max(0, row.xPct - thresholdPct) : 0; + row.dotColor = row.allocated + ? "var(--acc)" + : row.inPlay + ? "var(--info)" + : "var(--f4)"; + } + + return { + deployable, + deployed, + mad: dispersion, + median: med, + medianPct, + positionCount: positions.length, + quote, + reserved, + rows, + threshold, + thresholdPct, + }; +}; + +const visibleRows = (alloc: AllocationSummary) => + alloc.rows.filter((row) => row.allocated || row.inPlay || row.action); + +export const AllocationMain = ({ alloc }: { alloc: AllocationSummary }) => { + const rows = visibleRows(alloc); + + return ( +
+
+ cross-section + + median {alloc.median.toFixed(3)} + + + mad {alloc.mad.toFixed(3)} + + entry {alloc.threshold.toFixed(3)} + live ladder frames +
+ +
+ symbol + thesis score {"->"} sqrt(confirmations) + edge + share + notional +
+ +
+ {rows.length === 0 ? ( +
+ waiting for backend decision frames +
+ ) : null} + + {rows.map((row) => ( +
+ + {row.symbol.split("/")[0]} + +
+
+
+
+
+
+
+ 0 ? "var(--up)" : "var(--f4)" }} + > + {row.edge >= 0 ? "+" : "-"} + {Math.abs(row.edge).toFixed(3)} + + + {(row.share * 100).toFixed(1)}% + + + {row.allocated ? money(row.notional, alloc.quote) : "-"} + +
+ ))} +
+ +
+ {[ + ["var(--acc)", "allocated"], + ["var(--info)", "in play · below edge"], + ["var(--f4)", "scanned"], + ].map(([color, label]) => ( + + + {label} + + ))} + + entry line + +
+
+ ); +}; + +const Panel = ({ children }: { children: ReactNode }) => ( +
{children}
+); + +const Bar = ({ percent }: { percent: number }) => ( +
+
+
+); + +export const AllocationSidePanel = ({ alloc, orders }: { + alloc: AllocationSummary; + orders: Order[]; +}) => { + const deployedPercent = + alloc.deployable > 0 + ? Math.min(100, Math.round((alloc.deployed / alloc.deployable) * 100)) + : 0; + const rows = alloc.rows.filter((row) => row.allocated); + + return ( +
+ +
+ Capital deployment + + {deployedPercent}% + +
+
+ share of deployable free cash +
+ +
+ deployed {money(alloc.deployed, alloc.quote)} + reserved {money(alloc.reserved, alloc.quote)} +
+ {orders.length > 0 ? ( +
+
+ Reserved orders +
+ {orders.map((order) => ( +
+ + {order.pair} {order.side} {order.type} + + + {money(finite(order.reserved_amount), order.reserved_asset)} + +
+ ))} +
+ ) : null} +
+ + +
Position sizing
+
+ notional {alloc.quote} per allocated symbol +
+
+ {rows.length === 0 ? ( +
+ waiting for admitted backend actions +
+ ) : null} + {rows.map((row) => ( +
+
+ {row.symbol.split("/")[0]} + + {money(row.notional, alloc.quote)} + +
+
+
+
+
+ + {(row.share * 100).toFixed(1)}% + +
+
+ ))} +
+ +
+ ); +}; diff --git a/frontend/src/components/terminal/canvas.ts b/frontend/src/components/terminal/canvas.ts new file mode 100644 index 00000000..bae0856a --- /dev/null +++ b/frontend/src/components/terminal/canvas.ts @@ -0,0 +1,203 @@ +export const TERMINAL_COLORS = { + background: "#0e0c0a", + surface: "#17140f", + line: "#2b251e", + lineStrong: "#3a342b", + foreground: "#f4efe5", + muted: "#938a7e", + amber: "#e8a33d", + cyan: "#7fbacb", + green: "#9cc06e", + red: "#d5786a", +} as const; + +export const resizeCanvas = ( + canvas: HTMLCanvasElement, +): CanvasRenderingContext2D | null => { + const width = Math.max(1, canvas.clientWidth); + const height = Math.max(1, canvas.clientHeight); + const ratio = window.devicePixelRatio || 1; + + if ( + canvas.width !== Math.floor(width * ratio) || + canvas.height !== Math.floor(height * ratio) + ) { + canvas.width = Math.floor(width * ratio); + canvas.height = Math.floor(height * ratio); + } + + const context = canvas.getContext("2d"); + + if (context === null) { + return null; + } + + context.setTransform(ratio, 0, 0, ratio, 0, 0); + + return context; +}; + +export const clearCanvas = ( + context: CanvasRenderingContext2D, + width: number, + height: number, +) => { + context.clearRect(0, 0, width, height); + context.fillStyle = TERMINAL_COLORS.background; + context.fillRect(0, 0, width, height); +}; + +export const clamp01 = (value: number): number => + Math.min(1, Math.max(0, value)); + +const hexToRgb = (hex: string): [number, number, number] => [ + parseInt(hex.slice(1, 3), 16), + parseInt(hex.slice(3, 5), 16), + parseInt(hex.slice(5, 7), 16), +]; + +const lerp = (left: number, right: number, amount: number): number => + left + (right - left) * amount; + +const mix = (left: string, right: string, amount: number): string => { + const a = hexToRgb(left); + const b = hexToRgb(right); + + return `rgb(${Math.round(lerp(a[0], b[0], amount))},${Math.round(lerp(a[1], b[1], amount))},${Math.round(lerp(a[2], b[2], amount))})`; +}; + +export const heatColor = (value: number): string => { + const normalized = clamp01(value); + + if (normalized < 0.45) { + return mix(TERMINAL_COLORS.background, "#1b2232", normalized / 0.45); + } + + if (normalized < 0.7) { + return mix("#1b2232", TERMINAL_COLORS.cyan, (normalized - 0.45) / 0.25); + } + + if (normalized < 0.88) { + return mix( + TERMINAL_COLORS.cyan, + TERMINAL_COLORS.amber, + (normalized - 0.7) / 0.18, + ); + } + + return mix( + TERMINAL_COLORS.amber, + TERMINAL_COLORS.foreground, + (normalized - 0.88) / 0.12, + ); +}; + +export const drawGrid = ( + context: CanvasRenderingContext2D, + width: number, + height: number, + padding = 14, +) => { + context.strokeStyle = TERMINAL_COLORS.line; + context.lineWidth = 1; + + for (let index = 0; index <= 4; index += 1) { + const y = padding + index * ((height - padding * 2) / 4); + context.beginPath(); + context.moveTo(padding, y); + context.lineTo(width - padding, y); + context.stroke(); + } +}; + +export const drawPolyline = ( + context: CanvasRenderingContext2D, + points: Array<{ x: number; y: number }>, + color: string, + dashed = false, +) => { + if (points.length < 2) { + return; + } + + context.strokeStyle = color; + context.lineWidth = 1.8; + context.setLineDash(dashed ? [4, 3] : []); + context.beginPath(); + + for (let index = 0; index < points.length; index += 1) { + const point = points[index]; + + if (index === 0) { + context.moveTo(point.x, point.y); + continue; + } + + context.lineTo(point.x, point.y); + } + + context.stroke(); + context.setLineDash([]); +}; + +const matrixExtent = (matrix: number[][]) => { + let min = Number.POSITIVE_INFINITY; + let max = Number.NEGATIVE_INFINITY; + + for (const row of matrix) { + for (const value of row) { + if (!Number.isFinite(value)) { + continue; + } + + min = Math.min(min, value); + max = Math.max(max, value); + } + } + + if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min) { + return { min: 0, max: 1 }; + } + + return { min, max }; +}; + +export const drawMatrix = ( + context: CanvasRenderingContext2D, + width: number, + height: number, + matrix: number[][], + contour = false, +) => { + clearCanvas(context, width, height); + + if (matrix.length === 0 || (matrix[0]?.length ?? 0) === 0) { + drawGrid(context, width, height); + return; + } + + const { min, max } = matrixExtent(matrix); + const rows = matrix.length; + const columns = matrix[0]?.length ?? 0; + const cellWidth = width / columns; + const cellHeight = height / rows; + + for (let rowIndex = 0; rowIndex < rows; rowIndex += 1) { + for (let columnIndex = 0; columnIndex < columns; columnIndex += 1) { + const value = matrix[rowIndex]?.[columnIndex] ?? min; + let normalized = (value - min) / (max - min); + + if (contour) { + normalized = Math.floor(normalized / 0.12) * 0.12; + } + + context.fillStyle = heatColor(normalized); + context.fillRect( + columnIndex * cellWidth, + rowIndex * cellHeight, + cellWidth + 1, + cellHeight + 1, + ); + } + } +}; diff --git a/frontend/src/components/terminal/charts.tsx b/frontend/src/components/terminal/charts.tsx new file mode 100644 index 00000000..3feed210 --- /dev/null +++ b/frontend/src/components/terminal/charts.tsx @@ -0,0 +1,530 @@ +import { useSelector } from "@tanstack/react-store"; +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { appStore } from "#/collections/app"; +import { manifoldStore } from "#/collections/manifold"; +import { measurementsStore } from "#/collections/measurements"; +import { resonanceStore } from "#/collections/resonance"; +import { + clearCanvas, + drawGrid, + drawMatrix, + drawPolyline, + resizeCanvas, + TERMINAL_COLORS, +} from "#/components/terminal/canvas"; + +type Draw = ( + context: CanvasRenderingContext2D, + width: number, + height: number, +) => void; + +const asRecord = (value: unknown): Record | null => + value !== null && typeof value === "object" && !Array.isArray(value) + ? (value as Record) + : null; + +const numberArray = (value: unknown): number[] => + Array.isArray(value) + ? value.filter((item): item is number => typeof item === "number") + : []; + +const recordArray = (value: unknown): Record[] => + Array.isArray(value) + ? value.flatMap((item) => { + const record = asRecord(item); + return record === null ? [] : [record]; + }) + : []; + +const numberMatrix = (value: unknown): number[][] => + Array.isArray(value) + ? value.map((row) => numberArray(row)).filter((row) => row.length > 0) + : []; + +const frameOutput = ( + frame: Record | null | undefined, +): Record | null => asRecord(frame?.output); + +const frameMatrix = ( + frame: Record | null | undefined, +): number[][] => { + const output = frameOutput(frame); + + for (const value of [ + frame?.rho, + output?.rho, + frame?.matrix, + output?.matrix, + frame?.grid, + output?.grid, + ]) { + const matrix = numberMatrix(value); + + if (matrix.length > 0) { + return matrix; + } + } + + for (const value of [ + frame?.state, + output?.state, + frame?.values, + output?.values, + ]) { + const row = numberArray(value); + + if (row.length > 0) { + return [row]; + } + } + + return []; +}; + +const finiteNumber = (value: unknown): number | null => + typeof value === "number" && Number.isFinite(value) ? value : null; + +const stringValue = (value: unknown): string => + typeof value === "string" ? value.trim() : ""; + +const drawWaiting = ( + context: CanvasRenderingContext2D, + width: number, + height: number, + message: string, +) => { + clearCanvas(context, width, height); + drawGrid(context, width, height); + context.fillStyle = TERMINAL_COLORS.muted; + context.font = "11px JetBrains Mono, monospace"; + context.fillText(message, 18, 52); +}; + +const PREDICTION_HISTORY_LIMIT = 130; + +export type TerminalPredictionSample = { + key: string; + symbol: string; + actual: number; + prediction: number; + error: number; +}; + +export const terminalPredictionSampleFromFrame = ( + frame: unknown, +): TerminalPredictionSample | null => { + const root = asRecord(frame); + + if (root === null) { + return null; + } + + const actual = finiteNumber(root.flow); + const prediction = finiteNumber(root.baseline); + + if (actual === null || prediction === null) { + return null; + } + + const symbol = stringValue(root.symbol) || "resonance"; + const timestamp = stringValue(root.at); + const error = finiteNumber(root.surprise) ?? Math.abs(actual - prediction); + + return { + key: + timestamp === "" + ? `${symbol}:${actual}:${prediction}:${error}` + : `${symbol}:${timestamp}`, + symbol, + actual, + prediction, + error, + }; +}; + +const StaticCanvas = ({ draw }: { draw: Draw }) => { + const canvasRef = useRef(null); + + useEffect(() => { + const canvas = canvasRef.current; + + if (canvas === null) { + return; + } + + const render = () => { + const context = resizeCanvas(canvas); + + if (context === null) { + return; + } + + draw(context, canvas.clientWidth, canvas.clientHeight); + }; + + render(); + const observer = new ResizeObserver(render); + observer.observe(canvas); + + return () => observer.disconnect(); + }, [draw]); + + return ; +}; + +export const TerminalFluidChart = ({ + contour = false, +}: { + contour?: boolean; +}) => { + const focusSymbol = useSelector(appStore, (state) => state.focusSymbol); + const frame = useSelector( + manifoldStore, + (state) => state.manifold[focusSymbol]?.values().at(-1) ?? null, + ); + const matrix = useMemo(() => frameMatrix(frame), [frame]); + const carriers = useMemo(() => recordArray(frame?.carriers), [frame]); + const draw = useCallback( + (context, width, height) => { + if (matrix.length === 0) { + drawWaiting(context, width, height, "waiting for manifold field"); + return; + } + + drawMatrix(context, width, height, matrix, contour); + + const columns = matrix[0]?.length ?? 0; + const rows = matrix.length; + + if (columns === 0 || rows === 0) { + return; + } + + for (const carrier of carriers) { + const cellX = finiteNumber(carrier.cell_x); + const cellZ = finiteNumber(carrier.cell_z); + + if (cellX === null || cellZ === null) { + continue; + } + + const role = String(carrier.role ?? ""); + const x = (cellX / Math.max(columns - 1, 1)) * width; + const y = (cellZ / Math.max(rows - 1, 1)) * height; + const radius = role === "whale" ? 4 : 2.5; + + context.fillStyle = + role === "whale" ? TERMINAL_COLORS.amber : TERMINAL_COLORS.cyan; + context.shadowColor = context.fillStyle; + context.shadowBlur = role === "whale" ? 14 : 6; + context.beginPath(); + context.arc(x, y, radius, 0, Math.PI * 2); + context.fill(); + context.shadowBlur = 0; + } + }, + [matrix, carriers, contour], + ); + + return ; +}; + +export const TerminalPredictionChart = () => { + const focusSymbol = useSelector(appStore, (state) => state.focusSymbol); + const frame = useSelector( + resonanceStore, + (state) => state.resonance[focusSymbol]?.values().at(-1) ?? null, + ); + const sample = useMemo(() => terminalPredictionSampleFromFrame(frame), [frame]); + const [samples, setSamples] = useState([]); + + useEffect(() => { + setSamples((previous) => { + if ( + previous.length === 0 || + previous[previous.length - 1]?.symbol === focusSymbol + ) { + return previous; + } + + return []; + }); + }, [focusSymbol]); + + useEffect(() => { + if (sample === null) { + return; + } + + setSamples((previous) => { + const last = previous[previous.length - 1]; + + if (last?.symbol !== sample.symbol) { + return [sample]; + } + + if (last.key === sample.key) { + return previous; + } + + return [...previous, sample].slice(-PREDICTION_HISTORY_LIMIT); + }); + }, [sample]); + + const draw = useCallback( + (context, width, height) => { + if (samples.length === 0) { + drawWaiting(context, width, height, "waiting for resonance history"); + return; + } + + clearCanvas(context, width, height); + drawGrid(context, width, height, 18); + + const values = samples + .flatMap((entry) => [entry.actual, entry.prediction]) + .filter(Number.isFinite); + + if (values.length === 0) { + return; + } + + let min = Math.min(...values); + let max = Math.max(...values); + const span = max > min ? max - min : 1; + const margin = span * 0.08; + min -= margin; + max += margin; + const paddedSpan = max > min ? max - min : 1; + const paddingX = 18; + const plotWidth = Math.max(1, width - paddingX * 2); + const plotHeight = Math.max(1, height - 46); + const denominator = Math.max(samples.length - 1, 1); + const xFor = (index: number) => + paddingX + (index / denominator) * plotWidth; + const yFor = (value: number) => + height - 26 - ((value - min) / paddedSpan) * plotHeight; + const actualPoints = samples.map((entry, index) => ({ + x: xFor(index), + y: yFor(entry.actual), + })); + const predictionPoints = samples.map((entry, index) => ({ + x: xFor(index), + y: yFor(entry.prediction), + })); + + context.fillStyle = "rgba(232, 163, 61, 0.18)"; + context.beginPath(); + for (const [index, point] of actualPoints.entries()) { + if (index === 0) { + context.moveTo(point.x, point.y); + } else { + context.lineTo(point.x, point.y); + } + } + for (let index = predictionPoints.length - 1; index >= 0; index -= 1) { + const point = predictionPoints[index]; + context.lineTo(point.x, point.y); + } + context.closePath(); + context.fill(); + + drawPolyline(context, actualPoints, TERMINAL_COLORS.foreground); + drawPolyline(context, predictionPoints, TERMINAL_COLORS.cyan, true); + + const latest = samples[samples.length - 1]; + + if (latest !== undefined) { + context.fillStyle = TERMINAL_COLORS.amber; + context.beginPath(); + context.arc( + xFor(samples.length - 1), + yFor(latest.actual), + 2.6, + 0, + Math.PI * 2, + ); + context.fill(); + context.fillStyle = TERMINAL_COLORS.muted; + context.font = "10px JetBrains Mono, monospace"; + context.fillText(`ε ${latest.error.toFixed(4)}`, 18, height - 8); + } + }, + [samples], + ); + + return ; +}; + +export const TerminalHawkesChart = () => { + const focusSymbol = useSelector(appStore, (state) => state.focusSymbol); + const frame = useSelector( + measurementsStore, + (state) => state.measurements[focusSymbol]?.hawkes?.values().at(-1) ?? null, + ); + const output = frame?.metrics; + const values = numberArray([ + output?.baseline, + output?.intensity, + output?.buyIntensity, + output?.sellIntensity, + output?.branching, + output?.radius, + ]); + const draw = useCallback( + (context, width, height) => { + if (values.length === 0) { + drawWaiting(context, width, height, "waiting for hawkes output"); + return; + } + + drawMatrix(context, width, height, [values]); + }, + [values], + ); + + return ; +}; + +export const terminalResonanceLayerMatrixFromFrame = ( + frame: Record | null, +): number[][] => { + const latent = numberArray(frame?.latent); + const modes = numberArray([frame?.flow, frame?.stress, frame?.coupling]); + const energy = numberArray([frame?.baseline, frame?.energy, frame?.surprise]); + + return [latent, modes, energy].filter((row) => row.length > 0); +}; + +export const TerminalManifoldChart = () => { + const focusSymbol = useSelector(appStore, (state) => state.focusSymbol); + const frame = useSelector( + manifoldStore, + (state) => state.manifold[focusSymbol]?.values().at(-1) ?? null, + ); + const matrix = frameMatrix(frame); + const draw = useCallback( + (context, width, height) => { + if (matrix.length === 0) { + drawWaiting(context, width, height, "waiting for manifold rho"); + return; + } + + drawMatrix(context, width, height, matrix); + }, + [matrix], + ); + + return ; +}; + +export const TerminalResonanceChart = () => { + const focusSymbol = useSelector(appStore, (state) => state.focusSymbol); + const frame = useSelector( + resonanceStore, + (state) => state.resonance[focusSymbol]?.values().at(-1) ?? null, + ); + const matrix = terminalResonanceLayerMatrixFromFrame(frame); + const draw = useCallback( + (context, width, height) => { + if (matrix.length === 0) { + drawWaiting(context, width, height, "waiting for resonance layers"); + return; + } + + drawMatrix(context, width, height, matrix); + }, + [matrix], + ); + + return ; +}; + +export const TerminalCognitiveChart = () => { + const draw = useCallback((context, width, height) => { + drawWaiting(context, width, height, "waiting for cognitive frames"); + }, []); + + return ; +}; + +export const TerminalSignalHeatmap = ({ + kind, +}: { + kind: "confidence" | "surprise"; +}) => { + const readings = useSelector(measurementsStore, (state) => state); + const matrix = useMemo( + () => + Object.values(readings.measurements).flatMap((sources) => + Object.values(sources).flatMap((history) => + history.values().flatMap((frame) => { + const category = frame.categories.at(0); + const value = + kind === "confidence" + ? category?.confidence + : category?.surprisal; + + return typeof value === "number" ? [[value]] : []; + }), + ), + ), + [readings, kind], + ); + const draw = useCallback( + (context, width, height) => { + if (matrix.length === 0) { + drawWaiting(context, width, height, "waiting for signal readings"); + return; + } + + drawMatrix(context, width, height, matrix); + }, + [matrix], + ); + + return ; +}; + +export const TerminalPositionChart = ({ + positions, +}: { + positions: Array<{ + key: string; + symbol: string; + pnlPercentText: string; + profitable: boolean; + }>; +}) => { + const draw = useCallback( + (context, width, height) => { + clearCanvas(context, width, height); + drawGrid(context, width, height); + const rowHeight = Math.max( + 22, + (height - 24) / Math.max(positions.length, 1), + ); + + positions.forEach((position, index) => { + const y = 18 + index * rowHeight; + const value = Number.parseFloat(position.pnlPercentText) || 0; + const bar = Math.min(width * 0.42, Math.abs(value) * 18); + const origin = width * 0.5; + + context.fillStyle = TERMINAL_COLORS.muted; + context.font = "10px JetBrains Mono, monospace"; + context.fillText(position.symbol, 12, y + 4); + context.fillStyle = position.profitable + ? TERMINAL_COLORS.green + : TERMINAL_COLORS.red; + context.fillRect(value >= 0 ? origin : origin - bar, y - 6, bar, 10); + }); + }, + [positions], + ); + + return ; +}; + +export const terminalFluidMatrixFromFrame = frameMatrix; diff --git a/frontend/src/components/terminal/cognitive-viz.ts b/frontend/src/components/terminal/cognitive-viz.ts new file mode 100644 index 00000000..77d8d8ee --- /dev/null +++ b/frontend/src/components/terminal/cognitive-viz.ts @@ -0,0 +1,166 @@ +import { + type CortexBeam, + type CortexTree, + cortexTreeFromReading, + drawCortexTree, +} from "#/components/terminal/cortex-tree"; + +const clamp = (value: number, min: number, max: number): number => + Math.min(max, Math.max(min, value)); + +export type CognitivePosterior = { + winner: string; + winnerPercent: string; + winnerBits: string; + runnerBits: string; + kl: string; + marginPercent: number; + entropy: string; + entropyThreshold: string; + entropyPercent: number; + ambiguous: boolean; + classes: Array<{ + name: string; + percent: number; + color: string; + foreground: string; + }>; +}; + +export const cognitivePosteriorFromReading = ( + reading: Record | null, +): CognitivePosterior => { + const tree = cortexTreeFromReading(reading); + + if (tree === null) { + return { + winner: "waiting", + winnerPercent: "0%", + winnerBits: "0.00", + runnerBits: "0.00", + kl: "0.000", + marginPercent: 0, + entropy: "0.00", + entropyThreshold: "0.00", + entropyPercent: 0, + ambiguous: false, + classes: [], + }; + } + + const sorted = tree.classes + .map((entry) => ({ + name: entry.name, + probability: entry.probability, + })) + .sort((left, right) => right.probability - left.probability); + const winner = sorted[0]; + const runner = sorted[1]; + + if (winner === undefined) { + return { + winner: "waiting", + winnerPercent: "0%", + winnerBits: "0.00", + runnerBits: "—", + kl: "—", + marginPercent: 0, + entropy: + typeof reading?.entropyBits === "number" + ? reading.entropyBits.toFixed(2) + : "0.00", + entropyThreshold: + typeof reading?.entropyThreshold === "number" + ? reading.entropyThreshold.toFixed(2) + : "0.00", + entropyPercent: 0, + ambiguous: reading?.ambiguous === true, + classes: [], + }; + } + + const winnerProbability = clamp(winner.probability, 0.001, 0.999); + const runnerProbability = + runner === undefined ? null : clamp(runner.probability, 0.001, 0.999); + const winnerBits = -Math.log2(winnerProbability); + const runnerBits = + runnerProbability === null ? null : -Math.log2(runnerProbability); + const kl = + runnerProbability === null + ? null + : winnerProbability * + Math.log2(winnerProbability / Math.max(runnerProbability, 1e-9)); + const entropyRatio = + reading !== null && + typeof reading.entropyBits === "number" && + typeof reading.entropyThreshold === "number" && + reading.entropyThreshold > 0 + ? reading.entropyBits / reading.entropyThreshold + : 0; + + return { + winner: winner.name, + winnerPercent: `${Math.round(winnerProbability * 100)}%`, + winnerBits: winnerBits.toFixed(2), + runnerBits: runnerBits === null ? "—" : runnerBits.toFixed(2), + kl: kl === null ? "—" : kl.toFixed(3), + marginPercent: + runnerBits === null + ? 0 + : Math.round(clamp((runnerBits - winnerBits) / 4, 0, 1) * 100), + entropy: + typeof reading?.entropyBits === "number" + ? reading.entropyBits.toFixed(2) + : "0.00", + entropyThreshold: + typeof reading?.entropyThreshold === "number" + ? reading.entropyThreshold.toFixed(2) + : "0.00", + entropyPercent: Math.round(clamp(entropyRatio, 0, 1) * 100), + ambiguous: reading?.ambiguous === true, + classes: sorted.map((entry, index) => ({ + name: entry.name, + percent: Math.round(entry.probability * 100), + color: index === 0 ? "var(--acc)" : "var(--info)", + foreground: index === 0 ? "var(--f1)" : "var(--f3)", + })), + }; +}; + +export const cognitiveBeamsFromReading = ( + reading: Record | null, +): CortexBeam[] => { + const tree = cortexTreeFromReading(reading); + + if (tree === null) { + return []; + } + + return tree.beams; +}; + +export const cognitiveTreeFromReading = ( + reading: Record | null, +): CortexTree | null => cortexTreeFromReading(reading); + +export const drawCognitiveTree = ( + context: CanvasRenderingContext2D, + width: number, + height: number, + reading: Record | null, +): void => { + const tree = cognitiveTreeFromReading(reading); + + if (tree === null) { + context.clearRect(0, 0, width, height); + context.fillStyle = "#938a7e"; + context.font = "11px JetBrains Mono, monospace"; + context.textAlign = "center"; + context.fillText("waiting for cognitive reading", width / 2, height / 2); + context.textAlign = "left"; + + return; + } + + drawCortexTree(context, width, height, tree); +}; diff --git a/frontend/src/components/terminal/context.tsx b/frontend/src/components/terminal/context.tsx new file mode 100644 index 00000000..9b840efa --- /dev/null +++ b/frontend/src/components/terminal/context.tsx @@ -0,0 +1,47 @@ + + +export const ContextStrip = ({ + label, + symbols, + meta, + activeSymbol, + onSelect, +}: { + label: string; + symbols: string[]; + meta?: string; + activeSymbol?: string; + onSelect?: (symbol: string) => void; +}) => ( +
+ + {label} + + {symbols.map((symbol) => { + const active = activeSymbol === symbol; + + return ( + + ); + })} + {meta ? ( + + {meta} + + ) : null} +
+); \ No newline at end of file diff --git a/frontend/src/components/terminal/cortex-panels.tsx b/frontend/src/components/terminal/cortex-panels.tsx new file mode 100644 index 00000000..ca9b08fe --- /dev/null +++ b/frontend/src/components/terminal/cortex-panels.tsx @@ -0,0 +1,271 @@ +import { + cognitiveBeamsFromReading, + cognitivePosteriorFromReading, +} from "#/components/terminal/cognitive-viz"; + +const finite = (value: unknown): number | null => + typeof value === "number" && Number.isFinite(value) ? value : null; + +const clamp = (value: number, min: number, max: number): number => + Math.min(max, Math.max(min, value)); + +export const CortexBeamList = ({ + reading, +}: { + reading: Record | null; +}) => { + const beams = cognitiveBeamsFromReading(reading); + + if (beams.length === 0) { + return ( +
+ waiting for cognitive beam reading +
+ ); + } + + return ( +
+ {beams.map((beam) => ( +
+ + #{beam.rank} + + + {beam.sequence || "root"} + +
+
+
+ + {beam.score} + +
+ ))} +
+ ); +}; + +export const CortexSidePanels = ({ + reading, +}: { + reading: Record | null; +}) => { + const posterior = cognitivePosteriorFromReading(reading); + const lookaheadScore = finite(reading?.lookaheadScore); + const decay = + lookaheadScore === null + ? "—" + : Math.exp(Math.min(0, lookaheadScore)).toFixed(3); + const replays = finite(reading?.lookaheadPaths); + const entropyBits = finite(reading?.entropyBits); + const entropyThreshold = finite(reading?.entropyThreshold); + const inhibition = + entropyBits !== null && entropyThreshold !== null && entropyThreshold > 0 + ? `${Math.round(clamp((entropyBits / entropyThreshold) * 100, 0, 100))}%` + : "—"; + const remPhaseColor = + reading?.sideline === true + ? "var(--down)" + : reading?.ambiguous === true + ? "var(--warn)" + : "var(--info)"; + + return ( +
+
+
+ + Attractor basin · classify + + + {posterior.winner} {posterior.winnerPercent} + +
+
+ softmax posterior · b/[class]/[sequence] +
+
+ {posterior.classes.length === 0 ? ( +
+ waiting for attractor basin +
+ ) : ( + posterior.classes.map((row) => ( +
+ + {row.name} + +
+
+
+ + {row.percent}% + +
+ )) + )} +
+
+ +
+
+ Contrastive evidence +
+
+ routing margin · winner vs runner-up +
+
+ + + +
+
+
+ separation margin + {posterior.marginPercent}% +
+
+
+
+
+
+ +
+
+ + Branch entropy gate + + + {posterior.ambiguous ? "ambiguous" : "decisive"} + +
+
+ shannon H vs uniform threshold +
+
+ + {posterior.entropy}b + +
+
+
+ + thr {posterior.entropyThreshold} + +
+
+ +
+
+ + REM consolidation + + + {reading?.sideline + ? "sideline" + : reading?.ambiguous + ? "rem-replay" + : "awake"} + +
+
+ episodic replay · decay · retroactive inhibition +
+
+ + + +
+
+
+ ); +}; + +const StatBlock = ({ + label, + value, + tone = "var(--f1)", + large = false, +}: { + label: string; + value: string; + tone?: string; + large?: boolean; +}) => ( +
+
+ {label} +
+
+ {value} +
+
+); diff --git a/frontend/src/components/terminal/cortex-tree.ts b/frontend/src/components/terminal/cortex-tree.ts new file mode 100644 index 00000000..0edb1ab5 --- /dev/null +++ b/frontend/src/components/terminal/cortex-tree.ts @@ -0,0 +1,418 @@ +import type { + CognitiveBranch, + CognitiveBeam as FrameBeam, +} from "#/collections/cognitive"; +import { TERMINAL_COLORS } from "#/components/terminal/canvas"; + +export type CortexBeam = { + rank: number; + sequence: string; + score: string; + percent: number; + color: string; +}; + +export type CortexClass = { + name: string; + probability: number; +}; + +export type CortexNode = CognitiveBranch & { + children: CortexNode[]; +}; + +export type CortexTree = { + beamWidth: number; + maxDepth: number; + nodeCount: number; + root: CortexNode; + nodes: CortexNode[]; + beams: CortexBeam[]; + classes: CortexClass[]; + beamPrefixes: Set; +}; + +const finite = (value: unknown): number | null => + typeof value === "number" && Number.isFinite(value) ? value : null; + +const numberField = ( + reading: Record, + key: string, +): number | null => finite(reading[key]); + +const stringField = (value: unknown, fallback = ""): string => + typeof value === "string" ? value : fallback; + +const branchesFromReading = ( + reading: Record, +): CognitiveBranch[] => { + const branches = reading.branches; + + if (!Array.isArray(branches)) { + return []; + } + + return branches.flatMap((entry) => { + if (entry === null || typeof entry !== "object") { + return []; + } + + const record = entry as Record; + const id = finite(record.id); + const parentId = finite(record.parentId); + const depth = finite(record.depth); + const probability = finite(record.probability); + const count = finite(record.count); + + if ( + id === null || + parentId === null || + depth === null || + probability === null || + count === null + ) { + return []; + } + + return [ + { + id, + parentId, + token: stringField(record.token, "node"), + prefix: stringField(record.prefix), + depth, + probability, + count, + }, + ]; + }); +}; + +const frameBeams = (reading: Record): FrameBeam[] => { + const beams = reading.beams; + + if (!Array.isArray(beams)) { + return []; + } + + return beams.flatMap((entry) => { + if (entry === null || typeof entry !== "object") { + return []; + } + + const record = entry as Record; + const score = finite(record.score); + const sequence = stringField(record.sequence); + + if (score === null || sequence === "") { + return []; + } + + return [{ sequence, score }]; + }); +}; + +const beamsFromReading = (reading: Record): CortexBeam[] => { + const beams = frameBeams(reading); + + if (beams.length === 0) { + return []; + } + + const maxScore = Math.max(...beams.map((beam) => beam.score)); + + return beams.map((beam, index) => ({ + rank: index + 1, + sequence: beam.sequence, + score: beam.score.toFixed(2), + percent: Math.round(Math.exp(beam.score - maxScore) * 100), + color: index === 0 ? "var(--acc)" : "var(--info)", + })); +}; + +const classesFromReading = ( + reading: Record, +): CortexClass[] => { + const classes = reading.classes; + + if (!Array.isArray(classes)) { + return []; + } + + return classes + .flatMap((entry) => { + if (entry === null || typeof entry !== "object") { + return []; + } + + const record = entry as Record; + const probability = finite(record.probability); + const name = stringField(record.name); + + if (probability === null || name === "") { + return []; + } + + return [{ name, probability }]; + }) + .sort((left, right) => right.probability - left.probability); +}; + +const prefixesFromSequence = (sequence: string): Set => { + const prefixes = new Set([""]); + + if (sequence === "") { + return prefixes; + } + + const tokens = sequence.split("_").filter(Boolean); + let prefix = ""; + + for (const token of tokens) { + prefix = prefix === "" ? token : `${prefix}_${token}`; + prefixes.add(prefix); + } + + return prefixes; +}; + +const activePrefixesFrom = ( + reading: Record, + beam: FrameBeam | undefined, +): Set => { + const sequence = stringField(reading.sequence); + + if (sequence !== "") { + return prefixesFromSequence(sequence); + } + + return prefixesFromSequence(beam?.sequence ?? ""); +}; + +export const cortexTreeFromReading = ( + reading: Record | null, +): CortexTree | null => { + if (reading === null) { + return null; + } + + const branches = branchesFromReading(reading); + + if (branches.length === 0) { + return null; + } + + const byID = new Map(); + + for (const branch of branches) { + byID.set(branch.id, { ...branch, children: [] }); + } + + let root: CortexNode | null = null; + + for (const node of byID.values()) { + if (node.parentId < 0 || node.depth === 0) { + root = node; + continue; + } + + byID.get(node.parentId)?.children.push(node); + } + + if (root === null) { + return null; + } + + for (const node of byID.values()) { + node.children.sort((left, right) => { + if (left.probability === right.probability) { + return left.token.localeCompare(right.token); + } + + return right.probability - left.probability; + }); + } + + const nodes = [...byID.values()].sort((left, right) => left.id - right.id); + const beamWidth = numberField(reading, "beamWidth"); + const maxHops = numberField(reading, "maxHops"); + const nodeCount = numberField(reading, "nodeCount"); + + if (beamWidth === null || maxHops === null || nodeCount === null) { + return null; + } + + const maxDepth = Math.max(1, maxHops); + const rawBeams = frameBeams(reading); + + return { + beamWidth, + maxDepth, + nodeCount, + root, + nodes, + beams: beamsFromReading(reading), + classes: classesFromReading(reading), + beamPrefixes: activePrefixesFrom(reading, rawBeams[0]), + }; +}; + +type PositionedNode = { + node: CortexNode; + x: number; + y: number; +}; + +const isOnBeam = (tree: CortexTree, node: CortexNode): boolean => + tree.beamPrefixes.has(node.prefix); + +const truncate = (value: string, maxLength: number): string => + value.length <= maxLength ? value : value.slice(0, maxLength - 1); + +export const drawCortexTree = ( + context: CanvasRenderingContext2D, + width: number, + height: number, + tree: CortexTree, +): void => { + context.clearRect(0, 0, width, height); + context.fillStyle = TERMINAL_COLORS.background; + context.fillRect(0, 0, width, height); + + const padLeft = 74; + const padRight = 116; + const padTop = 44; + const padBottom = 26; + const usableWidth = Math.max(1, width - padLeft - padRight); + const usableHeight = Math.max(1, height - padTop - padBottom); + const leaves: CortexNode[] = []; + + const collectLeaves = (node: CortexNode): void => { + if (node.children.length === 0) { + leaves.push(node); + return; + } + + for (const child of node.children) { + collectLeaves(child); + } + }; + + collectLeaves(tree.root); + + const leafY = new Map(); + + for (const [index, leaf] of leaves.entries()) { + leafY.set(leaf.id, leaves.length > 1 ? index / (leaves.length - 1) : 0.5); + } + + const assignY = (node: CortexNode): number => { + if (node.children.length === 0) { + return leafY.get(node.id) ?? 0.5; + } + + const childY = node.children.map(assignY); + + return childY.reduce((sum, value) => sum + value, 0) / childY.length; + }; + + const yByID = new Map(); + + const recordY = (node: CortexNode): number => { + const y = assignY(node); + yByID.set(node.id, y); + + for (const child of node.children) { + recordY(child); + } + + return y; + }; + + recordY(tree.root); + + const xFor = (depth: number): number => + padLeft + (depth / Math.max(1, tree.maxDepth)) * usableWidth; + const yFor = (node: CortexNode): number => + padTop + (yByID.get(node.id) ?? 0.5) * usableHeight; + const positions = new Map(); + + for (const node of tree.nodes) { + positions.set(node.id, { + node, + x: xFor(node.depth), + y: yFor(node), + }); + } + + const drawEdges = (node: CortexNode): void => { + const from = positions.get(node.id); + + if (from === undefined) { + return; + } + + for (const child of node.children) { + const to = positions.get(child.id); + + if (to === undefined) { + continue; + } + + const onBeam = isOnBeam(tree, node) && isOnBeam(tree, child); + const middleX = (from.x + to.x) / 2; + + context.strokeStyle = onBeam + ? TERMINAL_COLORS.amber + : TERMINAL_COLORS.line; + context.lineWidth = onBeam ? 2.2 : 0.6 + child.probability * 2.4; + context.globalAlpha = onBeam ? 1 : 0.45 + child.probability * 0.4; + context.beginPath(); + context.moveTo(from.x, from.y); + context.bezierCurveTo(middleX, from.y, middleX, to.y, to.x, to.y); + context.stroke(); + + if (!onBeam) { + context.globalAlpha = 0.7; + context.fillStyle = TERMINAL_COLORS.muted; + context.font = "8px JetBrains Mono, monospace"; + context.textAlign = "center"; + context.fillText( + child.probability.toFixed(2), + middleX, + (from.y + to.y) / 2 - 3, + ); + } + + drawEdges(child); + } + }; + + drawEdges(tree.root); + context.globalAlpha = 1; + + for (const positioned of positions.values()) { + const { node, x, y } = positioned; + const onBeam = isOnBeam(tree, node); + const radius = node.depth === 0 ? 5.5 : onBeam ? 4.2 : 3; + + context.fillStyle = onBeam ? TERMINAL_COLORS.amber : "#1f1a14"; + context.strokeStyle = onBeam + ? TERMINAL_COLORS.amber + : TERMINAL_COLORS.lineStrong; + context.lineWidth = 1; + context.beginPath(); + context.arc(x, y, radius, 0, Math.PI * 2); + context.fill(); + context.stroke(); + + if (node.depth > 0 && (onBeam || node.children.length === 0)) { + context.fillStyle = onBeam + ? TERMINAL_COLORS.foreground + : TERMINAL_COLORS.muted; + context.font = `${onBeam ? "600 " : ""}9.5px JetBrains Mono, monospace`; + context.textAlign = "left"; + context.fillText(truncate(node.token, 12), x + 7, y + 3.2); + } + } +}; diff --git a/frontend/src/components/terminal/dashboard-rail.tsx b/frontend/src/components/terminal/dashboard-rail.tsx new file mode 100644 index 00000000..ffc1a4c3 --- /dev/null +++ b/frontend/src/components/terminal/dashboard-rail.tsx @@ -0,0 +1,177 @@ +import { useSelector } from "@tanstack/react-store"; +import { type Action, actionStore } from "#/collections/actions"; +import { type Execution, executionsStore } from "#/collections/executions"; +import { type Position, positionsStore } from "#/collections/positions"; +import { ColumnHeader } from "#/components/dashboard/header"; +import { fixed } from "#/components/terminal/decision-format"; +import { cn } from "#/lib/utils"; + +const DecisionRows = ({ decisions }: { decisions: Action[] }) => ( +
+
+ Symbol + Comb + Fraction + Verdict +
+ {decisions.length === 0 ? ( +
+ waiting for decision frames +
+ ) : null} + {decisions.map((decision) => { + return ( +
+
+
+ {decision.symbol} +
+
trader
+
+ + {fixed(Number(decision.score))} + + + {(decision.fraction * 100).toFixed(2)}% + + + + {decision.verdict} + + +
+ ); + })} +
+); + +const PositionRows = ({ + positions, + quote, + observed, +}: { + positions: Position[]; + quote: string; + observed: boolean; +}) => ( +
+ {positions.length === 0 ? ( +
+ {observed ? "no open positions" : "waiting for position frames"} +
+ ) : null} + {positions.slice(-8).map((position) => { + return ( +
+
+ {position.symbol} + + P/L {position.pnl.toFixed(4)} {quote} + +
+
+ + entry {fixed(position.entry_price)} / mark {fixed(position.mark)} + + + {(position.return_pct * 100).toFixed(2)}% + +
+
+ ); + })} +
+); + +const AuditRows = ({ executions }: { executions: Execution[] }) => ( +
+ {executions.length === 0 ? ( +
+ waiting for execution frames +
+ ) : null} + {executions.map((execution) => ( +
+
+ + {execution.order_status} + + #{execution.exec_id} +
+
+ {execution.side} / {execution.symbol} +
+
+ ))} +
+); + +export const DashboardRail = () => { + const actions = useSelector(actionStore, (state) => + Object.values(state.actions).flatMap((history) => history.values()), + ); + const allowed = actions.filter((action) => action.verdict === "allow"); + const denied = actions.filter((action) => action.verdict !== "allow"); + const positionsState = useSelector(positionsStore, (state) => state); + const executions = useSelector(executionsStore, (state) => + state.executions.flat(), + ); + const positions = positionsState.positions; + const quote = positions[0]?.symbol.split("/")[1] ?? "USD"; + const net = positions.reduce((sum, position) => sum + position.pnl, 0); + + return ( +
+
+ + {allowed.length} allow · {denied.length} deny + + } + /> + +
+
+ + {positions.length === 0 + ? "" + : `net ${net.toFixed(4)} ${quote} · `} + {positions.length} open + + } + /> + +
+
+ + +
+
+ ); +}; diff --git a/frontend/src/components/terminal/decision-format.ts b/frontend/src/components/terminal/decision-format.ts new file mode 100644 index 00000000..07d9597f --- /dev/null +++ b/frontend/src/components/terminal/decision-format.ts @@ -0,0 +1,113 @@ +/* +decision-format is production-safe only for literal formatting helpers such as +fixed and whyLabel. The score-distribution functions below are legacy fixture +helpers retained for non-live tests; live decision and allocation surfaces must +read backend entry statistics and verdicts directly. +*/ + +const sorted = (values: number[]): number[] => + [...values].sort((left, right) => left - right); + +/* +median returns the middle value (mean of the two middle values for even length). +*/ +export const median = (values: number[]): number => { + if (values.length === 0) { + return 0; + } + + const order = sorted(values); + const mid = Math.floor(order.length / 2); + + return order.length % 2 === 0 + ? (order[mid - 1] + order[mid]) / 2 + : order[mid]; +}; + +/* +mad is the median absolute deviation from the median — a robust spread that the +entry gate adds to the median so only standout candidates clear it. +*/ +export const mad = (values: number[]): number => { + if (values.length === 0) { + return 0; + } + + const center = median(values); + + return median(values.map((value) => Math.abs(value - center))); +}; + +/* +fixed formats a score to three decimals, the precision the tmp terminal used for +combined scores and edges. +*/ +export const fixed = (value: number): string => value.toFixed(3); + +/* +entryLineStats is a non-live legacy helper for tests/fixtures. Production +decision surfaces must not derive trader gates from frontend score arrays. +*/ +// Robust standout factor: median + 1.5×MAD marks a candidate as clearing the +// gate, mirroring the ~1.5 MAD outlier convention. Only scores meaningfully above +// the pack qualify, so the gate adapts to the live distribution's spread. +const STANDOUT_MAD = 1.5; + +export const entryLineStats = ( + scores: number[], +): { line: number; median: number; mad: number } => { + const med = median(scores); + const dispersion = mad(scores); + + // The gate is median + 1.5×MAD, but it can never exceed the best candidate's + // score: a tight distribution must not veto its own top opportunity. Clamping + // to the max keeps the single strongest candidate deployable while still + // rejecting the pack below it. + const ceiling = scores.length > 0 ? Math.max(...scores) : 0; + const line = Math.min(med + STANDOUT_MAD * dispersion, ceiling); + + return { line, median: med, mad: dispersion }; +}; + +/* +allocationEntryStats mirrors the tmp allocation x-ray. It intentionally uses the +upper middle score for even sets and the mean absolute deviation from that +center, matching the functional mockup's sizing gate. +*/ +export const allocationEntryStats = ( + scores: number[], +): { threshold: number; median: number; mad: number } => { + if (scores.length === 0) { + return { threshold: 0, median: 0, mad: 0 }; + } + + const order = sorted(scores); + const med = order[Math.floor(order.length / 2)]; + const dispersion = + order.reduce((sum, score) => sum + Math.abs(score - med), 0) / order.length; + + return { threshold: med + dispersion, median: med, mad: dispersion }; +}; + +const REASON_LABELS: Record = { + matched_branch: "matched branch", + below_entry: "below entry line", + below_edge: "below edge", + held: "already held", + no_slot: "no slot", + no_causal_uplift: "no causal uplift", + no_manifold_field: "no manifold field", +}; + +/* +whyLabel turns a raw walk/decider reason token into the human phrase the surface +shows. Unknown reasons pass through with underscores normalised; an empty reason +renders as an em dash so a missing reason is visible, not blank. +*/ +export const whyLabel = (reason?: string): string => { + if (reason === undefined || reason.trim() === "") { + return "—"; + } + + return REASON_LABELS[reason] ?? reason.replace(/_/g, " "); +}; diff --git a/frontend/src/components/terminal/decision-side.tsx b/frontend/src/components/terminal/decision-side.tsx new file mode 100644 index 00000000..4a1d5980 --- /dev/null +++ b/frontend/src/components/terminal/decision-side.tsx @@ -0,0 +1,288 @@ +import { useSelector } from "@tanstack/react-store"; +import { appStore } from "#/collections/app"; +import { causalStore } from "#/collections/causal"; +import { + type CognitiveReading, + cognitiveScopes, + cognitiveStore, +} from "#/collections/cognitive"; + +type Rung = { + rung: number; + name: string; + desc: string; + key: string; + color: string; +}; + +const RUNGS: Rung[] = [ + { + rung: 1, + name: "Association", + desc: "P(y | x)", + key: "beta", + color: "var(--info)", + }, + { + rung: 2, + name: "Intervention", + desc: "P(y | do(x))", + key: "intervention", + color: "var(--acc)", + }, + { + rung: 3, + name: "Counterfactual", + desc: "Pearl strength", + key: "strength", + color: "var(--up)", + }, +]; + +const isConcreteSymbol = (symbol: string | undefined): symbol is string => + symbol !== undefined && symbol !== "" && symbol !== "stream"; + +const clamp = (value: number, min: number, max: number): number => + Math.min(max, Math.max(min, value)); + +const finite = (value: unknown): number | null => + typeof value === "number" && Number.isFinite(value) ? value : null; + +export type CognitiveBeamModel = { + cohort: string; + sequence: string; + winner: string; + paths: string; + meters: Array<{ + label: string; + value: string; + percent: number; + color: string; + }>; +}; + +export const cognitiveReadingFor = ( + readings: Record, + symbol?: string, +): CognitiveReading | null => { + if (isConcreteSymbol(symbol)) { + return readings[symbol] ?? null; + } + + const [scope] = cognitiveScopes(readings); + + return scope === undefined ? null : readings[scope]; +}; + +export const cognitiveBeamModel = ( + reading: CognitiveReading | null, +): CognitiveBeamModel | null => { + if (reading === null) { + return null; + } + + const entropyBits = finite(reading.entropyBits) ?? 0; + const entropyThreshold = finite(reading.entropyThreshold) ?? 0; + const confidence = clamp(finite(reading.classConfidence) ?? 0, 0, 1); + const lookahead = clamp(finite(reading.lookaheadScore) ?? 0, 0, 1); + const paths = + finite(reading.lookaheadPaths) ?? finite(reading.prewarmPaths) ?? 0; + const entropyPercent = + entropyThreshold > 0 + ? clamp((entropyBits / entropyThreshold) * 100, 0, 100) + : 0; + + return { + cohort: String(reading.regimeCohort), + sequence: reading.sequence || "waiting", + winner: reading.winnerClass || "pending", + paths: String(Math.round(paths)), + meters: [ + { + label: "Entropy gate", + value: `${entropyBits.toFixed(2)} / ${entropyThreshold.toFixed(1)} bits`, + percent: entropyPercent, + color: "var(--up)", + }, + { + label: "Class confidence", + value: `${Math.round(confidence * 100)}%`, + percent: confidence * 100, + color: "var(--info)", + }, + { + label: "Lookahead beam", + value: lookahead.toFixed(3), + percent: lookahead * 100, + color: "var(--acc)", + }, + ], + }; +}; + +export const CausalLadder = ({ symbol }: { symbol?: string }) => { + const focusSymbol = useSelector(appStore, (state) => state.focusSymbol); + const scope = isConcreteSymbol(symbol) ? symbol : focusSymbol; + const frame = useSelector( + causalStore, + (state) => state.causal[scope]?.values().at(-1), + ); + + if (frame === undefined) { + return ( +
+
+ Causal ladder +
+
+ no causal reading yet +
+
+ ); + } + + return ( +
+
Causal ladder
+
+ pearl do-calculus · {String(frame.category)} +
+ +
+ {RUNGS.map((rung) => { + const raw = Number(frame[rung.key] ?? 0); + const value = Math.max(0, Math.min(1, raw)); + + return ( +
+
+ + {rung.rung}. {rung.name} + + + {value.toFixed(3)} + +
+
+ {rung.desc} +
+
+
+
+
+ ); + })} +
+
+
+ uplift + + {Number(frame.uplift ?? 0).toFixed(3)} + +
+
+ residual + + {Number(frame.residual ?? 0).toFixed(3)} + +
+
+ baseline + + {Number(frame.baseline ?? 0).toFixed(3)} + +
+
+ panic + + {Number(frame.panic ?? 0).toFixed(3)} + +
+
+
+ ); +}; + +export const CognitiveBeam = ({ symbol }: { symbol?: string }) => { + const readings = useSelector(cognitiveStore, (state) => state.readings); + const model = cognitiveBeamModel(cognitiveReadingFor(readings, symbol)); + + if (model === null) { + return ( +
+
+ Cognitive beam +
+
+ waiting for cognitive frame +
+
+ ); + } + + return ( +
+
+ + Cognitive beam + + + cohort {model.cohort} + +
+
+ DMT sequence +
+
+ {model.sequence} +
+ +
+ {model.meters.map((meter) => ( +
+
+ {meter.label} + {meter.value} +
+
+
+
+
+ ))} +
+ +
+
+ winner + {model.winner} +
+
+ paths + {model.paths} +
+
+
+ ); +}; + +export const DecisionSideRail = ({ symbol }: { symbol?: string }) => ( + <> + + + +); diff --git a/frontend/src/components/terminal/decisions-surface.tsx b/frontend/src/components/terminal/decisions-surface.tsx new file mode 100644 index 00000000..12a431fa --- /dev/null +++ b/frontend/src/components/terminal/decisions-surface.tsx @@ -0,0 +1,437 @@ +import { useSelector } from "@tanstack/react-store"; +import { useState } from "react"; +import { actionStore } from "#/collections/actions"; +import { appStore } from "#/collections/app"; +import { causalStore } from "#/collections/causal"; +import { instrumentsStore } from "#/collections/instruments"; +import { manifoldStore } from "#/collections/manifold"; +import { measurementsStore } from "#/collections/measurements"; +import { resonanceStore } from "#/collections/resonance"; +import { cn } from "#/lib/utils"; +import { fixed } from "./decision-format"; +import { DecisionSideRail } from "./decision-side"; + +const finite = (value: unknown): number => { + const number = typeof value === "number" ? value : Number(value); + + return Number.isFinite(number) ? number : 0; +}; + +const ratio = (value: unknown): number => + Math.min(1, Math.max(0, finite(value))); + +export const DecisionsSurface = () => { + const [selectedSymbol, setSelectedSymbol] = useState(null); + const focusSymbol = useSelector(appStore, (state) => state.focusSymbol); + const actionsBySymbol = useSelector(actionStore, (state) => state.actions); + const causalBySymbol = useSelector(causalStore, (state) => state.causal); + const manifoldBySymbol = useSelector( + manifoldStore, + (state) => state.manifold, + ); + const resonanceBySymbol = useSelector( + resonanceStore, + (state) => state.resonance, + ); + const measurementsBySymbol = useSelector( + measurementsStore, + (state) => state.measurements, + ); + const instrumentSymbols = useSelector( + instrumentsStore, + (state) => state.symbols, + ); + const allowedActions = Object.values(actionsBySymbol).flatMap((history) => + history.values(), + ); + const allowedBySymbol = allowedActions.reduce( + (out, action) => { + out[action.symbol] = action; + + return out; + }, + {} as Record, + ); + const symbolSet = new Set( + [ + ...Object.keys(causalBySymbol), + ...Object.keys(resonanceBySymbol), + ...Object.keys(manifoldBySymbol), + ...Object.keys(measurementsBySymbol), + ...Object.keys(actionsBySymbol), + ].filter((symbol) => symbol.includes("/")), + ); + const symbols = [ + ...instrumentSymbols.filter((symbol) => symbolSet.has(symbol)), + ...[...symbolSet] + .filter((symbol) => !instrumentSymbols.includes(symbol)) + .sort(), + ]; + const candidates = symbols + .map((symbol) => { + const action = allowedBySymbol[symbol]; + const causal = causalBySymbol[symbol]?.values().at(-1); + const resonance = resonanceBySymbol[symbol]?.values().at(-1); + const manifold = manifoldBySymbol[symbol]?.values().at(-1); + const causalStrength = finite(causal?.strength); + const causalBaseline = finite(causal?.baseline); + const resonanceConfidence = ratio(resonance?.confidence); + const causalConfidence = ratio(causal?.confidence); + const score = action?.score ?? Math.min(resonanceConfidence, causalConfidence); + const support = [causal, resonance, manifold].filter(Boolean).length; + const inPlay = support >= 2 && causalStrength >= causalBaseline; + const verdict = action?.verdict ?? (inPlay ? "blocked" : "below"); + const why = + action?.reason ?? + (causal === undefined + ? "waiting causal" + : resonance === undefined + ? "waiting resonance" + : manifold === undefined + ? "waiting manifold" + : inPlay + ? "not admitted" + : "below line"); + + return { + action, + causal, + manifold, + resonance, + symbol, + support, + score, + inPlay, + verdict, + why, + bars: [ + { src: "causal", value: causalStrength }, + { src: "predict", value: finite(resonance?.confidence) }, + { src: "manifold", value: finite(manifold?.momentum) }, + ].filter((bar) => bar.value !== 0), + waterfall: [ + { + src: "causal", + delta: causalStrength - causalBaseline, + }, + { + src: "predict", + delta: finite(resonance?.flow) - finite(resonance?.baseline), + }, + { + src: "field", + delta: finite(manifold?.momentum), + }, + ], + probes: [ + { label: "beta", value: finite(causal?.beta) }, + { label: "panic", value: finite(causal?.panic) }, + { label: "residual", value: finite(causal?.residual) }, + { label: "intervention", value: finite(causal?.intervention) }, + ], + }; + }); + const current = + candidates.find((candidate) => candidate.symbol === selectedSymbol) ?? + candidates.find((candidate) => candidate.symbol === focusSymbol) ?? + candidates[0]; + const scanned = instrumentSymbols.length || symbols.length; + const quoted = Object.keys(measurementsBySymbol).length; + const inPlay = candidates.filter((candidate) => candidate.inPlay).length; + const allowed = candidates.filter( + (candidate) => candidate.verdict === "allow", + ).length; + const entryLine = finite(current?.causal?.baseline ?? current?.action?.entryLine); + const entryScore = finite( + current?.causal?.strength ?? current?.action?.entryScore, + ); + const entryConfidence = finite( + current?.causal?.confidence ?? current?.action?.entryConfidence, + ); + + return ( +
+
+
+
+
+ Scanned +
+
+ {scanned} +
+
+ universe +
+
+ +
+
+ Quoted +
+
+ {quoted} +
+
+ fresh ticks +
+
+ +
+
+ In Play +
+
+ {inPlay} +
+
+ ≥ entry line +
+
+ +
+
+ Allowed +
+
+ {allowed} +
+
+ edge clears +
+
+
+ + {current ? ( +
+ entry line + + {fixed(entryLine)} + + · + strength {fixed(entryScore)} + · + + confidence {fixed(entryConfidence)} + + + support gate ≥ 2 · backend verdict wins + +
+ ) : null} + +
+ + Candidate evaluation + + + click a row to inspect attribution + counterfactuals + +
+ +
+ {candidates.length === 0 ? ( +
+ waiting for backend decision frames +
+ ) : null} + + {candidates.map((candidate) => { + const selected = candidate.symbol === current?.symbol; + const scorePercent = Math.round(ratio(candidate.score) * 100); + const verdictTone = + candidate.verdict === "allow" + ? "var(--up)" + : candidate.verdict === "blocked" + ? "var(--down)" + : "var(--f3)"; + const verdictBackground = + candidate.verdict === "allow" + ? "color-mix(in srgb,var(--up) 16%,transparent)" + : candidate.verdict === "blocked" + ? "color-mix(in srgb,var(--down) 14%,transparent)" + : "var(--line)"; + + return ( + + ); + })} +
+
+ +
+ +
+
+ ); +}; diff --git a/frontend/src/components/terminal/health.test.ts b/frontend/src/components/terminal/health.test.ts new file mode 100644 index 00000000..6517f0e3 --- /dev/null +++ b/frontend/src/components/terminal/health.test.ts @@ -0,0 +1,46 @@ +import { describe, expect, it } from "vitest"; +import { Circular } from "#/collections/circular"; +import type { Measurement } from "#/collections/measurements"; +import { terminalHealthSummary } from "./health"; + +describe("terminalHealthSummary", () => { + it("counts backend measurement frames as firing", () => { + const history = Circular(4); + + history.push({ + source: "depthflow", + symbol: "BTC/USD", + at: "2026-07-06T10:00:00Z", + status: "measured", + elapsed: 0, + entryBaseline: 0.5, + exitBaseline: 0.25, + categories: [ + { + type: "loaded_imbalance", + confidence: 0.21, + surprisal: 0, + strength: 0.4, + }, + ], + metrics: {}, + }); + + const summary = terminalHealthSummary( + { + measurements: { + "BTC/USD": { + depthflow: history, + }, + }, + }, + "BTC/USD", + ["depthflow", "fluid"], + ); + + expect(summary.firing).toBe(1); + expect(summary.measured).toBe(1); + expect(summary.total).toBe(2); + expect(summary.avg).toBe(21); + }); +}); diff --git a/frontend/src/components/terminal/health.tsx b/frontend/src/components/terminal/health.tsx new file mode 100644 index 00000000..3c84860f --- /dev/null +++ b/frontend/src/components/terminal/health.tsx @@ -0,0 +1,370 @@ +import { useSelector } from "@tanstack/react-store"; +import { appStore } from "#/collections/app"; +import { measurementsStore } from "#/collections/measurements"; + +const Meter = ({ + label, + value, + percent, + color = "var(--info)", +}: { + label: string; + value: string; + percent: number; + color?: string; +}) => ( +
+ {label} +
+
+
+ + {value} + +
+); + +const Stat = ({ + value, + label, + accent = false, +}: { + value: string; + label: string; + accent?: boolean; +}) => ( +
+
+ {value} +
+
{label}
+
+); + +export type HealthSummary = { + bars: Array<{ color: string; count: number; label: string; percent: number }>; + avg: number; + firing: number; + label: string; + measured: number; + tone: string; + total: number; +}; + +export const terminalHealthSummary = ( + readings: typeof measurementsStore.state, + focusSymbol: string, + sources = [ + ...new Set( + Object.values(readings.measurements).flatMap((sourceMap) => + Object.keys(sourceMap), + ), + ), + ], +): HealthSummary => { + const total = sources.length; + let measured = 0; + let warming = 0; + let degraded = 0; + let confidence = 0; + let confidenceCount = 0; + let firing = 0; + + for (const source of sources) { + const history = + focusSymbol === "stream" + ? Object.values(readings.measurements).flatMap( + (sourceMap) => sourceMap[source]?.values() ?? [], + ) + : (readings.measurements[focusSymbol]?.[source]?.values() ?? []); + const frame = history.at(-1); + const status = + frame === undefined + ? "waiting" + : frame.status === "fault" || + frame.status === "ambiguous" || + frame.status === "calibrating" + ? frame.status + : "measured"; + const category = frame?.categories.at(0); + + if (status === "ambiguous" || status === "fault") { + degraded += 1; + } else if (status === "waiting" || status === "calibrating") { + warming += 1; + } else { + measured += 1; + } + + if (typeof category?.confidence === "number") { + confidence += category.confidence; + confidenceCount += 1; + } + + if (frame !== undefined) { + firing += 1; + } + } + + const label = + degraded > 0 + ? "Degraded" + : measured < total / 2 + ? "Thin" + : "Nominal"; + const tone = + degraded > 0 + ? "var(--down)" + : measured < total / 2 + ? "var(--warn)" + : "var(--up)"; + const bars = [ + { label: "Healthy", count: measured, color: "var(--up)" }, + { label: "Warming", count: warming, color: "var(--warn)" }, + { label: "Degraded", count: degraded, color: "var(--down)" }, + ].map((bar) => ({ + ...bar, + percent: total > 0 ? Math.round((bar.count / total) * 100) : 0, + })); + + return { + avg: confidenceCount > 0 ? Math.round((confidence / confidenceCount) * 100) : 0, + bars, + firing, + label, + measured, + tone, + total, + }; +}; + +export const HealthPanel = ({ sources }: { sources?: string[] }) => { + const readings = useSelector(measurementsStore, (state) => state); + const focusSymbol = useSelector(appStore, (state) => state.focusSymbol); + const health = terminalHealthSummary(readings, focusSymbol, sources); + + return ( +
+
+ System health + + {health.label} + +
+
+ + + +
+
+ {health.bars.map((bar) => ( + + ))} +
+
+ ); +}; + +const finiteRatio = (value: unknown): number => { + const number = typeof value === "number" ? value : Number(value); + + return Number.isFinite(number) ? Math.min(1, Math.max(0, number)) : 0; +}; + +export const regimeValuesFromFrames = ( + readings: typeof measurementsStore.state, + regimeFrame: Record | null, +): [number, number, number, number, number] => { + if (regimeFrame !== null) { + return [ + finiteRatio(regimeFrame.volatility), + finiteRatio(regimeFrame.trend), + finiteRatio(regimeFrame.bullish), + finiteRatio(regimeFrame.bearish), + finiteRatio(regimeFrame.choppiness), + ]; + } + + const rows = Object.values(readings.measurements).flatMap((sources) => + Object.values(sources).flatMap((history) => { + const frame = history.values().at(-1); + + return ( + frame?.categories.map((category) => ({ + source: frame.source, + type: category.type, + value: Math.max(category.confidence, category.strength), + })) ?? [] + ); + }), + ); + const axis = (matches: (row: (typeof rows)[number]) => boolean) => { + const values = rows.flatMap((row) => (matches(row) ? [row.value] : [])); + + return values.length === 0 + ? 0 + : finiteRatio(values.reduce((sum, value) => sum + value, 0) / values.length); + }; + const contains = (row: (typeof rows)[number], terms: string[]) => + terms.some((term) => row.type.includes(term) || row.source.includes(term)); + + return [ + axis((row) => + contains(row, [ + "turbulent", + "frenzy", + "ignition", + "vacuum", + "shock", + "collapse", + "expansion", + "reversal", + "bluff", + "spoof", + "thinning", + "scarcity", + ]), + ), + axis((row) => + contains(row, [ + "trend", + "drift", + "drive", + "laminar", + "edge", + "alpha", + "beta", + "surge", + ]), + ), + axis((row) => + contains(row, [ + "edge", + "ignition", + "trend", + "surge", + "drive", + "robust", + "absorption", + "support", + "alpha", + ]), + ), + axis((row) => + contains(row, [ + "slump", + "vacuum", + "collapse", + "exhaustion", + "starvation", + "thinning", + "bluff", + "stress", + "faded", + "scarcity", + ]), + ), + axis((row) => + contains(row, [ + "balance", + "neutrality", + "equilibrium", + "noise", + "decoupled", + "stall", + "median", + "saturation", + ]), + ), + ]; +}; + +export const RadarPanel = () => { + const readings = useSelector(measurementsStore, (state) => state); + const values = regimeValuesFromFrames(readings, null); + const units = [ + [0, -1], + [0.951, -0.309], + [0.588, 0.809], + [-0.588, 0.809], + [-0.951, -0.309], + ]; + const points = units + .map( + ([x, y], index) => + `${110 + x * 84 * values[index]},${105 + y * 84 * values[index]}`, + ) + .join(" "); + + return ( +
+
Regime radar
+
+ cross-section mean · market +
+ + Regime radar + + + + {units.map(([x, y]) => ( + + ))} + + {["volatility", "trend", "bullish", "bearish", "chop"].map( + (label, index) => ( + + {label} + + ), + )} + +
+ ); +}; diff --git a/frontend/src/components/terminal/kernel-list.tsx b/frontend/src/components/terminal/kernel-list.tsx new file mode 100644 index 00000000..6a90a1b0 --- /dev/null +++ b/frontend/src/components/terminal/kernel-list.tsx @@ -0,0 +1,164 @@ +import { useSelector } from "@tanstack/react-store"; +import { appStore } from "#/collections/app"; +import { measurementsStore } from "#/collections/measurements"; +import { terminalStore } from "#/collections/terminal"; +import { + kernelCopy, + kernelSparkPaths, + kernelStatusMeta, + type SignalHealthStatus, +} from "#/components/terminal/kernel-meta"; + +export const KernelList = ({ + compact = false, + sources: inputSources, +}: { + compact?: boolean; + sources?: string[]; +}) => { + const app = useSelector(appStore, (state) => state); + const mStore = useSelector(measurementsStore, (state) => state); + const measurements = mStore.measurements[app.focusSymbol] ?? {}; + const terminal = useSelector(terminalStore, (state) => state); + const sources = (inputSources ?? Object.keys(measurements)).sort(); + const { inspectSource, selectSource } = terminalStore.actions; + + if (sources.length === 0) { + return ( +
+ waiting for backend measurement frames +
+ ); + } + + return ( +
+ {sources.map((source) => { + const values = measurements[source]?.values() ?? []; + const frame = values.at(-1); + const category = frame?.categories.at(0); + const confidence = category?.confidence ?? 0; + const surprise = category?.surprisal ?? 0; + const copy = kernelCopy(source, category?.type ?? source); + const status = ( + frame === undefined + ? "waiting" + : frame.status === "fault" || + frame.status === "ambiguous" || + frame.status === "calibrating" + ? frame.status + : "measured" + ) as SignalHealthStatus; + const statusMeta = kernelStatusMeta(status); + const spark = kernelSparkPaths( + values.flatMap((x) => x.categories.map((y) => y.confidence)), + status, + ); + const inspecting = terminal.inspectorSource === source; + const selected = terminal.selectedSource === source; + + return ( + + ); + })} +
+ ); +}; diff --git a/frontend/src/components/terminal/kernel-meta.ts b/frontend/src/components/terminal/kernel-meta.ts new file mode 100644 index 00000000..b1e1b973 --- /dev/null +++ b/frontend/src/components/terminal/kernel-meta.ts @@ -0,0 +1,270 @@ +export type SignalHealthStatus = + | "waiting" + | "standby" + | "calibrating" + | "fault" + | "ambiguous" + | "measured" + | "unknown"; + +export type KernelStatusMeta = { + label: string; + fg: string; + bg: string; + bd: string; +}; + +export const TERMINAL_KERNEL_ORDER = [ + "fluid", + "prediction", + "resonance", + "hawkes", + "cognitive", + "causal", + "manifold", + "regime", + "correlation", + "pumpdump", + "toxicity", + "exhaustion", + "cvd", + "depthflow", + "liquidity", + "sentiment", + "leadlag", +] as const; + +const kernelOrderIndex = (source: string): number => { + const index = TERMINAL_KERNEL_ORDER.indexOf( + source as (typeof TERMINAL_KERNEL_ORDER)[number], + ); + + return index === -1 ? TERMINAL_KERNEL_ORDER.length : index; +}; + +export const orderedKernelSources = (sources: string[]): string[] => + [...sources].sort((left, right) => { + const byOrder = kernelOrderIndex(left) - kernelOrderIndex(right); + + return byOrder === 0 ? left.localeCompare(right) : byOrder; + }); + +const KERNEL_COPY: Record< + string, + { name: string; sub: string; blurb: string } +> = { + fluid: { + name: "Fluid dynamics", + sub: "fluid · vol-rank × Δ", + blurb: + "Navier–Stokes pressure field over the market cross-section. Whale carriers bend the density surface; turbulence flags regime breaks before price confirms.", + }, + hawkes: { + name: "Hawkes process", + sub: "hawkes · branching η", + blurb: + "Self-exciting point process over order-flow events. Branching ratio η near 1 means the book is reflexive and primed to cascade.", + }, + // "prediction" is a presentation alias for the resonance measurement: the + // backend has one autoencoder output, while the mockup names the detail row + // after its predictive-coding role. + prediction: { + name: "Predictive coding", + sub: "predict · 8-step horizon", + blurb: + "Hierarchical generative model. Each layer predicts the one below; the residual error norm is the tradeable surprise.", + }, + resonance: { + name: "Resonance", + sub: "resonance · laminar/turbulent", + blurb: + "Latent-state x-ray of coupled oscillators. Laminar phase locks ride trends; turbulent decoherence precedes reversals.", + }, + cognitive: { + name: "Cognitive memory", + sub: "cognitive · entropy gate", + blurb: + "Discrete DMT sequence sealed through an entropy gate, then a beam search lookahead picks the winning regime class.", + }, + causal: { + name: "Causal ladder", + sub: "causal · assoc→interv→cf", + blurb: + "Pearl do-calculus. Climbs association → intervention → counterfactual to estimate the effect of acting, not merely observing.", + }, + manifold: { + name: "Manifold", + sub: "manifold · whale carriers", + blurb: + "Density manifold projection of the liquidity field, with whale-carrier markers lifted off the base surface.", + }, + regime: { + name: "Regime radar", + sub: "regime · 5-axis", + blurb: + "Cross-section mean of volatility, trend, bullish, bearish and choppiness — the coarse weather of the tape.", + }, + correlation: { + name: "Correlation", + sub: "correlation · cross-section", + blurb: + "Cross-symbol correlation pressure from backend measurements.", + }, + pumpdump: { + name: "Pumpdump", + sub: "pumpdump · ignition", + blurb: + "Pump impulse measurement from raw market frames projected into the terminal signal surface.", + }, + leadlag: { + name: "Lead-lag", + sub: "leadlag · cross-lag", + blurb: + "Lead-lag coupling across the cross-section from backend measurements.", + }, + liquidity: { + name: "Liquidity", + sub: "liquidity · depth", + blurb: + "Book depth and liquidity pressure from backend measurements.", + }, + toxicity: { + name: "Toxicity", + sub: "toxicity · flow", + blurb: "Order-flow toxicity measurement from backend frames.", + }, + exhaustion: { + name: "Exhaustion", + sub: "exhaustion · fade", + blurb: "Exhaustion measurement from backend frames.", + }, + depthflow: { + name: "Depthflow", + sub: "depthflow · ladder", + blurb: "Depth flow measurement from backend frames.", + }, + cvd: { + name: "CVD", + sub: "cvd · pressure", + blurb: "Cumulative volume delta pressure from backend frames.", + }, + sentiment: { + name: "Sentiment", + sub: "sentiment · tape", + blurb: "Sentiment measurement from backend frames.", + }, +}; + +export const kernelCopy = (source: string, category: string) => + KERNEL_COPY[source] ?? { + name: source, + sub: category || source, + blurb: + "Backend measurement projected into the terminal signal surface.", + }; + +export const kernelStatusMeta = ( + status: SignalHealthStatus, +): KernelStatusMeta => { + const table: Record = { + measured: { + label: "Healthy", + fg: "var(--up)", + bg: "color-mix(in srgb, var(--up) 12%, transparent)", + bd: "color-mix(in srgb, var(--up) 38%, transparent)", + }, + ambiguous: { + label: "Ambig", + fg: "var(--down)", + bg: "color-mix(in srgb, var(--down) 12%, transparent)", + bd: "color-mix(in srgb, var(--down) 38%, transparent)", + }, + fault: { + label: "Fault", + fg: "var(--down)", + bg: "color-mix(in srgb, var(--down) 12%, transparent)", + bd: "color-mix(in srgb, var(--down) 38%, transparent)", + }, + waiting: { + label: "Standby", + fg: "var(--f3)", + bg: "var(--line)", + bd: "var(--line2)", + }, + standby: { + label: "Standby", + fg: "var(--f3)", + bg: "var(--line)", + bd: "var(--line2)", + }, + calibrating: { + label: "Calib", + fg: "var(--info)", + bg: "color-mix(in srgb, var(--info) 12%, transparent)", + bd: "color-mix(in srgb, var(--info) 38%, transparent)", + }, + unknown: { + label: "No status", + fg: "var(--warn)", + bg: "color-mix(in srgb, var(--warn) 12%, transparent)", + bd: "color-mix(in srgb, var(--warn) 38%, transparent)", + }, + }; + + return table[status] ?? table.waiting; +}; + +export const kernelSparkPaths = ( + values: number[], + status: SignalHealthStatus = "unknown", +): { + spark: string; + area: string; + line: string; + fill: string; + active: boolean; +} => { + const history = values.length > 0 ? values : [0]; + const active = status === "measured" || status === "ambiguous"; + const points = history.map((value, index) => { + const x = + history.length === 1 + ? index === 0 + ? "0.0" + : "150.0" + : ((index / Math.max(history.length - 1, 1)) * 150).toFixed(1); + const y = (29 - value * 26).toFixed(1); + + return `${x},${y}`; + }); + const spark = + history.length === 1 + ? `${points[0]} 150,${points[0].split(",")[1]}` + : points.join(" "); + const area = `${spark} 150,30 0,30`; + + return { + spark, + area, + line: active ? "var(--acc)" : "var(--info)", + fill: active + ? "color-mix(in srgb, var(--acc) 16%, transparent)" + : "color-mix(in srgb, var(--info) 12%, transparent)", + active, + }; +}; + +export const formatUptime = (startedAtMs: number | null): string => { + if (startedAtMs === null || !Number.isFinite(startedAtMs)) { + return "0m 0s"; + } + + const totalSeconds = Math.max( + 0, + Math.floor((Date.now() - startedAtMs) / 1000), + ); + const minutes = Math.floor(totalSeconds / 60); + const seconds = totalSeconds % 60; + + return `${minutes}m ${seconds}s`; +}; diff --git a/frontend/src/components/terminal/kernel-readout.ts b/frontend/src/components/terminal/kernel-readout.ts new file mode 100644 index 00000000..edbe2e28 --- /dev/null +++ b/frontend/src/components/terminal/kernel-readout.ts @@ -0,0 +1,186 @@ +import type { SignalHealthStatus } from "#/components/terminal/kernel-meta"; +import { orderedKernelSources } from "#/components/terminal/kernel-meta"; +import { isConcreteSymbol } from "./scoped-frame"; + +const BACKEND_STATUSES = new Set([ + "waiting", + "standby", + "calibrating", + "fault", + "ambiguous", + "measured", + "unknown", +]); + +const finiteScore = (value: unknown): number => { + const number = typeof value === "number" ? value : Number(value); + + return Number.isFinite(number) ? Math.min(1, Math.max(0, number)) : 0; +}; + +const numberFrom = (value: unknown): number => { + const number = typeof value === "number" ? value : Number(value); + + return Number.isFinite(number) ? number : 0; +}; + +export type ReadingsState = { + measurements: Record Record[] }>; + symbols: Record[]>; +}; + +export type KernelSparkHistory = { + scope: string; + stamp: string; + values: number[]; +}; + +export const kernelReadingSource = (source: string): string => + source === "prediction" ? "resonance" : source; + +export const kernelFrameForSource = ( + readings: ReadingsState, + source: string, + focusSymbol: string, +): Record | undefined => { + const sourceName = kernelReadingSource(source); + + if (isConcreteSymbol(focusSymbol)) { + for ( + let index = (readings.symbols[focusSymbol] ?? []).length - 1; + index >= 0; + index -= 1 + ) { + const frame = readings.symbols[focusSymbol]?.[index]; + + if (frame?.source === sourceName) { + return frame; + } + } + + return undefined; + } + + return readings.measurements[sourceName]?.values().at(-1); +}; + +export const kernelStatus = ( + frame: Record | undefined, +): SignalHealthStatus => { + if (frame === undefined) { + return "waiting"; + } + + const status = typeof frame.status === "string" ? frame.status : ""; + + if (BACKEND_STATUSES.has(status)) { + return status as SignalHealthStatus; + } + + const confidence = finiteScore(frame.confidence); + const strength = finiteScore(frame.strength); + + if (confidence > 0 || strength > 0) { + return "measured"; + } + + return "unknown"; +}; + +export const kernelReadout = (frame: Record | undefined) => { + const output = frame ?? {}; + const stamp = + frame?.at ?? + frame?.observed_at ?? + frame?.timestamp_unix_nano ?? + frame?.timestamp ?? + frame?.ts; + + return { + output, + confidence: finiteScore(output.confidence), + surprise: Math.max(0, numberFrom(output.surprise)), + strength: Math.max(0, numberFrom(output.strength)), + status: kernelStatus(frame), + stamp: stamp === undefined ? "" : String(stamp), + }; +}; + +export const kernelHistoryValues = ( + frame: Record | undefined, +): number[] => + (Array.isArray(frame?.history) ? frame.history : []).flatMap((sample) => { + const output = sample as Record; + + return output.confidence === undefined && output.strength === undefined + ? [] + : [finiteScore(output.confidence ?? output.strength)]; + }); + +export const kernelCollectionValues = ( + readings: ReadingsState, + source: string, + focusSymbol: string, +): number[] => { + const sourceName = kernelReadingSource(source); + const frames = isConcreteSymbol(focusSymbol) + ? (readings.symbols[focusSymbol] ?? []).filter( + (frame) => frame.source === sourceName, + ) + : (readings.measurements[sourceName]?.values() ?? []); + + return frames.flatMap((frame) => { + const score = frame.confidence ?? frame.strength; + + return score === undefined ? [] : [finiteScore(score)]; + }); +}; + +export const kernelHistoryCount = ( + frame: Record | undefined, +): number => (Array.isArray(frame?.history) ? frame.history.length : 0); + +export const appendKernelSparkHistory = ( + history: KernelSparkHistory, + scope: string, + stamp: string, + sample: unknown, + limit = 40, +): KernelSparkHistory => { + if (history.scope === scope && history.stamp === stamp) { + return history; + } + + const values = [ + ...(history.scope === scope ? history.values : []), + finiteScore(sample), + ].slice(-Math.max(1, limit)); + + return { scope, stamp, values }; +}; + +export const kernelHealthSummary = ( + readings: ReadingsState, + focusSymbol: string, + inputSources?: string[], +) => { + const sources = orderedKernelSources( + inputSources ?? Object.keys(readings.measurements), + ); + let measured = 0; + + for (const source of sources) { + if ( + kernelReadout(kernelFrameForSource(readings, source, focusSymbol)) + .status === "measured" + ) { + measured += 1; + } + } + + return { + measured, + total: sources.length, + label: `${measured}/${sources.length} measured`, + }; +}; diff --git a/frontend/src/components/terminal/kernels.ts b/frontend/src/components/terminal/kernels.ts new file mode 100644 index 00000000..aa48a8a9 --- /dev/null +++ b/frontend/src/components/terminal/kernels.ts @@ -0,0 +1,66 @@ +import { isConcreteSymbol, resolveScopedFrame } from "./scoped-frame"; + +type ReadingsState = Record>; + +export type TerminalKernel = { + source: string; + confidencePercent: number; + surprisePercent: number; +}; + +const numberFrom = (output: Record, key: string): number => { + const nested = output[key]; + + return typeof nested === "number" ? nested : 0; +}; + +/* +kernelsForFocus projects the latest measurement per source into the +TerminalKernel shape the Decision Tree and Allocation surfaces consume. +confidence/surprise come straight off the backend measurement output - no +client-side scoring, just unit-to-percent scaling. + +readings is the measurementsStore state: source -> symbol -> frame. When a +concrete focus symbol is supplied, only that symbol's backend reading is used. +Fallback to the first live symbol is reserved for stream/no-focus mode. +*/ +export const kernelsForFocus = ( + readings: ReadingsState, + focusSymbol?: string, +): TerminalKernel[] => { + const kernels: TerminalKernel[] = []; + + for (const source of Object.keys(readings)) { + const bySymbol = readings[source] as + | Record> + | undefined; + + if (bySymbol === undefined) { + continue; + } + + const scoped = resolveScopedFrame(bySymbol, focusSymbol, source); + + if (isConcreteSymbol(focusSymbol) && scoped.mode !== "concrete") { + continue; + } + + const frame = scoped.frame; + + if (frame === null) { + continue; + } + + const output = (frame?.output ?? {}) as Record; + const confidence = numberFrom(output, "confidence"); + const surprise = numberFrom(output, "surprise"); + + kernels.push({ + source, + confidencePercent: Math.round(confidence * 100), + surprisePercent: Math.round(Math.min(surprise, 1) * 100), + }); + } + + return kernels; +}; diff --git a/frontend/src/components/terminal/palette.tsx b/frontend/src/components/terminal/palette.tsx new file mode 100644 index 00000000..32979986 --- /dev/null +++ b/frontend/src/components/terminal/palette.tsx @@ -0,0 +1,279 @@ +import { useSelector } from "@tanstack/react-store"; +import { useEffect, useRef } from "react"; +import { appStore } from "#/collections/app"; +import { instrumentsStore } from "#/collections/instruments"; +import { type TerminalSurface, terminalStore } from "#/collections/terminal"; + +const SURFACES: Array<{ id: TerminalSurface; label: string; hint: string }> = [ + { id: "dashboard", label: "Dashboard", hint: "Fluid field · live decisions" }, + { id: "signals", label: "Signal insight", hint: "Per-kernel forensics" }, + { id: "decisions", label: "Decision tree", hint: "Gate-by-gate trace" }, + { id: "xray", label: "Latent x-ray", hint: "State-space cross-section" }, + { id: "cortex", label: "Cognitive tree", hint: "Reasoning graph" }, + { id: "allocation", label: "Allocation", hint: "Capital & exposure" }, +]; + +const SearchIcon = () => ( + +); + +const SurfaceIcon = ({ active }: { active: boolean }) => ( + +); + +const KernelIcon = () => ( + +); + +const SymbolIcon = () => ( + +); + +type PaletteCommand = { + key: string; + label: string; + hint: string; + group: "Surface" | "Kernel" | "Symbol"; + surface: TerminalSurface; + source?: string; + symbol?: string; + active: boolean; +}; + +export const CommandPalette = ({ + activeSurface, + onRun, +}: { + activeSurface: TerminalSurface; + onRun: (surface: TerminalSurface, source?: string, symbol?: string) => void; +}) => { + const app = useSelector(appStore, (state) => state); + const instrumentSymbols = useSelector( + instrumentsStore, + (state) => state.symbols, + ); + const terminal = useSelector(terminalStore, (state) => state); + const { closePalette, setPaletteQuery } = terminalStore.actions; + const inputRef = useRef(null); + + useEffect(() => { + if (!terminal.paletteOpen) { + return; + } + + inputRef.current?.focus(); + }, [terminal.paletteOpen]); + + if (!terminal.paletteOpen) { + return null; + } + + const commands: PaletteCommand[] = [ + ...SURFACES.map( + (surface): PaletteCommand => ({ + key: `surface:${surface.id}`, + label: surface.label, + hint: surface.hint, + group: "Surface", + surface: surface.id, + active: surface.id === activeSurface, + }), + ), + ...app.kernels.map( + (kernel): PaletteCommand => ({ + key: `kernel:${kernel}`, + label: `Inspect · ${kernel}`, + hint: kernel, + group: "Kernel", + surface: "dashboard" as TerminalSurface, + source: kernel, + active: false, + }), + ), + ...instrumentSymbols.map( + (symbol): PaletteCommand => ({ + key: `symbol:${symbol}`, + label: symbol, + hint: "Focus symbol", + group: "Symbol", + surface: activeSurface, + symbol, + active: symbol === app.focusSymbol, + }), + ), + ].filter((command) => + `${command.label} ${command.hint}` + .toLowerCase() + .includes(terminal.paletteQuery.trim().toLowerCase()), + ); + const selectedIndex = + commands.length === 0 + ? 0 + : ((terminal.paletteIndex % commands.length) + commands.length) % + commands.length; + const countText = `${commands.length} command${commands.length === 1 ? "" : "s"}`; + + return ( +
+ + ); + }) + )} +
+
+
+
+ ); +}; diff --git a/frontend/src/components/terminal/panels.tsx b/frontend/src/components/terminal/panels.tsx new file mode 100644 index 00000000..3c54dffd --- /dev/null +++ b/frontend/src/components/terminal/panels.tsx @@ -0,0 +1,434 @@ +import { Link } from "@tanstack/react-router"; +import { useSelector } from "@tanstack/react-store"; +import type { ReactNode } from "react"; +import { appStore } from "#/collections/app"; +import { balancesStore } from "#/collections/balances"; +import { terminalStore, type TerminalSurface } from "#/collections/terminal"; +import { tickStore } from "#/collections/tick"; +import { formatUptime } from "#/components/terminal/kernel-meta"; +import { cn } from "#/lib/utils"; + +type TerminalRoutePath = + | "/" + | "/signals" + | "/decisions" + | "/xray" + | "/cortex" + | "/allocation"; + +const SURFACE_ITEMS: Array<{ + key: TerminalSurface; + label: string; + to: TerminalRoutePath; +}> = [ + { key: "dashboard", label: "Dashboard", to: "/" }, + { key: "signals", label: "Signal insight", to: "/signals" }, + { key: "decisions", label: "Decision tree", to: "/decisions" }, + { key: "xray", label: "Latent x-ray", to: "/xray" }, + { key: "cortex", label: "Cognitive tree", to: "/cortex" }, + { key: "allocation", label: "Allocation", to: "/allocation" }, +]; + +const SymmLogo = () => ( + +); + +const NavIcon = ({ surface }: { surface: TerminalSurface }) => { + switch (surface) { + case "dashboard": + return ( + + Dashboard + + + + + + ); + case "signals": + return ( + + ); + case "decisions": + return ( + + Decision tree + + + + + + ); + case "xray": + return ( + + Latent x-ray + + + + ); + case "cortex": + return ( + + Cognitive tree + + + + + + ); + default: + return ( + + Allocation + + + + + + ); + } +}; + +const navStyle = (active: boolean) => + active + ? { + borderColor: "var(--line2)", + background: "var(--raised)", + color: "var(--f1)", + } + : { + borderColor: "transparent", + background: "transparent", + color: "var(--f3)", + }; + +export const TerminalSection = ({ + title, + meta, + children, + className, +}: { + title: string; + meta?: ReactNode; + children: ReactNode; + className?: string; +}) => ( +
+
+ + {title} + + {meta ? ( + {meta} + ) : null} +
+ {children} +
+); + +export const TerminalTopBar = () => { + const online = useSelector(appStore, (state) => state.online); + const tick = useSelector(tickStore, (state) => state.frame); + const { openPalette } = terminalStore.actions; + + const balancesList = useSelector(balancesStore, (state) => state.balances); + const usdBalance = + balancesList.find((b) => b.asset === "USD" || b.asset === "EUR") ?? + balancesList[0]; + const cashValue = usdBalance + ? `${Number(usdBalance.balance).toFixed(2)} ${usdBalance.asset}` + : "—"; + const availableValue = usdBalance + ? `${Number(usdBalance.available ?? usdBalance.balance).toFixed(2)} ${usdBalance.asset}` + : "—"; + const reservedValue = usdBalance + ? `${Number(usdBalance.reserved ?? 0).toFixed(2)} ${usdBalance.asset}` + : "—"; + + return ( +
+
+ + + SYMM + +
+ + + {online ? "live" : "offline"} + + + {String(tick?.open ?? 0)} open positions + +
+ + + + + +
+
+ ); +}; + +const TopMetric = ({ + label, + value, + accent = false, + strong = false, +}: { + label: string; + value: string; + accent?: boolean; + strong?: boolean; +}) => ( +
+ + {label} + + + {value} + +
+); + +export const TerminalNav = ({ active }: { active: TerminalSurface }) => { + const scanlines = useSelector(terminalStore, (state) => state.scanlines); + const fieldStyle = useSelector(terminalStore, (state) => state.fieldStyle); + const { toggleScanlines, toggleFieldStyle } = terminalStore.actions; + const online = useSelector(appStore, (state) => state.online); + const tick = useSelector(tickStore, (state) => state.frame); + const storyTicks = tick?.count ?? 0; + const enginePhase = (tick?.phase as string) ?? ""; + const candidates = (tick?.candidates as number) ?? 0; + const open = (tick?.open as number) ?? 0; + const fluid = (tick?.fluid as number) ?? 0; + const quotesReady = (tick?.quotes_ready as number) ?? 0; + const quotesTotal = (tick?.quotes_total as number) ?? 0; + const quotesPercent = + quotesTotal > 0 ? Math.round((quotesReady / quotesTotal) * 100) : 0; + const fluidPercent = + quotesTotal > 0 ? Math.round((fluid / quotesTotal) * 100) : 0; + const clockText = new Date().toISOString().slice(11, 19); + + return ( + + ); +}; + +const MetricLine = ({ + label, + value, + accent = false, +}: { + label: string; + value: string; + accent?: boolean; +}) => ( +
+ {label} + {value} +
+); + +const ProgressLine = ({ + label, + text, + value, + accent = false, +}: { + label: string; + text: string; + value: number; + accent?: boolean; +}) => ( +
+
+ {label} + {text} +
+
+
+
+
+); diff --git a/frontend/src/components/terminal/scoped-frame.ts b/frontend/src/components/terminal/scoped-frame.ts new file mode 100644 index 00000000..c516ff98 --- /dev/null +++ b/frontend/src/components/terminal/scoped-frame.ts @@ -0,0 +1,192 @@ +import type { DashboardFrame } from "#/collections/frames"; + +export type ScopedFrameMode = "concrete" | "stream_preview" | "missing"; + +export type ScopedFrameResult = { + frame: DashboardFrame | null; + mode: ScopedFrameMode; + sourceName: string; + symbol: string; +}; + +export type ScopedFrameSource = + | DashboardFrame + | DashboardFrame[] + | { + frame?: DashboardFrame | null; + frames?: DashboardFrame[]; + bySymbol?: Record; + } + | Record + | null + | undefined; + +export const isConcreteSymbol = (symbol: unknown): symbol is string => + typeof symbol === "string" && symbol.trim() !== "" && symbol !== "stream"; + +const asRecord = (value: unknown): DashboardFrame | null => + value !== null && typeof value === "object" && !Array.isArray(value) + ? (value as DashboardFrame) + : null; + +const recordArray = (value: unknown): DashboardFrame[] => + Array.isArray(value) + ? value.flatMap((item) => { + const record = asRecord(item); + return record === null ? [] : [record]; + }) + : []; + +const stringField = (frame: DashboardFrame, key: string): string => + typeof frame[key] === "string" ? frame[key].trim() : ""; + +const frameDeclaresSymbol = (frame: DashboardFrame, symbol: string): boolean => + [ + "symbol", + "scope", + "pair", + "market", + "focus_symbol", + "symbol_pair", + "instrument", + ].some((key) => stringField(frame, key) === symbol); + +const scopedFrameFromRoot = ( + frame: DashboardFrame, + symbol: string, +): DashboardFrame | null => { + for (const snapshot of recordArray(frame.snapshots)) { + if (frameDeclaresSymbol(snapshot, symbol)) { + return snapshot; + } + } + + const focus = asRecord(frame.focus); + + if (focus !== null && frameDeclaresSymbol(focus, symbol)) { + return focus; + } + + return frameDeclaresSymbol(frame, symbol) ? frame : null; +}; + +const streamPreviewFromRoot = ( + frame: DashboardFrame, +): DashboardFrame | null => { + const focus = asRecord(frame.focus); + + if (focus !== null) { + return focus; + } + + const [firstSnapshot] = recordArray(frame.snapshots); + + return firstSnapshot ?? frame; +}; + +const looksLikeFrame = (record: DashboardFrame): boolean => + [ + "role", + "source", + "scope", + "symbol", + "focus", + "focus_symbol", + "snapshots", + "layers", + "output", + ].some((key) => record[key] !== undefined); + +const collectFrames = (source: ScopedFrameSource): DashboardFrame[] => { + if (source === null || source === undefined) { + return []; + } + + if (Array.isArray(source)) { + return source.flatMap((item) => collectFrames(item)); + } + + const record = asRecord(source); + + if (record === null) { + return []; + } + + const frames: DashboardFrame[] = []; + + if (Array.isArray(record.frames)) { + frames.push(...record.frames.flatMap((item) => collectFrames(item))); + } + + const bySymbol = asRecord(record.bySymbol); + + if (bySymbol !== null) { + for (const value of Object.values(bySymbol)) { + frames.push(...collectFrames(value as ScopedFrameSource)); + } + } + + const latest = asRecord(record.frame); + + if (latest !== null) { + frames.push(latest); + } + + if (frames.length === 0 && looksLikeFrame(record)) { + frames.push(record); + } + + if (frames.length === 0) { + for (const [key, value] of Object.entries(record)) { + const scopedFrames = collectFrames(value as ScopedFrameSource); + + if (isConcreteSymbol(key)) { + frames.push( + ...scopedFrames.map((frame) => + frameDeclaresSymbol(frame, key) ? frame : { ...frame, scope: key }, + ), + ); + continue; + } + + frames.push(...scopedFrames); + } + } + + return frames; +}; + +export const resolveScopedFrame = ( + source: ScopedFrameSource, + concreteSymbol: string | null | undefined, + sourceName: string, +): ScopedFrameResult => { + const symbol = concreteSymbol?.trim() ?? ""; + const frames = collectFrames(source); + const concrete = isConcreteSymbol(symbol); + + if (concrete) { + for (let index = frames.length - 1; index >= 0; index -= 1) { + const frame = scopedFrameFromRoot( + frames[index] as DashboardFrame, + symbol, + ); + + if (frame !== null) { + return { frame, mode: "concrete", sourceName, symbol }; + } + } + + return { frame: null, mode: "missing", sourceName, symbol }; + } + + for (let index = frames.length - 1; index >= 0; index -= 1) { + const frame = streamPreviewFromRoot(frames[index] as DashboardFrame); + + if (frame !== null) { + return { frame, mode: "stream_preview", sourceName, symbol: "stream" }; + } + } + + return { frame: null, mode: "missing", sourceName, symbol: "stream" }; +}; diff --git a/frontend/src/components/terminal/signals-surface.bench.ts b/frontend/src/components/terminal/signals-surface.bench.ts new file mode 100644 index 00000000..f68bbc09 --- /dev/null +++ b/frontend/src/components/terminal/signals-surface.bench.ts @@ -0,0 +1,23 @@ +import { bench, describe } from "vitest"; +import { DEFAULT_KERNELS } from "#/collections/app"; +import { Circular } from "#/collections/circular"; +import type { + Measurement, + measurementsStore, +} from "#/collections/measurements"; +import { signalsSurfaceSources } from "./signals-surface"; + +describe("signalsSurfaceSources", () => { + const measurements: typeof measurementsStore.state = { + measurements: { + "BTC/USD": { + customflow: Circular(50), + customregime: Circular(50), + }, + }, + }; + + bench("merges configured kernels with backend sources", () => { + signalsSurfaceSources(DEFAULT_KERNELS, measurements); + }); +}); diff --git a/frontend/src/components/terminal/signals-surface.tsx b/frontend/src/components/terminal/signals-surface.tsx new file mode 100644 index 00000000..c593d9f2 --- /dev/null +++ b/frontend/src/components/terminal/signals-surface.tsx @@ -0,0 +1,61 @@ +import { useSelector } from "@tanstack/react-store"; +import { useEffect, useMemo } from "react"; +import { appStore } from "#/collections/app"; +import { measurementsStore } from "#/collections/measurements"; +import { terminalStore } from "#/collections/terminal"; +import { SignalDetail } from "#/components/kernel/detail"; +import { HealthPanel, RadarPanel } from "#/components/terminal/health"; +import { KernelList } from "#/components/terminal/kernel-list"; +import { orderedKernelSources } from "#/components/terminal/kernel-meta"; + +export const signalsSurfaceSources = ( + kernels: string[], + measurements: typeof measurementsStore.state, +): string[] => + orderedKernelSources([ + ...new Set([ + ...kernels, + ...Object.values(measurements.measurements).flatMap((sources) => + Object.keys(sources), + ), + ]), + ]); + +export const SignalsSurface = () => { + const kernels = useSelector(appStore, (state) => state.kernels); + const measurements = useSelector(measurementsStore, (state) => state); + const selectedSource = useSelector( + terminalStore, + (state) => state.selectedSource, + ); + const sources = useMemo( + () => signalsSurfaceSources(kernels, measurements), + [kernels, measurements], + ); + + useEffect(() => { + if (sources.length === 0 || sources.includes(selectedSource)) { + return; + } + + terminalStore.actions.selectSource(sources[0] ?? ""); + }, [selectedSource, sources]); + + return ( +
+
+
+ Kernels +
+ +
+
+ +
+
+ + +
+
+ ); +}; diff --git a/frontend/src/components/terminal/symbol-focus.tsx b/frontend/src/components/terminal/symbol-focus.tsx new file mode 100644 index 00000000..175dcb59 --- /dev/null +++ b/frontend/src/components/terminal/symbol-focus.tsx @@ -0,0 +1,82 @@ +import type { MouseEvent, ReactNode } from "react"; +import { appStore } from "#/collections/app"; +import { terminalStore } from "#/collections/terminal"; + +const symbolExact = + /^[A-Za-z0-9][A-Za-z0-9._-]{0,19}\/(?:USD|EUR|USDT|USDC|BTC|ETH|GBP|CAD|AUD|JPY|CHF)$/i; +const symbolText = + /\b[A-Za-z0-9][A-Za-z0-9._-]{0,19}\/(?:USD|EUR|USDT|USDC|BTC|ETH|GBP|CAD|AUD|JPY|CHF)\b/gi; + +export const SymbolFocusLayer = ({ children }: { children: ReactNode }) => { + const onClickCapture = (event: MouseEvent) => { + const selection = window.getSelection(); + + if (selection !== null && !selection.isCollapsed) { + return; + } + + if (!(event.target instanceof Element)) { + return; + } + + let symbol = ""; + const marked = event.target.closest("[data-symbol],[data-focus-symbol]"); + + if (marked !== null && event.currentTarget.contains(marked)) { + const value = ( + marked.getAttribute("data-symbol") ?? + marked.getAttribute("data-focus-symbol") ?? + "" + ) + .trim() + .toUpperCase(); + + if (symbolExact.test(value)) { + symbol = value; + } + } + + let current: Element | null = event.target; + + while ( + symbol === "" && + current !== null && + event.currentTarget.contains(current) + ) { + const text = current.textContent?.trim() ?? ""; + + if (text.length > 0 && text.length <= 120) { + const matches = text.match(symbolText) ?? []; + const symbols = [ + ...new Set(matches.map((value) => value.toUpperCase())), + ].filter((value) => symbolExact.test(value)); + + if (symbols.length === 1) { + symbol = String(symbols[0]); + } + } + + if (current === event.currentTarget) { + break; + } + + current = current.parentElement; + } + + if (symbol === "" || appStore.state.focusSymbol === symbol) { + return; + } + + appStore.actions.updateFocusSymbol(symbol); + terminalStore.actions.selectFocusSymbol(symbol); + }; + + return ( +
+ {children} +
+ ); +}; diff --git a/frontend/src/components/terminal/xray-layers.tsx b/frontend/src/components/terminal/xray-layers.tsx new file mode 100644 index 00000000..4c34572a --- /dev/null +++ b/frontend/src/components/terminal/xray-layers.tsx @@ -0,0 +1,142 @@ +import { heatColor } from "#/components/terminal/canvas"; + +const LAYER_NAMES = ["sensory", "micro", "meso", "macro"]; + +export const semanticLayerName = (index: number, count: number): string => { + if (index <= 0) { + return LAYER_NAMES[0] ?? "sensory"; + } + + if (index >= count - 1) { + return "macro"; + } + + if (count === 3) { + return "micro"; + } + + return LAYER_NAMES[index] ?? "latent"; +}; + +export const layerCellsFromState = ( + state: unknown, + cellCount = 16, +): number[] => { + const values = Array.isArray(state) + ? state.filter((value): value is number => typeof value === "number") + : []; + + if (values.length === 0 || cellCount <= 0) { + return []; + } + + if (values.length === cellCount) { + return values; + } + + if (values.length === 1) { + return Array.from({ length: cellCount }, () => values[0] ?? 0); + } + + return Array.from({ length: cellCount }, (_, index) => { + const position = (index / Math.max(cellCount - 1, 1)) * (values.length - 1); + const left = Math.floor(position); + const right = Math.min(values.length - 1, left + 1); + const ratio = position - left; + + return (values[left] ?? 0) * (1 - ratio) + (values[right] ?? 0) * ratio; + }); +}; + +const layerColor = (value: unknown): string => { + if (typeof value !== "number") { + return "var(--line)"; + } + + return heatColor((value + 1) / 2); +}; + +const layerErrorTone = (error: unknown): string => { + if (typeof error !== "number") { + return "var(--f4)"; + } + + if (error > 0.55) { + return "var(--down)"; + } + + if (error > 0.3) { + return "var(--warn)"; + } + + return "var(--up)"; +}; + +export const XrayLayerRows = ({ + layers, +}: { + layers: Record[]; +}) => ( +
+ {layers.map((layer, index) => { + const state = Array.isArray(layer.state) ? layer.state : []; + const error = typeof layer.error_norm === "number" ? layer.error_norm : 0; + const errorTone = layerErrorTone(layer.error_norm); + const layerIndex = + typeof layer.index === "number" && Number.isFinite(layer.index) + ? layer.index + : index; + const label = String( + layer.name ?? + layer.label ?? + `L${layerIndex} · ${semanticLayerName(index, layers.length)}`, + ); + const cells = layerCellsFromState(state); + const occurrences = new Map(); + const keyedCells = cells.map((value) => { + const valueKey = value.toFixed(6); + const count = occurrences.get(valueKey) ?? 0; + + occurrences.set(valueKey, count + 1); + + return { + key: `${label}-${valueKey}-${count}`, + value, + }; + }); + const errorWidth = Math.min(100, Math.max(0, error * 100)); + + return ( +
+ + {label} + +
+ {keyedCells.map((cell) => ( +
+ ))} +
+
+
+ ε + {error.toFixed(3)} +
+
+
+
+
+
+ ); + })} +
+); diff --git a/frontend/src/components/trade-history.tsx b/frontend/src/components/trade-history.tsx deleted file mode 100644 index 45abc69b..00000000 --- a/frontend/src/components/trade-history.tsx +++ /dev/null @@ -1,137 +0,0 @@ -import { ArrowDownRightIcon, ArrowUpRightIcon, MinusIcon } from "lucide-react"; -import type { - TradeHistoryOutcome, - TradeHistoryRow, -} from "#/components/panels/data/trade-history-data-provider"; -import { - useSymmConnected, - useSymmTradeHistoryRows, -} from "#/lib/symm/use-dashboard-data"; - -const formatSignedEur = (value: number) => { - const prefix = value >= 0 ? "+" : "−"; - - return `${prefix}€${Math.abs(value).toFixed(4)}`; -}; - -const formatPrice = (value: number) => { - if (Math.abs(value) < 1) { - return value.toFixed(4); - } - - return value.toFixed(2); -}; - -const formatTime = (value: string) => { - const parsed = Date.parse(value); - - if (!Number.isFinite(parsed)) { - return value; - } - - return new Intl.DateTimeFormat(undefined, { - month: "short", - day: "numeric", - hour: "2-digit", - minute: "2-digit", - hour12: false, - }).format(parsed); -}; - -const outcomeMeta: Record< - TradeHistoryOutcome, - { label: string; tone: string; Icon: typeof ArrowUpRightIcon } -> = { - profit: { - label: "profit", - tone: "text-emerald-400", - Icon: ArrowUpRightIcon, - }, - loss: { - label: "loss", - tone: "text-rose-400", - Icon: ArrowDownRightIcon, - }, - flat: { - label: "flat", - tone: "text-muted-foreground", - Icon: MinusIcon, - }, -}; - -const HistoryRow = ({ row }: { row: TradeHistoryRow }) => { - const outcome = outcomeMeta[row.outcome]; - - return ( -
  • -
    -
    -
    -
    - {row.reason ? ( -

    - {row.reason} -

    - ) : null} -
    -
    -
    - {formatSignedEur(row.realizedEur)} -
    - {row.realizedPct !== undefined ? ( -
    - {row.realizedPct >= 0 ? "+" : "−"} - {Math.abs(row.realizedPct).toFixed(2)}% -
    - ) : null} -
    -
    -
    - {outcome.label} - - {formatTime(row.closedAt)} - -
    - {row.entryPrice !== undefined || row.exitPrice !== undefined ? ( -
    - {row.qty !== undefined ? `${row.qty.toFixed(6)} · ` : ""} - {row.entryPrice !== undefined - ? `entry ${formatPrice(row.entryPrice)}` - : ""} - {row.exitPrice !== undefined - ? ` · exit ${formatPrice(row.exitPrice)}` - : ""} -
    - ) : null} -
  • - ); -}; - -export const TradeHistoryPanel = () => { - const connected = useSymmConnected(); - const rows = useSymmTradeHistoryRows(); - - return ( -
    -

    - Trade history -

    - {rows.length === 0 ? ( -

    - {connected ? "No closed trades yet" : "Connect to load trade history"} -

    - ) : ( -
      - {rows.map((row) => ( - - ))} -
    - )} -
    - ); -}; diff --git a/frontend/src/components/trades.tsx b/frontend/src/components/trades.tsx deleted file mode 100644 index 81ce5ae7..00000000 --- a/frontend/src/components/trades.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import { - useSymmConnected, - useSymmTradePanelRows, -} from "#/lib/symm/use-dashboard-data"; -import { EmptyHint } from "./hint"; -import type { TradePanelRow } from "./panels/data/trades-data-provider"; -import { SidebarSection } from "./sidebar-section"; - -const formatSignedEur = (value: number) => { - const prefix = value >= 0 ? "+" : "−"; - - return `${prefix}€${Math.abs(value).toFixed(4)}`; -}; - -const formatPrice = (value: number) => { - if (Math.abs(value) < 1) { - return value.toFixed(4); - } - - return value.toFixed(2); -}; - -const pnlClass = (value: number | undefined) => { - if (value === undefined || value === 0) { - return "text-(--dash-muted)"; - } - - return value > 0 ? "text-emerald-400" : "text-rose-400"; -}; - -const OpenRow = ({ row }: { row: TradePanelRow }) => ( -
  • -
    - OPEN {row.symbol} - {row.unrealizedEur !== undefined ? ( - - P/L - {formatSignedEur(row.unrealizedEur)} - - ) : row.qty !== undefined ? ( - - {row.qty.toFixed(6)} - - ) : null} -
    -
    - - open - {row.entryPrice !== undefined - ? ` · entry ${formatPrice(row.entryPrice)}` - : ""} - {row.markPrice !== undefined - ? ` · mark ${formatPrice(row.markPrice)}` - : ""} - - {row.unrealizedPct !== undefined ? ( - - {row.unrealizedPct >= 0 ? "+" : "−"} - {Math.abs(row.unrealizedPct).toFixed(2)}% - - ) : ( - inventory - )} -
    -
  • -); - -const FillRow = ({ row }: { row: TradePanelRow }) => { - const label = row.kind === "enter" ? "BUY" : "SELL"; - const labelClass = - row.kind === "enter" ? "text-emerald-400" : "text-rose-400"; - - return ( -
  • -
    - - {label} {row.symbol} - - {row.notionalEur !== undefined ? ( - - €{row.notionalEur.toFixed(2)} - - ) : null} -
    -
    - fill - {row.price !== undefined && row.qty !== undefined ? ( - - {row.qty.toFixed(6)} @ {formatPrice(row.price)} - - ) : null} -
    -
  • - ); -}; - -export const TradesPanel = () => { - const connected = useSymmConnected(); - const rows = useSymmTradePanelRows(); - - return ( - - {rows.length === 0 ? ( - - ) : ( -
      - {rows - .slice(0, 24) - .map((row) => - row.kind === "open" ? ( - - ) : ( - - ), - )} -
    - )} -
    - ); -}; diff --git a/frontend/src/components/ui/accordion.tsx b/frontend/src/components/ui/accordion.tsx deleted file mode 100644 index a6026ba4..00000000 --- a/frontend/src/components/ui/accordion.tsx +++ /dev/null @@ -1,68 +0,0 @@ -"use client"; - -import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion"; -import { ChevronDownIcon } from "lucide-react"; -import type React from "react"; -import { cn } from "@/lib/utils"; - -export function Accordion( - props: AccordionPrimitive.Root.Props, -): React.ReactElement { - return ; -} - -export function AccordionItem({ - className, - ...props -}: AccordionPrimitive.Item.Props): React.ReactElement { - return ( - - ); -} - -export function AccordionTrigger({ - className, - children, - ...props -}: AccordionPrimitive.Trigger.Props): React.ReactElement { - return ( - - - {children} - - - - ); -} - -export function AccordionPanel({ - className, - children, - ...props -}: AccordionPrimitive.Panel.Props): React.ReactElement { - return ( - -
    {children}
    -
    - ); -} - -export { AccordionPrimitive, AccordionPanel as AccordionContent }; diff --git a/frontend/src/components/ui/alert-dialog.tsx b/frontend/src/components/ui/alert-dialog.tsx deleted file mode 100644 index fed42706..00000000 --- a/frontend/src/components/ui/alert-dialog.tsx +++ /dev/null @@ -1,167 +0,0 @@ -"use client"; - -import { AlertDialog as AlertDialogPrimitive } from "@base-ui/react/alert-dialog"; -import type React from "react"; -import { cn } from "@/lib/utils"; - -export const AlertDialogCreateHandle: typeof AlertDialogPrimitive.createHandle = - AlertDialogPrimitive.createHandle; - -export const AlertDialog: typeof AlertDialogPrimitive.Root = - AlertDialogPrimitive.Root; - -export const AlertDialogPortal: typeof AlertDialogPrimitive.Portal = - AlertDialogPrimitive.Portal; - -export function AlertDialogTrigger( - props: AlertDialogPrimitive.Trigger.Props, -): React.ReactElement { - return ( - - ); -} - -export function AlertDialogBackdrop({ - className, - ...props -}: AlertDialogPrimitive.Backdrop.Props): React.ReactElement { - return ( - - ); -} - -export function AlertDialogViewport({ - className, - ...props -}: AlertDialogPrimitive.Viewport.Props): React.ReactElement { - return ( - - ); -} - -export function AlertDialogPopup({ - className, - bottomStickOnMobile = true, - portalProps, - ...props -}: AlertDialogPrimitive.Popup.Props & { - bottomStickOnMobile?: boolean; - portalProps?: AlertDialogPrimitive.Portal.Props; -}): React.ReactElement { - return ( - - - - - - - ); -} - -export function AlertDialogHeader({ - className, - ...props -}: React.ComponentProps<"div">): React.ReactElement { - return ( -
    - ); -} - -export function AlertDialogFooter({ - className, - variant = "default", - ...props -}: React.ComponentProps<"div"> & { - variant?: "default" | "bare"; -}): React.ReactElement { - return ( -
    - ); -} - -export function AlertDialogTitle({ - className, - ...props -}: AlertDialogPrimitive.Title.Props): React.ReactElement { - return ( - - ); -} - -export function AlertDialogDescription({ - className, - ...props -}: AlertDialogPrimitive.Description.Props): React.ReactElement { - return ( - - ); -} - -export function AlertDialogClose( - props: AlertDialogPrimitive.Close.Props, -): React.ReactElement { - return ( - - ); -} - -export { - AlertDialogPrimitive, - AlertDialogBackdrop as AlertDialogOverlay, - AlertDialogPopup as AlertDialogContent, -}; diff --git a/frontend/src/components/ui/alert.tsx b/frontend/src/components/ui/alert.tsx deleted file mode 100644 index 722fd95e..00000000 --- a/frontend/src/components/ui/alert.tsx +++ /dev/null @@ -1,84 +0,0 @@ -import { cva, type VariantProps } from "class-variance-authority"; -import type * as React from "react"; -import { cn } from "@/lib/utils"; - -const alertVariants = cva( - "relative grid w-full items-start gap-x-2 gap-y-0.5 rounded-xl border px-3.5 py-3 text-card-foreground text-sm has-[>svg]:has-data-[slot=alert-action]:grid-cols-[calc(var(--spacing)*4)_1fr_auto] has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-data-[slot=alert-action]:grid-cols-[1fr_auto] has-[>svg]:gap-x-2 [&>svg]:h-lh [&>svg]:w-4", - { - defaultVariants: { - variant: "default", - }, - variants: { - variant: { - default: - "bg-transparent dark:bg-input/32 [&>svg]:text-muted-foreground", - error: - "border-destructive/32 bg-destructive/4 [&>svg]:text-destructive", - info: "border-info/32 bg-info/4 [&>svg]:text-info", - success: "border-success/32 bg-success/4 [&>svg]:text-success", - warning: "border-warning/32 bg-warning/4 [&>svg]:text-warning", - }, - }, - }, -); - -export function Alert({ - className, - variant, - ...props -}: React.ComponentProps<"div"> & - VariantProps): React.ReactElement { - return ( -
    - ); -} - -export function AlertTitle({ - className, - ...props -}: React.ComponentProps<"div">): React.ReactElement { - return ( -
    - ); -} - -export function AlertDescription({ - className, - ...props -}: React.ComponentProps<"div">): React.ReactElement { - return ( -
    - ); -} - -export function AlertAction({ - className, - ...props -}: React.ComponentProps<"div">): React.ReactElement { - return ( -
    - ); -} diff --git a/frontend/src/components/ui/autocomplete.tsx b/frontend/src/components/ui/autocomplete.tsx deleted file mode 100644 index 13f873f3..00000000 --- a/frontend/src/components/ui/autocomplete.tsx +++ /dev/null @@ -1,316 +0,0 @@ -"use client"; - -import { Autocomplete as AutocompletePrimitive } from "@base-ui/react/autocomplete"; -import { ChevronsUpDownIcon, XIcon } from "lucide-react"; -import type React from "react"; -import { Input } from "@/components/ui/input"; -import { ScrollArea } from "@/components/ui/scroll-area"; -import { cn } from "@/lib/utils"; - -export const Autocomplete: typeof AutocompletePrimitive.Root = - AutocompletePrimitive.Root; - -export const AutocompleteInput = ({ - className, - showTrigger = false, - showClear = false, - startAddon, - size, - triggerProps, - clearProps, - ...props -}: Omit & { - showTrigger?: boolean; - showClear?: boolean; - startAddon?: React.ReactNode; - size?: "sm" | "default" | "lg" | number; - ref?: React.Ref; - triggerProps?: AutocompletePrimitive.Trigger.Props; - clearProps?: AutocompletePrimitive.Clear.Props; -}): React.ReactElement => { - const sizeValue = (size ?? "default") as "sm" | "default" | "lg" | number; - - return ( - - {startAddon && ( - - )} - } - {...props} - /> - {showTrigger && ( - - - - - - )} - {showClear && ( - - - - )} - - ); -}; - -export const AutocompletePopup = ({ - className, - children, - side = "bottom", - sideOffset = 4, - alignOffset, - align = "start", - anchor, - portalProps, - ...props -}: AutocompletePrimitive.Popup.Props & { - align?: AutocompletePrimitive.Positioner.Props["align"]; - sideOffset?: AutocompletePrimitive.Positioner.Props["sideOffset"]; - alignOffset?: AutocompletePrimitive.Positioner.Props["alignOffset"]; - side?: AutocompletePrimitive.Positioner.Props["side"]; - anchor?: AutocompletePrimitive.Positioner.Props["anchor"]; - portalProps?: AutocompletePrimitive.Portal.Props; -}): React.ReactElement => { - return ( - - - - - {children} - - - - - ); -}; - -export const AutocompleteItem = ({ - className, - children, - ...props -}: AutocompletePrimitive.Item.Props): React.ReactElement => { - return ( - - {children} - - ); -}; - -export const AutocompleteSeparator = ({ - className, - ...props -}: AutocompletePrimitive.Separator.Props): React.ReactElement => { - return ( - - ); -}; - -export const AutocompleteGroup = ({ - className, - ...props -}: AutocompletePrimitive.Group.Props): React.ReactElement => { - return ( - - ); -}; - -export const AutocompleteGroupLabel = ({ - className, - ...props -}: AutocompletePrimitive.GroupLabel.Props): React.ReactElement => { - return ( - - ); -}; - -export const AutocompleteEmpty = ({ - className, - ...props -}: AutocompletePrimitive.Empty.Props): React.ReactElement => { - return ( - - ); -}; - -export const AutocompleteRow = ({ - className, - ...props -}: AutocompletePrimitive.Row.Props): React.ReactElement => { - return ( - - ); -}; - -export const AutocompleteValue = ({ - ...props -}: AutocompletePrimitive.Value.Props): React.ReactElement => { - return ( - - ); -}; - -export const AutocompleteList = ({ - className, - ...props -}: AutocompletePrimitive.List.Props): React.ReactElement => { - return ( - - - - ); -}; - -export const AutocompleteClear = ({ - className, - ...props -}: AutocompletePrimitive.Clear.Props): React.ReactElement => { - return ( - - - - ); -}; - -export const AutocompleteStatus = ({ - className, - ...props -}: AutocompletePrimitive.Status.Props): React.ReactElement => { - return ( - - ); -}; - -export const AutocompleteCollection = ({ - ...props -}: AutocompletePrimitive.Collection.Props): React.ReactElement => { - return ( - - ); -}; - -export const AutocompleteTrigger = ({ - className, - children, - ...props -}: AutocompletePrimitive.Trigger.Props): React.ReactElement => { - return ( - - {children} - - ); -}; - -export const useAutocompleteFilter: typeof AutocompletePrimitive.useFilter = - AutocompletePrimitive.useFilter; - -export { AutocompletePrimitive }; diff --git a/frontend/src/components/ui/avatar.tsx b/frontend/src/components/ui/avatar.tsx deleted file mode 100644 index d6f46ded..00000000 --- a/frontend/src/components/ui/avatar.tsx +++ /dev/null @@ -1,52 +0,0 @@ -"use client"; - -import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar"; -import type React from "react"; -import { cn } from "@/lib/utils"; - -export function Avatar({ - className, - ...props -}: AvatarPrimitive.Root.Props): React.ReactElement { - return ( - - ); -} - -export function AvatarImage({ - className, - ...props -}: AvatarPrimitive.Image.Props): React.ReactElement { - return ( - - ); -} - -export function AvatarFallback({ - className, - ...props -}: AvatarPrimitive.Fallback.Props): React.ReactElement { - return ( - - ); -} - -export { AvatarPrimitive }; diff --git a/frontend/src/components/ui/badge.tsx b/frontend/src/components/ui/badge.tsx deleted file mode 100644 index 675f330a..00000000 --- a/frontend/src/components/ui/badge.tsx +++ /dev/null @@ -1,64 +0,0 @@ -"use client"; - -import { mergeProps } from "@base-ui/react/merge-props"; -import { useRender } from "@base-ui/react/use-render"; -import { cva, type VariantProps } from "class-variance-authority"; -import type React from "react"; -import { cn } from "@/lib/utils"; - -export const badgeVariants = cva( - "relative inline-flex shrink-0 items-center justify-center gap-1 whitespace-nowrap rounded-sm border border-transparent font-medium outline-none transition-shadow focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background disabled:pointer-events-none disabled:opacity-64 [&_svg:not([class*='opacity-'])]:opacity-80 [&_svg:not([class*='size-'])]:size-3.5 sm:[&_svg:not([class*='size-'])]:size-3 [&_svg]:pointer-events-none [&_svg]:shrink-0 [button&,a&]:cursor-pointer [button&,a&]:pointer-coarse:after:absolute [button&,a&]:pointer-coarse:after:size-full [button&,a&]:pointer-coarse:after:min-h-11 [button&,a&]:pointer-coarse:after:min-w-11", - { - defaultVariants: { - size: "default", - variant: "default", - }, - variants: { - size: { - default: - "h-5.5 min-w-5.5 px-[calc(--spacing(1)-1px)] text-sm sm:h-4.5 sm:min-w-4.5 sm:text-xs", - lg: "h-6.5 min-w-6.5 px-[calc(--spacing(1.5)-1px)] text-base sm:h-5.5 sm:min-w-5.5 sm:text-sm", - sm: "h-5 min-w-5 rounded-[.25rem] px-[calc(--spacing(1)-1px)] text-xs sm:h-4 sm:min-w-4 sm:text-[.625rem]", - }, - variant: { - default: - "bg-primary text-primary-foreground [button&,a&]:hover:bg-primary/90", - destructive: - "bg-destructive text-white [button&,a&]:hover:bg-destructive/90", - error: - "bg-destructive/8 text-destructive-foreground dark:bg-destructive/16", - info: "bg-info/8 text-info-foreground dark:bg-info/16", - outline: - "border-input bg-background text-foreground dark:bg-input/32 [button&,a&]:hover:bg-accent/50 dark:[button&,a&]:hover:bg-input/48", - secondary: - "bg-secondary text-secondary-foreground [button&,a&]:hover:bg-secondary/90", - success: "bg-success/8 text-success-foreground dark:bg-success/16", - warning: "bg-warning/8 text-warning-foreground dark:bg-warning/16", - }, - }, - }, -); - -export interface BadgeProps extends useRender.ComponentProps<"span"> { - variant?: VariantProps["variant"]; - size?: VariantProps["size"]; -} - -export function Badge({ - className, - variant, - size, - render, - ...props -}: BadgeProps): React.ReactElement { - const defaultProps = { - className: cn(badgeVariants({ className, size, variant })), - "data-slot": "badge", - }; - - return useRender({ - defaultTagName: "span", - props: mergeProps<"span">(defaultProps, props), - render, - }); -} diff --git a/frontend/src/components/ui/breadcrumb.tsx b/frontend/src/components/ui/breadcrumb.tsx deleted file mode 100644 index dc62df36..00000000 --- a/frontend/src/components/ui/breadcrumb.tsx +++ /dev/null @@ -1,109 +0,0 @@ -"use client"; - -import { mergeProps } from "@base-ui/react/merge-props"; -import { useRender } from "@base-ui/react/use-render"; -import { ChevronRight, MoreHorizontal } from "lucide-react"; -import type * as React from "react"; -import { cn } from "@/lib/utils"; - -export function Breadcrumb({ - ...props -}: React.ComponentProps<"nav">): React.ReactElement { - return