From 09f951486a556a2952741df30d9a1063d8d3a837 Mon Sep 17 00:00:00 2001 From: Raoul Date: Wed, 19 Aug 2026 11:25:01 +0000 Subject: [PATCH 01/13] feat: a real call stack, shared by the editor and the CLI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Callstack view showed one frame, named after a wasm instruction and carrying the replay position in its label. It now shows every frame that led to the current line, and `soroban-trace` reports the same stack per stop as `frames` — both from one derivation, `debugAdapter/callStack.ts`, so a script and a debug session can never disagree about who called whom. The stack is assembled from three sources, ordered by how much each can be trusted, and every frame states which one placed it: The trace's own wasm activations are the STRUCTURE. `computeDepths` becomes `computeFrames`, which returns the linked activation stack (`fn`, `depth`, `callSite`, `caller`) the depths were always a projection of; depth is now that projection, so the frame count and step-over/ step-out are derived from the same walk and cannot drift apart. An outer frame stands at the call it is suspended in, which is also the record its own locals were last observed at. DWARF adds the Rust frames inlining erased. `ScopeIndex.inlineScopesAt` walks the DW_TAG_inlined_subroutine instances covering a pc, resolving names through abstract_origin/specification/linkage_name and call sites through call_file/call_line; LineTable keeps each unit's file table so a call-site file INDEX resolves to a path. An instance whose range this parser cannot read (a v5 .debug_rnglists list) is skipped, never guessed at: a missing frame degrades the view, an invented one misreports the program. The trace's contract-call boundaries close the stack below as labels. Names come off a precision ladder: the DWARF subprogram name qualified by its enclosing namespaces and types, else the module's `name`-section symbol demangled (new wasm/names.ts — rustc leaves some method DIEs anonymous, so this rung matters even in a DWARF build), else the function index, else the raw offset. A frame is never nameless, and a release build with no debug info still gets `control::Control::while_call+0x1a`. Frames are inspectable per frame, not just at the top: a variables reference now encodes the frame together with the scope kind, so Locals, Value Stack and Variables answer for the SELECTED frame, read from that frame's own record. Linear memory stays at the cursor — a callee may have written through a reference the caller still holds. `stackTrace` honors the client's paging window, gives each frame its own id and instruction pointer reference (so Disassembly follows the selection), and reports a non-workspace or sourceless frame as `subtle` rather than dropping it: an optimized build can put eight SDK conversion frames between the user's code and the pc, and a stack that quietly hid them would be a lie about how the program got here. The replay position moves out of the frame name into the thread label (`soroban-vm [29/40]`). A frame name says what the program is doing; where the cursor sits is a property of the recorded thread. The rules are specified as C1-C8 in the new docs/callstack.md, pinned by test/callStack.test.ts and test/dapFrames.test.ts across the fixture spread that matters: opt-0, optimized, stripped of DWARF, without a name section, and with no wasm at all. --- CHANGELOG.md | 5 +- CONTRIBUTING.md | 13 +- README.md | 2 +- docs/callstack.md | 77 +++++ docs/stepping.md | 5 +- docs/trace-cli-internal.md | 12 + docs/trace-cli.md | 17 +- src/debugAdapter/SorobanDebugSession.ts | 285 ++++++++++++------ src/debugAdapter/artifacts.ts | 25 +- src/debugAdapter/callStack.ts | 226 ++++++++++++++ src/debugAdapter/stopModel.ts | 19 +- src/debugAdapter/stops.ts | 143 +++++++-- src/dwarf/LineTable.ts | 30 +- src/dwarf/ScopeIndex.ts | 203 ++++++++++++- src/dwarf/constants.ts | 10 + src/dwarf/die.ts | 6 + src/sourcemap/DwarfSourceMapper.ts | 29 +- src/sourcemap/NullSourceMapper.ts | 8 + src/sourcemap/SourceMapper.ts | 8 + src/sourcemap/VariableResolver.ts | 87 +++++- src/trace/projectStop.ts | 49 +++ src/wasm/Disassembly.ts | 20 +- src/wasm/names.ts | 195 ++++++++++++ src/wasm/sections.ts | 6 +- test/callStack.test.ts | 377 ++++++++++++++++++++++++ test/dap.test.ts | 61 ++-- test/dapControlStepping.test.ts | 6 +- test/dapFrames.test.ts | 288 ++++++++++++++++++ test/dapStepping.test.ts | 8 +- test/dapVariables.test.ts | 23 +- test/dwarfSourceMapper.test.ts | 39 +++ test/justMyCode.test.ts | 8 + test/projectStop.test.ts | 21 ++ test/replayCursor.test.ts | 5 + test/scopeIndex.test.ts | 185 ++++++++++++ test/wasmNames.test.ts | 153 ++++++++++ 36 files changed, 2441 insertions(+), 213 deletions(-) create mode 100644 docs/callstack.md create mode 100644 src/debugAdapter/callStack.ts create mode 100644 src/wasm/names.ts create mode 100644 test/callStack.test.ts create mode 100644 test/dapFrames.test.ts create mode 100644 test/wasmNames.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index fcae92a..93b3a07 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,11 +38,12 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - The `soroban-trace` CLI reports the same state per stop as `globals` and `ledger`, with a `changed` flag marking the storage entries that moved since the previous stop, and `hasGlobals`/`hasLedger` announced in `meta`. -- New contributor spec: [`docs/state-inspection.md`](docs/state-inspection.md), - whose numbered rules (G1–G4, L1–L15) the test suite pins. +- **A real call stack.** The Callstack view now shows every frame that led to the current line — not one frame named after a wasm instruction. Frame *structure* comes from the trace's own wasm activations, so it is right at any optimization level, and DWARF adds the Rust frames inlining erased: an optimized build still shows `add` → `invoke_raw` → the export wrapper rather than one collapsed function. Outer frames stand on the call they are suspended in, every frame is selectable and shows *its own* locals, wasm stack and Rust variables, and the Disassembly view follows the selected frame. Names come off a precision ladder — DWARF, then the demangled `name` section, then the function index, then the code offset — so a release build with no debug info still gets `control::Control::while_call+0x1a` instead of a bare address, and the trace's contract-call boundaries close the stack as labels at the bottom. Frames the user did not write (Rust `std`/`core`, dependencies) are deemphasized rather than hidden. `soroban-trace` reports the same stack per stop as `frames`. +- New contributor specs: [`docs/state-inspection.md`](docs/state-inspection.md) (rules G1–G4, L1–L15) and [`docs/callstack.md`](docs/callstack.md) (rules C1–C8), both pinned by the test suite. ### Changed +- The replay cursor's position in the recording moved out of the stack frame's name and into the thread's label (`soroban-vm [29/40]`): a frame name now says what the program is doing, and where the cursor sits is a property of the recorded thread. - **The single-invoke launch config is gone.** `contract`, `function`, `args`, `buildCommand` and `debugInfo` no longer sit at the top level: wrap them in a `transactions` array (see [`docs/debug-config.md`](docs/debug-config.md)). A diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8298b27..1411ab9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -143,8 +143,11 @@ debugAdapter/ records, call depths, statement stops (shared with the CLI) replayCursor.ts the stepping engine — every forward/reverse move and the breakpoint resolution, as cursor moves over a StopModel - stops.ts the pure derivations stopModel is built from (depths, - line runs, S17/S18/S21 stop filtering) + stops.ts the pure derivations stopModel is built from (wasm frame + stacks + depths, line runs, S17/S18/S21 stop filtering) + callStack.ts the frames both front ends show: wasm activations, the + Rust frames inlining erased, contract boundaries + (docs/callstack.md) TraceModel records + replay cursor; owns the two state images below, built lazily and shared by every consumer MemoryImage linear memory at a cursor (snapshot-on-change index) @@ -181,17 +184,21 @@ soroban/strkey.ts raw address bytes -> C…/G… strkey (SDK-free: the SDK the DAP handshake) wasm/ sections.ts wasm section walker (offsets, custom-section lookup) + names.ts the `name` section + Rust demangling: how a frame is + labelled when the build carries no DWARF Disassembly.ts static disassembly (wasmparser), code-offset addressed dwarf/ DWARF v4/v5 .debug_line/.debug_info parser -> LineTable sourcemap/ SourceMapper the mapping seam the adapter talks to DwarfSourceMapper trace index / code offset -> Rust file:line (+ breakpoints) NullSourceMapper no-DWARF fallback (disassembly-only) + VariableResolver the source-level view of a pc: enclosing function, inlined + frames, in-scope variables, decoded values ``` All replay logic is free of the `vscode` API, so it can be unit-tested in plain Node; the `vscode`-only glue lives in `extension.ts`. For a deep dive on the -stepping model, see [`docs/stepping.md`](docs/stepping.md). +stepping model, see [`docs/stepping.md`](docs/stepping.md); for the frame model behind the Callstack view, see [`docs/callstack.md`](docs/callstack.md). ## Pull requests diff --git a/README.md b/README.md index 814c25a..3fb2a34 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ directions. your actual `.rs` files — not opaque bytecode. - ⏪ **Step backward.** Step back and reverse-continue as easily as going forward. Overshot the bug? Just step back. Backward stepping is instant. +- 🧭 **Follow the call stack.** Every Rust frame that led to the current line, including the ones the optimizer inlined away — select any frame to inspect *its* variables and jump to *its* line. - 🔎 **Inspect state at every step.** See the values in play at the current point of execution — your Rust variables, the wasm locals, stack and globals. - 🏦 **See the ledger, not just the code.** Contract storage (instance, @@ -136,7 +137,6 @@ internally. ## Roadmap -- Multi-frame call stacks with per-frame locals - A source-level Variables view with inline values - Column-level breakpoints diff --git a/docs/callstack.md b/docs/callstack.md new file mode 100644 index 0000000..ad7444d --- /dev/null +++ b/docs/callstack.md @@ -0,0 +1,77 @@ +# Call stack semantics + +> **Audience:** `contributor` · `maintainer` (frames, Callstack view) +> +> **TL;DR:** What the Callstack view shows and why it can be trusted at any optimization level. Frame STRUCTURE always comes from the trace's own wasm activations (C1); DWARF adds the Rust frames inlining erased (C2); the trace's contract boundaries close the stack at the bottom (C3). Names come off a precision ladder — DWARF, then the `name` section, then the function index, then the address (C4) — so a frame is never nameless and never labelled with something less precise than the build made available. The numbered rules C1–C8 are pinned by `test/callStack.test.ts` and `test/dapFrames.test.ts`. + +Where the rules live in the code: the activation reconstruction is `computeFrames` in `src/debugAdapter/stops.ts` (assembled into the `StopModel`, so stepping and frames share one derivation); the inline chain is `ScopeIndex.inlineScopesAt` behind `VariableResolver.inlineFramesAt`; the assembly of the three sources into frames is `src/debugAdapter/callStack.ts`, which both `SorobanDebugSession.stackTraceRequest` and the CLI's `projectSourceStop` call. Every one of those is pure and unit-tested without a DAP client. + +## Why not "Rust frames OR wasm frames" + +A recorded trace and a DWARF section disagree about what a frame is, and both are right about different things: + +- The **trace** knows exactly which wasm function bodies are active. It cannot know that four Rust functions were inlined into one of them. +- **DWARF** knows the Rust call chain the programmer wrote. Its line table and inline records are only as complete as the optimizer left them. + +So the view does not pick one. It takes the **structure** from the trace, which can never be wrong about the number of live activations, and takes **identity, position and inline depth** from the most precise source available at each frame. That is what makes the same view usable across build settings: + +| build | what the stack shows | +| --- | --- | +| opt-0 + DWARF (what the debugger builds by default) | Rust frames one-to-one with activations, plus the occasional `#[inline(always)]` frame; every frame located in the user's source | +| optimized + DWARF | fewer activations, with the erased Rust chain restored as inline frames (C2) — the whole chain is still named and located | +| no DWARF (release, `debugInfo: false`, stripped) | one frame per activation, named from the demangled `name` section, positioned by code offset (C4) | +| no wasm at all (`rawTrace` replay) | one frame per activation from the opcode walk, addressed but unnamed | + +```mermaid +flowchart TB + T["trace records"] -->|"computeFrames:
function membership of visible records"| ACT["wasm activations
C1 — structure, always trustworthy"] + ACT -->|"per activation pc:
DW_TAG_inlined_subroutine chain"| INL["+ inline frames
C2 — the Rust chain optimization erased"] + INL -->|"LedgerImage open calls"| CON["+ contract boundaries
C3 — host-level invocations"] + CON -->|"DWARF name → name section → func index → address"| OUT["Callstack view / CLI frames
C4 — named, C5 — deemphasized, C7 — inspectable"] +``` + +## Rules + +- **C1** (activations are the structure): the frames of a stack are, innermost first, the reconstructed wasm activation stack at the cursor — `computeFrames`, the same walk `depths` is projected from. + The number of activation frames is therefore always `depth + 1`, so the Callstack view and `next`/`stepOut` can never disagree about what frame the cursor is in. + An activation is positioned at the record it is executing: the cursor's record for the innermost frame, and for an outer frame the `call` instruction that entered the frame below it — which is what a caller frame reports in every debugger. + Without function-body ranges (wasm-less replay) the opcode walk supplies the same structure, minus function identity. +- **C2** (inline frames): when DWARF is present, each activation's pc is expanded through the `DW_TAG_inlined_subroutine` instances covering it, and each becomes a frame ABOVE the activation. + Positions shift by one along the chain: the innermost frame stands where the line table points, and every frame below it stands at its callee's `DW_AT_call_file`/`DW_AT_call_line` — the line the inlined call was written on. + Without this, a frame would carry the name of the wrapper function while the cursor sat on the inlined function's source line, which is the single most confusing thing a call stack can do. + An instance whose range this parser cannot read (a DWARF v5 `.debug_rnglists` list, or an absent `.debug_ranges`) is skipped, never guessed at: a missing frame degrades the view, an invented one misreports the program. +- **C3** (contract boundaries): the trace's own `callContract` boundaries (`LedgerImage`) are appended BELOW every wasm frame, innermost call first, as `increment() @ CA5XKA…7QFM`. + They are reported to DAP with `presentationHint: 'label'` — they mark a host-level invocation, not a code position, so they have no source, no pc and no scopes. + A trace carrying no call boundaries contributes none. +- **C4** (naming ladder): a frame's label is the first of these that exists — the DWARF subprogram name qualified by its enclosing namespaces and types (`control::__while_call::invoke_raw`); the module's `name`-section symbol, demangled (`control::Control::while_call` — rustc leaves some method DIEs anonymous, so this rung matters even in a DWARF build); the wasm function index (`func[7]`); the raw code offset (`wasm@0x2d`). + A frame with no source location also carries its offset inside the function (`soroban_sdk::…::get+0x99`), because for a wasm-level frame that offset is the only position the user has. + A frame is never nameless, and an inlined frame DWARF names nowhere is `` rather than blank. +- **C5** (deemphasis, never hiding): a frame whose source is non-workspace (the S21 test — `/.rustup/`, `/.cargo/`, `/rustc/`) or which has no source at all in a session that HAS line info is reported `presentationHint: 'subtle'` with a `deemphasize`d source. + It is still there: an optimized build can put eight SDK conversion frames between the user's code and the pc, and a stack that quietly dropped them would be a lie about how the program got here. + In a session with no line info at all nothing is deemphasized — greying out every frame says nothing. +- **C6** (the whole stack, paged): `stackTrace` reports every frame with `totalFrames` set, honoring the client's `startFrame`/`levels` window. + Frame ids are the frame's own level, so a client that pages twice gets the same frame for the same id, and each frame carries its own `instructionPointerReference` — the Disassembly view follows the SELECTED frame, not just the innermost one. +- **C7** (frames are inspectable): `scopes`/`variables` answer for the SELECTED frame. + Locals, Value Stack and the source-level Variables of an outer frame are read from that frame's own record (the call it is suspended in), so they are the caller's values, not the innermost frame's; an inline frame reports the variables its own inlined instance declares, which is why stepping into optimized code still shows the callee's parameters and not the host function's. + Linear memory is read at the CURRENT cursor for every frame — a callee may have written through a reference the caller still holds, and at opt-0 the caller's own locals live in that memory. + Globals and the Ledger are VM-wide and are offered on every code frame; a contract-boundary frame offers no scopes. +- **C8** (the recording position): the cursor's place in the recording (`[29/40]`) is reported as part of the THREAD's name, not smuggled into a frame label. + A frame name states what the program is doing; where the replay cursor sits is a property of the recorded thread, and a client refreshes thread names on every stop. + +## Fixtures pinning these rules + +Each fixture is a different point in the build-settings space, which is exactly what these rules have to survive: + +- `adder-debug.{wasm,trace.jsonl}` — built above opt-0, so `add` is inlined into the `#[contractimpl]` wrapper *entirely*. At the statement stop (index 29, pc `0x2d`) the stack is `add` (lib.rs:16) → `invoke_raw` (lib.rs:12) → `adder::__add::invoke_raw_extern` (lib.rs:12): ONE activation, three frames (C2). The same trace replayed with no wasm gives the single frame `wasm@0x2d` (C4). +- `stepper-debug.{wasm,trace.jsonl}` — a real `call` (`triple` is `#[inline(never)]`) under an inlined caller. Inside `triple` (index 29) the stack is `stepper::triple` (lib.rs:15) → `sum_triples` (lib.rs:**26**, the call site) → `invoke_raw` → `invoke_raw_extern`, and the caller's variables are read from record 28 — the `call` — not from the cursor (C1, C2, C7). +- `control-debug.wasm` + `control-while_call.trace.jsonl` — opt-0, where the Rust chain IS the activation chain: inside `bump` (index 266) the stack is `control::bump` (lib.rs:16) → `control::Control::while_call` (lib.rs:56) → `invoke_raw` → `invoke_raw_extern`, with `while_call` named from the `name` section because its DIE is anonymous (C4) and each frame reporting its own variables (C7). +- `stepper-debug.wasm` with its `.debug_*` sections stripped in-test — the release build's stack: `stepper::triple` and `sum_triples+0x…`, named from the `name` section and positioned by offset (C4). +- `composite.wasm` — neither DWARF nor a `name` section, so a frame can only say which function body it is in: `func[N]` (C4). +- `increment-debug.{wasm,trace.jsonl}` — carries ledger events, so the stack ends in the `increment() @ …` boundary frame (C3). + +## Known limitations + +- The activation reconstruction's own edges apply unchanged (see [`stepping.md`](./stepping.md#known-limitations-of-depth-reconstruction)): direct self-recursion is invisible to a membership-based frame stack, and only the exact opcode spellings `call` / `call_indirect` / `return_call` / `return_call_indirect` are recognized as calls. +- Inline frames need `.debug_ranges` (DWARF v4). A v5 `.debug_rnglists` inline instance is skipped (C2), which costs frames rather than correctness — this parser reads v4 and v5 line programs but only v4 range lists. +- A frame's variables are decoded from the record the frame is positioned at. Wasm locals cannot be modified by a callee, so a caller's locals are exact; values reached THROUGH memory are read at the current cursor and are therefore as current as the trace's last memory snapshot. +- Only legacy Rust symbol mangling (`_ZN…E`) is demangled. A `-Csymbol-mangling-version=v0` build shows its `_R…` symbols verbatim — undemangled, but still the function's identity. diff --git a/docs/stepping.md b/docs/stepping.md index df91d17..883ed0c 100644 --- a/docs/stepping.md +++ b/docs/stepping.md @@ -161,8 +161,11 @@ every stop, the unfiltered run starts stand. ### Frames +The rules below govern where the INNERMOST frame stands. +What the rest of the stack is — the wasm activations under it, the Rust frames inlining erased, the contract boundaries below them — is specified separately in [`callstack.md`](./callstack.md) (C1–C8), which builds on the same frame reconstruction `depth` is projected from. + - **S16** (frame consistency): whenever the cursor rests on a mapped record, - the stack frame carries that record's source and line; the frame is + the innermost stack frame carries that record's source and line; the frame is sourceless only when the cursor legitimately rests on an unmapped stop point (instruction granularity, or no line info at all). - **S19** (line-start cursor): whenever the cursor rests on a mapped record, the diff --git a/docs/trace-cli-internal.md b/docs/trace-cli-internal.md index 196dacf..7c3a231 100644 --- a/docs/trace-cli-internal.md +++ b/docs/trace-cli-internal.md @@ -93,6 +93,9 @@ low-level resolver calls: - `variables.functionNameAt(pc)` → function name (**may be `null`** even with DWARF) - `makeRuntimeState(record, model.memory, index)` + `variables.variablesInScope(pc)` + `variables.decodeVariable(v, state, pc)` → decoded variables + `buildCallStack({resolved, frames, ranges}, index)` → the stop's `frames` + +`frames` is the SAME derivation the DAP session's `stackTrace` returns (`src/debugAdapter/callStack.ts`), projected to JSON — the CLI adds only hex `pc` formatting and drops the per-frame `variables` (a stop's `variables` are the innermost frame's; repeating every frame's would multiply the output size). Children (`DecodedValue.children`) are expanded **eagerly** into plain arrays, bounded by a per-stop budget: `maxDepth` (default 3), `maxChildren` (default 64), and a global @@ -108,12 +111,21 @@ interface SourceStop { depth: number; // stopModel.depths[traceIndex] pc: string | null; // hex, e.g. "0x2d", or null function: string | null; // functionNameAt(pc) or null + frames: StopFrame[]; // the call stack, innermost first (docs/callstack.md); never empty instr: string; // renderInstr(record.instr) source: { path: string; line: number; column?: number } | null; variables: TraceVar[]; globals?: Record; // module-relative index (G1) ledger?: StopLedger; // omitted when the trace carries no ledger info (L14) } +interface StopFrame { // see docs/callstack.md for the rules + level: number; // 0 = innermost + name: string; // never empty (C4) + kind: 'rust' | 'inline' | 'wasm' | 'contract'; + pc: string | null; // hex code offset, or null for a contract boundary + source: { path: string; line: number; column?: number } | null; + subtle?: true; // non-workspace or sourceless: deemphasize (C5) +} interface TraceVar { name: string; // "" when DWARF gives none type?: string; diff --git a/docs/trace-cli.md b/docs/trace-cli.md index c8e02db..e0e7967 100644 --- a/docs/trace-cli.md +++ b/docs/trace-cli.md @@ -81,7 +81,7 @@ JSONL to stdout: ```jsonl {"kind":"meta","function":"add","records":41,"stops":1,"hasDwarf":true} -{"kind":"stop","step":0,"traceIndex":29,"depth":0,"pc":"0x2d","function":"invoke_raw_extern","instr":"i32.add","source":{"path":".../examples/adder/src/lib.rs","line":16,"column":9},"variables":[{"name":"arg_0","type":"Val","value":"17179869188"},{"name":"arg_1","type":"Val","value":"12884901892"}]} +{"kind":"stop","step":0,"traceIndex":29,"depth":0,"pc":"0x2d","function":"invoke_raw_extern","frames":[{"level":0,"name":"add","kind":"inline","pc":"0x2d","source":{"path":".../examples/adder/src/lib.rs","line":16}},{"level":1,"name":"invoke_raw","kind":"inline","pc":"0x2d","source":{"path":".../examples/adder/src/lib.rs","line":12}},{"level":2,"name":"adder::__add::invoke_raw_extern","kind":"rust","pc":"0x2d","source":{"path":".../examples/adder/src/lib.rs","line":12}}],"instr":"i32.add","source":{"path":".../examples/adder/src/lib.rs","line":16,"column":9},"variables":[{"name":"arg_0","type":"Val","value":"17179869188"},{"name":"arg_1","type":"Val","value":"12884901892"}]} {"kind":"result","terminated":true} ``` @@ -91,6 +91,21 @@ Each `stop` carries the source location, the enclosing function, the call `--max-children`). The full `SourceStop` / `TraceVar` field reference is in [`trace-cli-internal.md`](./trace-cli-internal.md). +### The call stack: `frames` + +`frames` is the whole call stack at that stop, innermost first — the same frames the editor's Callstack view shows, derived by the same shared code, so a script and a debug session never disagree about who called whom. +Each frame states its `name`, its `pc`, where it stands (`source`), and which rung of the precision ladder placed it: + +| `kind` | meaning | +| --- | --- | +| `rust` | a wasm activation located by DWARF | +| `inline` | a Rust frame the optimizer inlined into the activation below it | +| `wasm` | an activation with no source-level identity (no DWARF at its pc) | +| `contract` | a host-level contract invocation — a boundary marker, not a code position | + +An outer frame stands at the CALL it is suspended in, not at its own first line, and a frame the user did not write (Rust toolchain, a crates.io dependency, or any sourceless frame in a session that has line info) carries `"subtle": true`, so a consumer can fold the noise away without losing it. +The example above is a build above opt-level 0, where `add` survives only as an inline frame inside the `#[contractimpl]` wrapper — the rules are specified in [`callstack.md`](./callstack.md). + ### Machine state: `globals` and `ledger` When the trace carries them, a `stop` also reports the machine and chain state at that point — the same state the editor's **Globals** and **Ledger** scopes show. `meta` announces both up front (`hasGlobals`, `hasLedger`) so a consumer can branch without probing every stop: diff --git a/src/debugAdapter/SorobanDebugSession.ts b/src/debugAdapter/SorobanDebugSession.ts index 89be95b..261e355 100644 --- a/src/debugAdapter/SorobanDebugSession.ts +++ b/src/debugAdapter/SorobanDebugSession.ts @@ -29,13 +29,14 @@ import { DebugProtocol } from '@vscode/debugprotocol'; import * as path from 'path'; import { TraceModel } from './TraceModel'; import { firstNonWhitespaceColumn } from './stops'; -import { StopModel, buildStopModel, pcAtIndex } from './stopModel'; +import { StopModel, buildStopModel } from './stopModel'; import { Granularity, ReplayCursor, resolveBreakpoints } from './replayCursor'; import { SourceMapper } from '../sourcemap/SourceMapper'; import { VariableResolver, NullVariableResolver } from '../sourcemap/VariableResolver'; import { Disassembly } from '../wasm/Disassembly'; import { ResolvedTrace, SessionBackend, SorobanLaunchArgs } from './types'; -import { renderInstr } from '../komet/mnemonics'; +import { CallFrame, buildCallStack } from './callStack'; +import { TraceRecord } from '../komet/trace'; import { disassemblyRows, formatAddress, parseAddress } from './disassemblyView'; import { ledgerNodes, ledgerSnapshot } from './ledgerView'; import { globalNodes, localNodes, stackNodes } from './wasmView'; @@ -43,10 +44,14 @@ import { makeRuntimeState } from './runtimeState'; import { DecodedValue, ChildVar } from '../dwarf/ValueDecoder'; const THREAD_ID = 1; -const FRAME_ID = 1; -/** Variable-reference handles for the fixed scopes we expose. */ -enum ScopeRef { +/** + * The kinds of scope a frame can offer. A `variablesReference` encodes the kind + * TOGETHER with the frame it belongs to (see `scopeRef`), because every scope is + * now per-frame: selecting an outer frame must show that frame's state, not the + * innermost one's (docs/callstack.md, C7). + */ +enum ScopeKind { Locals = 1, Stack = 2, SourceVars = 3, @@ -56,6 +61,28 @@ enum ScopeRef { Ledger = 5, } +/** How many scope kinds a frame's reference block reserves. */ +const SCOPES_PER_FRAME = 8; +/** Frame ids are `FRAME_ID_BASE + level`, so frame 0 is a valid (non-zero) id. */ +const FRAME_ID_BASE = 1; +/** Scope references live above every frame id, child handles above every scope. */ +const SCOPE_REF_BASE = 100_000; +const CHILD_HANDLE_BASE = 1_000_000; + +/** The `variablesReference` naming scope `kind` of the frame at `level`. */ +function scopeRef(level: number, kind: ScopeKind): number { + return SCOPE_REF_BASE + level * SCOPES_PER_FRAME + kind; +} + +/** Inverse of `scopeRef`, or null when the reference is not a scope. */ +function decodeScopeRef(reference: number): { level: number; kind: ScopeKind } | null { + if (reference < SCOPE_REF_BASE || reference >= CHILD_HANDLE_BASE) { + return null; + } + const offset = reference - SCOPE_REF_BASE; + return { level: Math.floor(offset / SCOPES_PER_FRAME), kind: offset % SCOPES_PER_FRAME }; +} + export class SorobanDebugSession extends DebugSession { /** * Either a concrete backend or a selector resolved on the first line of @@ -64,13 +91,18 @@ export class SorobanDebugSession extends DebugSession { * concrete backend. */ private backend: SessionBackend | ((args: SorobanLaunchArgs) => SessionBackend); + private resolved?: ResolvedTrace; private model?: TraceModel; private cursor?: ReplayCursor; private stops?: StopModel; private source?: SourceMapper; private disassembly?: Disassembly; - /** Per-record validated code offsets, parallel to the trace records. */ - private positions: (number | null)[] = []; + /** + * The call stack at the current cursor, built once per stop: `stackTrace` and + * every following `scopes`/`variables` request must agree on what frame N is. + * Cleared whenever the cursor moves (see `reportStop`). + */ + private frames?: CallFrame[]; /** Resolves when the client has finished configuring (e.g. breakpoints). */ private readonly configurationDone: Promise; @@ -86,11 +118,11 @@ export class SorobanDebugSession extends DebugSession { /** Source-level variable resolver (Null until a DWARF-bearing wasm loads). */ private variables: VariableResolver = new NullVariableResolver(); /** - * Handles for lazily-expanded variable children. High start avoids colliding - * with the fixed ScopeRef range; reset on every stop so refs are fresh per - * cursor position. + * Handles for lazily-expanded variable children. Starts above every frame id + * and per-frame scope reference; reset on every stop so refs are fresh per + * cursor position (DAP invalidates all references at a stop). */ - private readonly childHandles = new Handles<() => ChildVar[]>(1000); + private readonly childHandles = new Handles<() => ChildVar[]>(CHILD_HANDLE_BASE); /** * Set once the per-connection backend has been disposed, so teardown is @@ -149,11 +181,11 @@ export class SorobanDebugSession extends DebugSession { } try { const resolved: ResolvedTrace = await this.backend.resolve(args, (msg) => this.log(msg)); + this.resolved = resolved; this.model = resolved.model; this.source = resolved.source; this.variables = resolved.variables; this.disassembly = resolved.disassembly; - this.positions = resolved.positions; this.stops = buildStopModel(resolved, { justMyCode: args.justMyCode }); this.cursor = new ReplayCursor(this.model, this.stops); @@ -176,7 +208,7 @@ export class SorobanDebugSession extends DebugSession { this.sendResponse(response); this.cursor.toEntry(); - this.sendEvent(new StoppedEvent('entry', THREAD_ID)); + this.reportStop('entry'); } catch (e) { // sendErrorResponse surfaces only a one-line, non-copyable modal. Mirror // the full error (with stack) into the debug console first, so the details @@ -278,67 +310,85 @@ export class SorobanDebugSession extends DebugSession { // --- Frames, disassembly, scopes -------------------------------------- + /** + * The single VM thread. Its label carries the cursor's position in the + * recording — the one fact a time-travel session has and DAP's frame model + * does not, and which a client refreshes on every stop. + */ protected threadsRequest(response: DebugProtocol.ThreadsResponse): void { - response.body = { threads: [new Thread(THREAD_ID, 'soroban-vm')] }; + const position = + this.model && !this.model.isEmpty ? ` [${this.model.cursor}/${this.model.length - 1}]` : ''; + response.body = { threads: [new Thread(THREAD_ID, `soroban-vm${position}`)] }; this.sendResponse(response); } + /** + * The full call stack at the cursor (docs/callstack.md), innermost frame + * first, honoring the client's paging window. Every frame is selectable and + * carries its own source position and instruction pointer; a contract-boundary + * frame is reported as a `label` so clients render it as the marker it is. + */ protected stackTraceRequest( response: DebugProtocol.StackTraceResponse, - _args: DebugProtocol.StackTraceArguments, + args: DebugProtocol.StackTraceArguments, ): void { - if (!this.model || !this.source) { - response.body = { stackFrames: [], totalFrames: 0 }; - this.sendResponse(response); - return; - } - - const index = this.model.cursor; - const loc = this.source.locationForIndex(index); - const frameName = `${renderInstr(this.model.current.instr)} [${index}/${this.model.length - 1}]`; - - // Unmapped records get no Source at all (and line 0): the client keeps - // showing the frame name instead of opening a wrong file. S19: a mapped - // frame reports the line's first non-whitespace column, not the arbitrary - // DWARF sub-expression column; fall back to the DWARF column when the line - // text is unavailable or all-whitespace. - const frame: DebugProtocol.StackFrame = loc - ? new StackFrame( - FRAME_ID, - frameName, - new Source(path.basename(loc.path), loc.path), - loc.line, - firstNonWhitespaceColumn(this.source.sourceTextForIndex(index)) ?? loc.column ?? 0, - ) - : new StackFrame(FRAME_ID, frameName); - const reference = this.instructionPointerReference(); - if (reference !== undefined) { - frame.instructionPointerReference = reference; - } - response.body = { stackFrames: [frame], totalFrames: 1 }; + const frames = this.callFrames(); + const start = args.startFrame ?? 0; + const end = args.levels && args.levels > 0 ? start + args.levels : frames.length; + response.body = { + stackFrames: frames.slice(start, end).map((frame) => this.toDapFrame(frame)), + totalFrames: frames.length, + }; this.sendResponse(response); } - /** - * The current PC as a hex address, so the Disassembly View stays anchored on - * the last real instruction. Absent when no record at or before the cursor has - * a validated code offset (e.g. a trace opening with global initializers). - */ - private instructionPointerReference(): string | undefined { - const pc = this.currentPc(); - return pc === null ? undefined : formatAddress(pc); + /** The call stack at the cursor, built once per stop. */ + private callFrames(): CallFrame[] { + if (this.frames === undefined) { + this.frames = + this.resolved && this.stops && !this.resolved.model.isEmpty + ? buildCallStack( + { resolved: this.resolved, frames: this.stops.frames, ranges: this.stops.ranges }, + this.resolved.model.cursor, + ) + : []; + } + return this.frames; } /** - * The current record's validated code offset, or — when it has none — that of - * the NEAREST earlier record that does, so in-scope variable lookup stays - * anchored on the last real instruction. Null when no record qualifies. + * One `CallFrame` as DAP. S19: a mapped frame reports its line's first + * non-whitespace column, not the arbitrary DWARF sub-expression column; the + * DWARF column is the fallback when the line text is unavailable or + * all-whitespace. An unmapped frame gets no Source at all (and line 0), so the + * client keeps showing the frame name instead of opening a wrong file. */ - private currentPc(): number | null { - if (!this.model) { - return null; + private toDapFrame(frame: CallFrame): DebugProtocol.StackFrame { + const id = FRAME_ID_BASE + frame.level; + const loc = frame.source; + const dap: DebugProtocol.StackFrame = loc + ? new StackFrame( + id, + frame.name, + new Source(path.basename(loc.path), loc.path), + loc.line, + firstNonWhitespaceColumn(this.source?.sourceTextAt(loc.path, loc.line) ?? null) ?? + loc.column ?? + 0, + ) + : new StackFrame(id, frame.name); + if (frame.kind === 'contract') { + dap.presentationHint = 'label'; + } else if (frame.subtle) { + dap.presentationHint = 'subtle'; + if (dap.source) { + dap.source.presentationHint = 'deemphasize'; + } } - return pcAtIndex(this.positions, this.model.cursor); + if (frame.pc !== null) { + dap.instructionPointerReference = formatAddress(frame.pc); + } + return dap; } protected disassembleRequest( @@ -349,34 +399,56 @@ export class SorobanDebugSession extends DebugSession { this.sendResponse(response); } + /** + * The scopes of ONE frame (C7). Locals, Value Stack and Variables describe the + * selected frame — an outer frame reports the state at its own call + * instruction, not the innermost frame's. Globals and the Ledger are VM-wide, + * so every code frame offers them; a contract-boundary frame has no state of + * its own and offers nothing. + */ protected scopesRequest( response: DebugProtocol.ScopesResponse, - _args: DebugProtocol.ScopesArguments, + args: DebugProtocol.ScopesArguments, ): void { - // Fresh child-expansion refs per stop: last cursor's handles are stale. - this.childHandles.reset(); + const frame = this.frameById(args.frameId); + if (!frame || frame.kind === 'contract') { + response.body = { scopes: [] }; + this.sendResponse(response); + return; + } + const level = frame.level; const scopes: Scope[] = [ - new Scope('Locals', ScopeRef.Locals, false), - new Scope('Value Stack', ScopeRef.Stack, false), + new Scope('Locals', scopeRef(level, ScopeKind.Locals), false), + new Scope('Value Stack', scopeRef(level, ScopeKind.Stack), false), ]; // The source-level Variables scope is offered only when the resolver has // DWARF functions; without it the list is exactly [Locals, Value Stack]. if (this.variables.hasVariables()) { - scopes.unshift(new Scope('Variables', ScopeRef.SourceVars, false)); + scopes.unshift(new Scope('Variables', scopeRef(level, ScopeKind.SourceVars), false)); } // G4: globals appear only for a trace whose records carry them. - if (this.model?.current.globals !== undefined) { - scopes.push(new Scope('Globals', ScopeRef.Globals, false)); + if (this.recordFor(frame)?.globals !== undefined) { + scopes.push(new Scope('Globals', scopeRef(level, ScopeKind.Globals), false)); } // L14: the ledger appears only for a trace carrying ledger information — // never as an empty tree. if (this.model?.ledger.hasLedger()) { - scopes.push(new Scope('Ledger', ScopeRef.Ledger, false)); + scopes.push(new Scope('Ledger', scopeRef(level, ScopeKind.Ledger), false)); } response.body = { scopes }; this.sendResponse(response); } + /** The frame a client-supplied frame id refers to, or undefined. */ + private frameById(frameId: number): CallFrame | undefined { + return this.callFrames()[frameId - FRAME_ID_BASE]; + } + + /** The trace record whose runtime state a frame reports, if it has one. */ + private recordFor(frame: CallFrame): TraceRecord | undefined { + return frame.stateIndex === null ? undefined : this.model?.records[frame.stateIndex]; + } + protected variablesRequest( response: DebugProtocol.VariablesResponse, args: DebugProtocol.VariablesArguments, @@ -389,40 +461,52 @@ export class SorobanDebugSession extends DebugSession { } /** - * The nodes behind a variables reference: one of the fixed scopes, or a - * container previously handed out behind a child handle. Every scope — wasm - * locals, the ledger tree, decoded Rust values — arrives as `ChildVar`s, so - * they all reach DAP through `toDapVariable` and its lazy-children plumbing. + * The nodes behind a variables reference: a scope of some frame, or a container + * previously handed out behind a child handle. Every scope — wasm locals, the + * ledger tree, decoded Rust values — arrives as `ChildVar`s, so they all reach + * DAP through `toDapVariable` and its lazy-children plumbing. */ private nodesFor(reference: number): ChildVar[] { - const record = this.model?.current; - switch (reference) { - case ScopeRef.Locals: + const scope = decodeScopeRef(reference); + if (scope === null) { + return this.expandChildHandle(reference); + } + const frame = this.callFrames()[scope.level]; + if (!frame) { + return []; + } + const record = this.recordFor(frame); + switch (scope.kind) { + case ScopeKind.Locals: return record ? localNodes(record) : []; - case ScopeRef.Stack: + case ScopeKind.Stack: return record ? stackNodes(record) : []; - case ScopeRef.Globals: + case ScopeKind.Globals: return record ? globalNodes(record) : []; - case ScopeRef.SourceVars: - return this.sourceVarNodes(); - case ScopeRef.Ledger: + case ScopeKind.SourceVars: + return this.sourceVarNodes(frame); + case ScopeKind.Ledger: return this.ledgerScopeNodes(); default: - return this.expandChildHandle(reference); + return []; } } /** - * The in-scope DWARF variables at the current PC, each decoded against the - * folded runtime state at the cursor. + * A frame's own DWARF variables, decoded against that frame's runtime state: + * the register values the trace recorded where the frame stands (its own + * instruction, or the call it is suspended in), and linear memory as it is NOW + * — a callee may have written through a reference the caller still holds, and + * the caller's spilled locals live in that memory. */ - private sourceVarNodes(): ChildVar[] { - const pc = this.currentPc(); - if (!this.model || pc === null) { + private sourceVarNodes(frame: CallFrame): ChildVar[] { + const record = this.recordFor(frame); + const pc = frame.pc; + if (!this.model || !record || pc === null) { return []; } - const state = makeRuntimeState(this.model.current, this.model.memory, this.model.cursor); - return this.variables.variablesInScope(pc).map((v) => ({ + const state = makeRuntimeState(record, this.model.memory, this.model.cursor); + return frame.variables.map((v) => ({ name: v.name ?? '', value: this.variables.decodeVariable(v, state, pc), })); @@ -516,7 +600,7 @@ export class SorobanDebugSession extends DebugSession { // S8/S10: reverse step over — the previous stop point not in a deeper frame. if (this.cursor) { this.cursor.stepBackward(granularityOf(args.granularity), this.cursor.depth); - this.sendEvent(new StoppedEvent('step', THREAD_ID)); + this.reportStop('step'); } } @@ -536,9 +620,22 @@ export class SorobanDebugSession extends DebugSession { granularityOf(granularity), maxDepth(this.cursor.depth), ); - this.sendEvent( - outcome === 'terminated' ? new TerminatedEvent() : new StoppedEvent('step', THREAD_ID), - ); + if (outcome === 'terminated') { + this.sendEvent(new TerminatedEvent()); + } else { + this.reportStop('step'); + } + } + + /** + * Report a stop. The cursor has moved, so everything derived from it is stale: + * the call stack is dropped (rebuilt on the next `stackTrace`) and the child + * handles are reset, which DAP already treats as invalidated at a stop. + */ + private reportStop(reason: 'entry' | 'step' | 'breakpoint'): void { + this.frames = undefined; + this.childHandles.reset(); + this.sendEvent(new StoppedEvent(reason, THREAD_ID)); } /** Run to the next/previous breakpoint, or clamp to the trace's last/first stop. */ @@ -551,9 +648,7 @@ export class SorobanDebugSession extends DebugSession { direction === 'forward' ? this.cursor.runForward(breakpoints) : this.cursor.runBackward(breakpoints); - this.sendEvent( - new StoppedEvent(outcome === 'breakpoint' ? 'breakpoint' : 'step', THREAD_ID), - ); + this.reportStop(outcome === 'breakpoint' ? 'breakpoint' : 'step'); } // --- Teardown --------------------------------------------------------- diff --git a/src/debugAdapter/artifacts.ts b/src/debugAdapter/artifacts.ts index 4df873c..bd8803f 100644 --- a/src/debugAdapter/artifacts.ts +++ b/src/debugAdapter/artifacts.ts @@ -118,7 +118,12 @@ export function buildDebugArtifacts( const table = readLineTable(wasm, report); const source = table === null ? new NullSourceMapper() : new DwarfSourceMapper(model, table, positions); - return { source, variables: resolveVariables(wasm, report), disassembly, positions }; + return { + source, + variables: resolveVariables(wasm, table, report), + disassembly, + positions, + }; } /** @@ -163,16 +168,22 @@ function readLineTable(wasm: Uint8Array, report: ProgressReporter): DwarfLineTab } /** - * Resolve the source-level variable resolver from the wasm bytes, in its own - * INDEPENDENT try/catch so a variable-resolution failure never disables the - * line table (callers have already committed their SourceMapper by this point). - * Degrades to a NullVariableResolver — the wasm-level variables view. + * Resolve the source-level variable/frame resolver from the wasm bytes, in its + * own INDEPENDENT try/catch so a resolution failure never disables the line + * table (callers have already committed their SourceMapper by this point). + * Degrades to a NullVariableResolver — the wasm-level variables and frames view. */ -function resolveVariables(wasm: Uint8Array, report: ProgressReporter): VariableResolver { +function resolveVariables( + wasm: Uint8Array, + table: DwarfLineTable | null, + report: ProgressReporter, +): VariableResolver { try { const dwarf = DwarfDebugInfo.fromWasm(wasm); if (dwarf && dwarf.scopes.hasFunctions()) { - return new DwarfVariableResolver(dwarf); + // The line table is what turns an inlined call site's file INDEX into a + // path; passing it here is why inline frames can report a source location. + return new DwarfVariableResolver(dwarf, table ?? undefined); } } catch (err) { if (err instanceof DwarfParseError || err instanceof WasmFormatError) { diff --git a/src/debugAdapter/callStack.ts b/src/debugAdapter/callStack.ts new file mode 100644 index 0000000..1af7632 --- /dev/null +++ b/src/debugAdapter/callStack.ts @@ -0,0 +1,226 @@ +/** + * The call stack at a replay position (docs/callstack.md) — the shared headless + * derivation behind the IDE's Callstack view and the CLI's `frames` projection, + * so the two can never disagree about who called whom. + * + * The stack is assembled from three sources, in order of how much they can be + * trusted, and each frame states which one it came from: + * + * 1. **wasm activations** (`WasmFrame`, `stops.ts`) — the physical frame stack + * reconstructed from the trace itself. This is ground truth at every + * optimization level and is the same structure stepping derives depth from, + * so the Callstack view and step-over/step-out always agree. + * 2. **DWARF inlined subroutines** — the Rust frames an optimizing compiler + * erased from the activation stack. Inserted ABOVE the activation they were + * inlined into, they are why an optimized build still shows a Rust call + * chain instead of one wrapper function. + * 3. **contract-call boundaries** (`LedgerImage`) — the host-level invocations + * the trace records. They sit BELOW everything else as non-code labels, + * naming the contract and function the wasm frames are running for. + * + * The naming ladder (C4) is likewise ordered by precision: a DWARF name, else + * the module's demangled `name`-section symbol, else the wasm function index, + * else the raw code offset. A frame is therefore never nameless, and never named + * with something less precise than the build made available. + * + * Pure module (no `vscode` / DAP imports). + */ + +import { MappedLocation } from '../sourcemap/SourceMapper'; +import { ScopeVar } from '../dwarf/ScopeIndex'; +import { InlineFrame } from '../sourcemap/VariableResolver'; +import { FunctionRange, WasmFrame, isWorkspaceSource } from './stops'; +import { LedgerCallFrame } from './LedgerImage'; +import { ResolvedTrace } from './types'; +import { renderAddress } from '../soroban/scvalJson'; +import { pcAtIndex } from './stopModel'; + +/** Where a frame's identity came from — the rung of the ladder that named it. */ +export type FrameKind = + /** A wasm activation named and located by DWARF. */ + | 'rust' + /** A Rust frame that optimization inlined into the activation below it. */ + | 'inline' + /** A wasm activation with no source-level identity (no DWARF, or none at its pc). */ + | 'wasm' + /** A host-level contract invocation: a boundary marker, not a code position. */ + | 'contract'; + +/** One frame of the call stack at a replay position. */ +export interface CallFrame { + /** 0 = innermost (where the cursor is), increasing outward. */ + level: number; + /** Display name; never empty (C4). */ + name: string; + kind: FrameKind; + /** + * The record whose runtime state this frame's variables are read from: the + * cursor for the innermost activation, the frame's own call instruction for an + * outer one. Null for a contract frame, which has no wasm state of its own. + */ + stateIndex: number | null; + /** Code offset this frame is executing at, or null when unknown. */ + pc: number | null; + /** Where to open the editor for this frame, or null when unmapped. */ + source: MappedLocation | null; + /** + * True for a frame the user did not write — toolchain or dependency source + * (S21's workspace test), and any frame with no source at all in a session + * that HAS line info. Presented deemphasized rather than hidden (C5). + */ + subtle: boolean; + /** The DWARF variables this frame declares, in scope at its pc (C7). */ + variables: ScopeVar[]; +} + +/** Everything `buildCallStack` reads; a subset of `ResolvedTrace` plus the cursor. */ +export interface CallStackInput { + resolved: ResolvedTrace; + /** Per-record wasm frame stacks, from `computeFrames`. */ + frames: readonly (WasmFrame | null)[]; + /** The function ranges `WasmFrame.fn` indexes (sorted), from `computeFrames`. */ + ranges: readonly FunctionRange[]; +} + +/** + * The call stack at trace index `index`, innermost frame first. + * + * Never empty for a non-empty trace: with no activation, no DWARF and no + * contract boundary to go on, the result is the single wasm frame at the + * cursor's own address — the honest floor of the ladder. + */ +export function buildCallStack(input: CallStackInput, index: number): CallFrame[] { + const { resolved, frames, ranges } = input; + const hasLineInfo = resolved.source.hasLineInfo(); + const built: CallFrame[] = []; + + /** Push one frame, numbering it and deriving its deemphasis (C5). */ + const push = (frame: Omit): void => { + const subtle = + frame.kind !== 'contract' && + (frame.source === null ? hasLineInfo : !isWorkspaceSource(frame.source.path)); + built.push({ ...frame, level: built.length, subtle }); + }; + + /** An inlined call site put through the mapper's on-disk policy. */ + const callSiteLocation = (inline: InlineFrame): MappedLocation | null => { + const site = inline.callSite; + return site === undefined + ? null + : resolved.source.locationForFile(site.path, site.line, site.column); + }; + + /** + * Expand one wasm activation into frames: the DWARF frames inlined into it + * (innermost first) followed by the activation itself, positioned at record + * `at`. + */ + const pushActivation = (frame: WasmFrame | null, at: number): void => { + const pc = pcAtIndex(resolved.positions, at); + const range = frame && frame.fn >= 0 ? ranges[frame.fn] : undefined; + const inlines = pc === null ? [] : resolved.variables.inlineFramesAt(pc); + + // An inlined chain shifts locations by one: the innermost frame stands where + // the line table points, and every frame below it stands at the call site of + // the frame above (C2). `inlines` is outermost first, so walk it backwards. + let below: MappedLocation | null = resolved.source.locationForIndex(at); + for (let i = inlines.length - 1; i >= 0; i--) { + const inline = inlines[i]; + push({ + name: inline.name ?? '', + kind: 'inline', + stateIndex: at, + pc, + source: below, + variables: inline.variables, + }); + below = callSiteLocation(inline); + } + + const qualified = pc === null ? null : resolved.variables.qualifiedFunctionNameAt(pc); + push({ + name: activationName(qualified, range, pc, below), + // Source, not the name, decides the kind: rustc leaves some method DIEs + // anonymous, and such a frame is still a located Rust frame — it just + // borrows its label from the `name` section. + kind: below === null ? 'wasm' : 'rust', + stateIndex: at, + pc, + source: below, + variables: pc === null ? [] : resolved.variables.variablesInScope(pc), + }); + }; + + // The activation stack, innermost first. The position walks outward with it: an + // outer activation stands at the call instruction that entered the frame below + // it, which is also where its own locals were last observed. Only the + // outermost frame has no call site, so the walk cannot end early. + let activation = frames[index] ?? null; + let at: number | null = index; + while (activation !== null && at !== null) { + pushActivation(activation, at); + at = activation.callSite; + activation = activation.caller; + } + if (built.length === 0) { + // No reconstructed activation at all: still report where the cursor is. + pushActivation(null, index); + } + + // Contract boundaries below the wasm frames, innermost call first. + const ledger = resolved.model.ledger; + if (ledger.hasLedger()) { + for (const call of ledger.callStackAt(index)) { + push({ + name: contractFrameName(call), + kind: 'contract', + stateIndex: null, + pc: null, + source: null, + variables: [], + }); + } + } + return built; +} + +/** + * A wasm activation's label, down the naming ladder (C4). A frame with no source + * location carries its code offset — for a wasm-level session that offset is the + * only position the user has, and inside a named function it is stated relative + * to the function's start, the way a disassembler does. + */ +function activationName( + qualified: string | null, + range: FunctionRange | undefined, + pc: number | null, + source: MappedLocation | null, +): string { + const indexed = range?.index === undefined ? null : `func[${range.index}]`; + const name = qualified ?? range?.name ?? indexed; + if (name === null) { + return pc === null ? '' : `wasm@${hex(pc)}`; + } + if (source !== null || pc === null || range === undefined) { + return name; + } + return pc === range.start ? name : `${name}+${hex(pc - range.start)}`; +} + +/** + * A contract invocation as a boundary label: `increment() @ CA5XKA…7QFM`. The + * `C…` strkey is elided in the middle — a frame label has to stay readable in a + * narrow panel, and the Ledger scope is where the full address is shown. + */ +function contractFrameName(call: LedgerCallFrame): string { + return `${call.function}() @ ${shortAddress(renderAddress(call.to))}`; +} + +/** Head and tail of an address long enough to need eliding. */ +function shortAddress(address: string): string { + return address.length > 16 ? `${address.slice(0, 6)}…${address.slice(-4)}` : address; +} + +function hex(value: number): string { + return `0x${value.toString(16)}`; +} diff --git a/src/debugAdapter/stopModel.ts b/src/debugAdapter/stopModel.ts index eb77625..f867f87 100644 --- a/src/debugAdapter/stopModel.ts +++ b/src/debugAdapter/stopModel.ts @@ -15,8 +15,10 @@ */ import { + FunctionRange, + WasmFrame, classifyLineRole, - computeDepths, + computeFrames, computeRunStarts, myCodeStops, statementStops, @@ -28,7 +30,15 @@ export interface StopModel { validatedPosToIndices: Map; /** Visible (validated-position) record indices, ascending. */ visibleIndices: number[]; - /** Call depth per record (parallel to records), via computeDepths. */ + /** + * Innermost wasm frame per record, from `computeFrames` — the call stack the + * Callstack view is built from (docs/callstack.md, C1). Depth-only consumers + * read `depths`, which is this projected. + */ + frames: (WasmFrame | null)[]; + /** The function ranges `WasmFrame.fn` indexes, sorted by start. */ + ranges: readonly FunctionRange[]; + /** Call depth per record (parallel to records). */ depths: number[]; /** Raw line-run starts, pre-S17/S18 (for breakpoint narrowing). */ rawRunStarts: number[]; @@ -69,7 +79,8 @@ export function buildStopModel( } }); - const depths = computeDepths(model.records, positions, disassembly.functionRanges); + const { frames, ranges } = computeFrames(model.records, positions, disassembly.functionRanges); + const depths = frames.map((frame) => frame?.depth ?? 0); const rawRunStarts = computeRunStarts(positions, depths, (i) => source.lineKeyForIndex(i)); const stmtStops = statementStops(rawRunStarts, depths, (i) => classifyLineRole(source.sourceTextForIndex(i)), @@ -88,6 +99,8 @@ export function buildStopModel( return { validatedPosToIndices, visibleIndices, + frames, + ranges, depths, rawRunStarts, runStarts, diff --git a/src/debugAdapter/stops.ts b/src/debugAdapter/stops.ts index f85e890..eb8cc8f 100644 --- a/src/debugAdapter/stops.ts +++ b/src/debugAdapter/stops.ts @@ -17,10 +17,19 @@ import * as path from 'path'; import { TraceRecord, opcode } from '../komet/trace'; -/** A function body in code-offset space: [start, end). */ +/** + * A function body in code-offset space: [start, end). Call-depth reconstruction + * reads only the bounds; `index` and `name` are what a wasm-level call stack + * frame is labelled with (docs/callstack.md, C4) and are absent for a + * trace-derived disassembly, which knows no function structure at all. + */ export interface FunctionRange { start: number; end: number; + /** Wasm function index (imports included in the numbering). */ + index?: number; + /** Demangled name from the module's `name` section, when it has one. */ + name?: string; } /** Opcodes that descend into a callee (may increase call depth). */ @@ -29,62 +38,108 @@ const CALL_OPCODES = new Set(['call', 'call_indirect', 'return_call', 'return_ca const RETURN_OPCODES = new Set(['return']); /** - * Fallback call-depth reconstruction from call/return opcodes alone (used when - * no function-body ranges exist, i.e. wasm-less replay). Depth is recorded at + * One activation record of the reconstructed wasm frame stack — the physical + * call stack the debugger shows (docs/callstack.md, C1) and the same structure + * the stepping depth is read off (`computeDepths`), so the Callstack view and + * step-over/step-out can never disagree about what a frame is. + * + * Frames are IMMUTABLE and SHARED: the walk hands the same object to every + * record executing in that activation, and `caller` links it to the frame it + * returns into, so the whole trace's stacks cost one object per call. + */ +export interface WasmFrame { + /** Index into the sorted function ranges; -1 when the pc is in no known body. */ + fn: number; + /** Call depth, 0 = outermost. Equals `computeDepths()[i]` for this frame's records. */ + depth: number; + /** + * Record index of the `call` that created this frame — i.e. the CALLER's + * position while this frame runs, which is what an outer stack frame reports. + * Null for the outermost frame and wherever the walk lost the call site. + */ + callSite: number | null; + /** The frame this one returns into, or null at the outermost. */ + caller: WasmFrame | null; +} + +/** The per-record frame stacks of a trace, plus the ranges the walk indexed. */ +export interface FrameStacks { + /** + * Innermost frame per record (parallel to `records`); null only for records + * ahead of the first frame the walk could establish. + */ + frames: (WasmFrame | null)[]; + /** The function ranges `WasmFrame.fn` indexes, sorted by start; empty in the opcode fallback. */ + ranges: readonly FunctionRange[]; +} + +/** + * Fallback frame reconstruction from call/return opcodes alone (used when no + * function-body ranges exist, i.e. wasm-less replay). Depth is recorded at * instruction entry, so a `return` belongs to the frame it leaves. Implicit - * returns are invisible to this walk — see computeDepths. + * returns are invisible to this walk — see computeFrames. Frames carry no + * function identity here (`fn: -1`): without ranges there is nothing to name. */ -export function opcodeDepths(records: readonly TraceRecord[]): number[] { - const depths = new Array(records.length); - let depth = 0; +function opcodeFrames(records: readonly TraceRecord[]): (WasmFrame | null)[] { + const frames = new Array(records.length); + let frame: WasmFrame = { fn: -1, depth: 0, callSite: null, caller: null }; for (let i = 0; i < records.length; i++) { - depths[i] = depth; + frames[i] = frame; const op = opcode(records[i]); if (CALL_OPCODES.has(op)) { - depth++; - } else if (RETURN_OPCODES.has(op) && depth > 0) { - depth--; + frame = { fn: -1, depth: frame.depth + 1, callSite: i, caller: frame }; + } else if (RETURN_OPCODES.has(op) && frame.caller !== null) { + frame = frame.caller; } } - return depths; + return frames; +} + +/** + * Fallback call-depth reconstruction from call/return opcodes alone; see + * `opcodeFrames`, of which this is the depth projection. + */ +export function opcodeDepths(records: readonly TraceRecord[]): number[] { + return opcodeFrames(records).map((frame) => frame?.depth ?? 0); } /** - * Call depth per trace record (spec Model/depth). + * The wasm frame stack per trace record (spec Model/depth, docs/callstack.md C1). * - * With function-body ranges, depth follows a frame stack over the VISIBLE - * records (validated `positions[i] !== null`): moving into a different + * With function-body ranges, the stack follows the function membership of the + * VISIBLE records (validated `positions[i] !== null`): moving into a different * function's body right after a call-class record pushes a frame; any other * transition pops back to that function's frame (matching implicit returns, * which produce no record) or, when the function is not on the stack at all, - * replaces the current frame. Invisible records carry the depth of the + * replaces the current frame. Invisible records carry the frame of the * surrounding visible context. Without ranges (or with an empty list) the * opcode-based reconstruction is the fallback. */ -export function computeDepths( +export function computeFrames( records: readonly TraceRecord[], positions: readonly (number | null)[], functionRanges?: readonly FunctionRange[], -): number[] { +): FrameStacks { if (!functionRanges || functionRanges.length === 0) { - return opcodeDepths(records); + return { frames: opcodeFrames(records), ranges: [] }; } const ranges = [...functionRanges].sort((a, b) => a.start - b.start); - const depths = new Array(records.length); - /** Frame stack of function identities (range indices; -1 = outside all bodies). */ - const stack: number[] = []; + const frames = new Array(records.length); + /** Frame stack, outermost first; the last entry is the executing frame. */ + const stack: WasmFrame[] = []; let prevVisible = -1; for (let i = 0; i < records.length; i++) { const pos = positions[i] ?? null; if (pos === null) { - depths[i] = Math.max(0, stack.length - 1); + frames[i] = stack[stack.length - 1] ?? null; continue; } const fn = functionIndexAt(ranges, pos); - if (stack.length === 0) { - stack.push(fn); - } else if (fn !== stack[stack.length - 1]) { + const top = stack[stack.length - 1]; + if (top === undefined) { + stack.push({ fn, depth: 0, callSite: null, caller: null }); + } else if (fn !== top.fn) { // A genuine call ENTRY lands on the callee body's first instruction right // after a call-class record; a return lands just after the caller's call // (never on a body's first instruction), so a call record alone does not @@ -97,20 +152,46 @@ export function computeDepths( prevVisible >= 0 && CALL_OPCODES.has(opcode(records[prevVisible])); if (isEntry) { - stack.push(fn); + stack.push({ fn, depth: stack.length, callSite: prevVisible, caller: top }); } else { - const frame = stack.lastIndexOf(fn); + const frame = lastIndexOfFn(stack, fn); if (frame >= 0) { stack.length = frame + 1; } else { - stack[stack.length - 1] = fn; + // Execution surfaced in a function that is not on the stack at all: + // the identity changes but the activation (and its depth) does not. + stack[stack.length - 1] = { ...top, fn }; } } } - depths[i] = stack.length - 1; + frames[i] = stack[stack.length - 1]; prevVisible = i; } - return depths; + return { frames, ranges }; +} + +/** Topmost stack position holding function identity `fn`, or -1. */ +function lastIndexOfFn(stack: readonly WasmFrame[], fn: number): number { + for (let i = stack.length - 1; i >= 0; i--) { + if (stack[i].fn === fn) { + return i; + } + } + return -1; +} + +/** + * Call depth per trace record (spec Model/depth) — the depth projection of + * `computeFrames`, which is where the reconstruction itself is documented. + */ +export function computeDepths( + records: readonly TraceRecord[], + positions: readonly (number | null)[], + functionRanges?: readonly FunctionRange[], +): number[] { + return computeFrames(records, positions, functionRanges).frames.map( + (frame) => frame?.depth ?? 0, + ); } /** diff --git a/src/dwarf/LineTable.ts b/src/dwarf/LineTable.ts index 3687cd0..8c661c9 100644 --- a/src/dwarf/LineTable.ts +++ b/src/dwarf/LineTable.ts @@ -34,9 +34,26 @@ export interface LineEntry { export class DwarfLineTable { /** All entries from all units, sorted by address. */ readonly entries: readonly LineEntry[]; + /** + * Per line program (keyed by its `.debug_line` offset, i.e. a CU's + * DW_AT_stmt_list) the unit's resolved file table, indexable by file index. + * `.debug_info` states an inlined call site as such an index (docs/callstack.md, + * C2), and this is the only place the two tables can be joined. + */ + private readonly filesByProgram: Map; - private constructor(entries: LineEntry[]) { + private constructor(entries: LineEntry[], filesByProgram: Map) { this.entries = entries; + this.filesByProgram = filesByProgram; + } + + /** + * The path of `fileIndex` in the line program at `stmtListOffset` — the + * resolution DWARF's `DW_AT_call_file` needs. Undefined when either index is + * unknown to the table. + */ + filePath(stmtListOffset: number, fileIndex: number): string | undefined { + return this.filesByProgram.get(stmtListOffset)?.[fileIndex]; } /** @@ -59,21 +76,24 @@ export class DwarfLineTable { const lineStr = parsed.customSection('.debug_line_str'); const entries: LineEntry[] = []; + const filesByProgram = new Map(); const cus = scanCompilationUnits({ info, abbrev, str, lineStr }); - const seenOffsets = new Set(); for (const cu of cus) { - if (cu.stmtListOffset === undefined || seenOffsets.has(cu.stmtListOffset)) { + if (cu.stmtListOffset === undefined || filesByProgram.has(cu.stmtListOffset)) { continue; } - seenOffsets.add(cu.stmtListOffset); const unit = parseLineProgram(debugLine, cu.stmtListOffset, { str, lineStr }); + filesByProgram.set( + cu.stmtListOffset, + unit.files.map((_, index) => resolveFilePath(unit, cu, index)), + ); collectEntries(unit, cu, entries); } // Sort by address; at equal addresses end_sequence rows come first so a // new sequence starting exactly where another ended wins the lookup. entries.sort((a, b) => a.address - b.address || Number(b.endSequence) - Number(a.endSequence)); - return new DwarfLineTable(entries); + return new DwarfLineTable(entries, filesByProgram); } /** diff --git a/src/dwarf/ScopeIndex.ts b/src/dwarf/ScopeIndex.ts index 59e5412..b5297bd 100644 --- a/src/dwarf/ScopeIndex.ts +++ b/src/dwarf/ScopeIndex.ts @@ -16,24 +16,43 @@ * PC, and inner declarations are appended after outer ones so callers may treat * later entries as shadowing. * + * `inlineScopesAt` answers the other half of a call stack (docs/callstack.md, + * C2): the chain of `DW_TAG_inlined_subroutine` instances covering the PC, which + * is how the Rust call chain survives inlining. Optimization inlines whole + * functions into one wasm body — `sum_triples` disappears into the + * `#[contractimpl]` wrapper's — so without this chain a frame would be labelled + * with the *host* function while the cursor sits on the *inlined* function's + * source line. Each instance carries its own declarations and the call site it + * was expanded at, which is what the frame BELOW it reports as its position. + * * Pure module (no `vscode` and no `src/wasm` imports). The optional * `nameFallback` lets the wiring layer supply a disassembly-derived name for an * anonymous subprogram without coupling this module to it. */ import { Cursor } from './cursor'; -import { DebugInfo, Die, dieName, dieUint, dieRef } from './die'; +import { DebugInfo, Die, dieName, dieUint, dieRef, dieString } from './die'; import { DW_TAG_subprogram, DW_TAG_formal_parameter, DW_TAG_variable, DW_TAG_lexical_block, + DW_TAG_inlined_subroutine, + DW_TAG_namespace, + DW_TAG_structure_type, DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_location, DW_AT_type, DW_AT_frame_base, + DW_AT_stmt_list, + DW_AT_call_file, + DW_AT_call_line, + DW_AT_call_column, + DW_AT_abstract_origin, + DW_AT_specification, + DW_AT_linkage_name, } from './constants'; /** One in-scope variable or parameter, with the raw material for value decoding. */ @@ -59,10 +78,37 @@ export interface ScopeVar { export interface FunctionScope { die: Die; name?: string; + /** + * `name` prefixed with the DIE's enclosing namespaces and types, e.g. + * `control::__while_call::invoke_raw` — what a stack frame is labelled with. + * Absent exactly when `name` is (rustc leaves some method DIEs anonymous). + */ + qualifiedName?: string; /** From DW_AT_frame_base, when it is an exprloc. */ frameBaseExpr?: Uint8Array; } +/** + * One `DW_TAG_inlined_subroutine` instance covering a PC: a Rust-level frame + * that has no wasm activation record of its own. + */ +export interface InlineScope { + /** Name of the inlined function, resolved through abstract origin / specification. */ + name?: string; + /** + * Where this inlined call was WRITTEN — a file index into the owning CU's + * line program, plus line/column. It is the position of the frame directly + * BELOW this one (its caller), not of this frame itself. + */ + callFileIndex?: number; + callLine?: number; + callColumn?: number; + /** The owning CU's DW_AT_stmt_list — which line program `callFileIndex` indexes. */ + stmtListOffset?: number; + /** The parameters and variables this instance declares, in scope at the PC. */ + variables: ScopeVar[]; +} + /** A recorded subprogram: its public scope plus the internal range material. */ interface RecordedFn extends FunctionScope { /** Contiguous `[low, low + high)` range, when the subprogram has one. */ @@ -71,6 +117,21 @@ interface RecordedFn extends FunctionScope { rangesOffset?: number; /** The CU's DW_AT_low_pc — the rangelist base default. */ cuLowPc: number; + /** The CU's DW_AT_stmt_list, for resolving inlined call-site file indices. */ + stmtListOffset?: number; +} + +/** LLVM writes this address for code the linker dropped; it is never a real PC. */ +const TOMBSTONE = 0xffffffff; +/** Reference hops `resolvedName` follows before giving up. */ +const MAX_NAME_HOPS = 4; + +/** What the indexing walk carries down one compilation unit's DIE tree. */ +interface UnitContext { + cuLowPc: number; + stmtListOffset?: number; + /** Enclosing namespace and type names, outermost first. */ + scope: string[]; } /** The DIE's `at` attribute bytes when it is an exprloc/block, else undefined. */ @@ -112,34 +173,46 @@ export class ScopeIndex { private readonly ranged: RecordedFn[] = []; constructor( - info: DebugInfo, + private readonly info: DebugInfo, private readonly debugRanges?: Uint8Array, private readonly nameFallback?: (pc: number) => string | undefined, ) { for (const unit of info.units) { const cuLowPc = dieUint(unit.die, DW_AT_low_pc) ?? 0; - this.indexTree(unit.die, cuLowPc); + this.indexTree(unit.die, { cuLowPc, stmtListOffset: dieUint(unit.die, DW_AT_stmt_list), scope: [] }); } this.contiguous.sort((a, b) => a.lowHigh![0] - b.lowHigh![0]); } - /** Walks a DIE subtree, recording every subprogram that carries a code range. */ - private indexTree(die: Die, cuLowPc: number): void { + /** + * Walks a DIE subtree, recording every subprogram that carries a code range. + * `unit.scope` accumulates the enclosing namespace and type names so a + * recorded function can report a qualified name. + */ + private indexTree(die: Die, unit: UnitContext): void { if (die.tag === DW_TAG_subprogram) { - this.record(die, cuLowPc); + this.record(die, unit); } + const nests = die.tag === DW_TAG_namespace || die.tag === DW_TAG_structure_type; + const inner: UnitContext = + nests && dieName(die) !== undefined ? { ...unit, scope: [...unit.scope, dieName(die)!] } : unit; for (const child of die.children) { - this.indexTree(child, cuLowPc); + this.indexTree(child, inner); } } - private record(die: Die, cuLowPc: number): void { + private record(die: Die, unit: UnitContext): void { + const name = dieName(die); const rec: RecordedFn = { die, - name: dieName(die), + name, frameBaseExpr: exprBytes(die, DW_AT_frame_base), - cuLowPc, + cuLowPc: unit.cuLowPc, + stmtListOffset: unit.stmtListOffset, }; + if (name !== undefined) { + rec.qualifiedName = [...unit.scope, name].join('::'); + } const low = dieUint(die, DW_AT_low_pc); const high = dieUint(die, DW_AT_high_pc); if (low !== undefined && high !== undefined) { @@ -202,6 +275,116 @@ export class ScopeIndex { return this.nameFallback?.(pc) ?? null; } + /** + * The inlined subroutines covering `pc`, OUTERMOST first — the Rust frames + * between the enclosing wasm function and the PC (docs/callstack.md, C2). + * Empty when the PC is in no recorded function, or when nothing was inlined + * there. An instance whose range this parser cannot read (a DWARF v5 + * `.debug_rnglists` list, or a `.debug_ranges` section that is absent) is + * skipped rather than guessed at: a missing frame degrades the view, an + * invented one misreports the program. + */ + inlineScopesAt(pc: number): InlineScope[] { + const fn = this.recordAt(pc); + if (!fn) { + return []; + } + const out: InlineScope[] = []; + this.collectInlines(fn.die, pc, fn, out); + return out; + } + + /** + * Collects the inlined-subroutine instances under `scope` that cover `pc`, + * outermost first. A nested instance is a DEEPER frame, so it is appended + * after its parent; lexical blocks are transparent (they are not frames). + */ + private collectInlines(scope: Die, pc: number, fn: RecordedFn, out: InlineScope[]): void { + for (const child of scope.children) { + if (child.tag === DW_TAG_inlined_subroutine) { + if (!this.rangeCovers(child, pc, fn.cuLowPc)) { + continue; + } + out.push(this.toInlineScope(child, pc, fn)); + this.collectInlines(child, pc, fn, out); + } else if (child.tag === DW_TAG_lexical_block && this.blockCovers(child, pc, fn.cuLowPc)) { + this.collectInlines(child, pc, fn, out); + } + } + } + + /** One inlined instance as a frame: its name, its call site, its own declarations. */ + private toInlineScope(die: Die, pc: number, fn: RecordedFn): InlineScope { + const variables: ScopeVar[] = []; + this.collect(die, pc, fn.frameBaseExpr, fn.cuLowPc, variables); + const scope: InlineScope = { variables }; + const name = this.resolvedName(die); + if (name !== undefined) { + scope.name = name; + } + const callFileIndex = dieUint(die, DW_AT_call_file); + if (callFileIndex !== undefined) { + scope.callFileIndex = callFileIndex; + } + const callLine = dieUint(die, DW_AT_call_line); + if (callLine !== undefined) { + scope.callLine = callLine; + } + const callColumn = dieUint(die, DW_AT_call_column); + if (callColumn !== undefined && callColumn > 0) { + scope.callColumn = callColumn; + } + if (fn.stmtListOffset !== undefined) { + scope.stmtListOffset = fn.stmtListOffset; + } + return scope; + } + + /** + * A DIE's own name, or the name of what it is an instance/declaration of: + * `DW_AT_abstract_origin` (the out-of-line abstract subprogram an inlined + * instance copies) and `DW_AT_specification` (the declaration a definition + * completes) are followed in turn, since rustc puts the name on either. The + * mangled `DW_AT_linkage_name` is the last resort. Bounded so a cyclic or + * pathological reference chain cannot spin. + */ + private resolvedName(die: Die, hops = 0): string | undefined { + const name = dieName(die); + if (name !== undefined) { + return name; + } + if (hops < MAX_NAME_HOPS) { + for (const at of [DW_AT_abstract_origin, DW_AT_specification]) { + const ref = dieRef(die, at); + const target = ref === undefined ? undefined : this.info.dieByOffset.get(ref); + const resolved = target && this.resolvedName(target, hops + 1); + if (resolved !== undefined) { + return resolved; + } + } + } + return dieString(die, DW_AT_linkage_name); + } + + /** + * Whether the DIE's OWN code range covers `pc`. Unlike `blockCovers`, a DIE + * with no readable range covers nothing: an inlined instance must be placed + * by its range or not at all. A `low_pc` of 0xffffffff is LLVM's tombstone for + * code the linker dropped, never a real address. + */ + private rangeCovers(die: Die, pc: number, cuLowPc: number): boolean { + const low = dieUint(die, DW_AT_low_pc); + const high = dieUint(die, DW_AT_high_pc); + if (low !== undefined && high !== undefined) { + return low !== TOMBSTONE && pc >= low && pc < low + high; + } + const rangesOffset = dieUint(die, DW_AT_ranges); + if (rangesOffset !== undefined && this.debugRanges) { + return rangesCover(this.debugRanges, rangesOffset, pc, cuLowPc); + } + return false; + } + /** The parameters and variables in scope at `pc` (empty if no enclosing function). */ variablesInScope(pc: number): ScopeVar[] { const fn = this.recordAt(pc); diff --git a/src/dwarf/constants.ts b/src/dwarf/constants.ts index 253d290..434dafe 100644 --- a/src/dwarf/constants.ts +++ b/src/dwarf/constants.ts @@ -102,6 +102,8 @@ export const DW_TAG_variable = 0x34; export const DW_TAG_volatile_type = 0x35; export const DW_TAG_subprogram = 0x2e; export const DW_TAG_variant = 0x59; +export const DW_TAG_inlined_subroutine = 0x1d; +export const DW_TAG_namespace = 0x39; // Attributes (DW_AT_*) — variables, types, scopes, locations. export const DW_AT_location = 0x02; @@ -121,6 +123,14 @@ export const DW_AT_frame_base = 0x40; export const DW_AT_type = 0x49; export const DW_AT_ranges = 0x55; export const DW_AT_data_bit_offset = 0x6b; +// Inlined-subroutine attributes: where the inlined call was written, and which +// abstract (or declared) subprogram it is an instance of. +export const DW_AT_call_column = 0x57; +export const DW_AT_call_file = 0x58; +export const DW_AT_call_line = 0x59; +export const DW_AT_abstract_origin = 0x31; +export const DW_AT_specification = 0x47; +export const DW_AT_linkage_name = 0x6e; // Base-type encodings (DW_ATE_*). export const DW_ATE_address = 0x01; diff --git a/src/dwarf/die.ts b/src/dwarf/die.ts index e7715bb..b56be70 100644 --- a/src/dwarf/die.ts +++ b/src/dwarf/die.ts @@ -157,3 +157,9 @@ export function dieRef(die: Die, at: number): number | undefined { const value = die.attrs.get(at); return value && value.kind === 'ref' ? value.value : undefined; } + +/** The DIE's `at` attribute as a string, when present as one. */ +export function dieString(die: Die, at: number): string | undefined { + const value = die.attrs.get(at); + return value && value.kind === 'str' ? value.value : undefined; +} diff --git a/src/sourcemap/DwarfSourceMapper.ts b/src/sourcemap/DwarfSourceMapper.ts index 82208ca..c94c66a 100644 --- a/src/sourcemap/DwarfSourceMapper.ts +++ b/src/sourcemap/DwarfSourceMapper.ts @@ -91,6 +91,21 @@ export class DwarfSourceMapper implements SourceMapper { return this.mapEntry(this.lineTable.lookup(codeOffset)); } + locationForFile(filePath: string, line: number, column?: number): MappedLocation | null { + if (line <= 0) { + return null; // DWARF line 0 is compiler-generated code with no source line. + } + const normalized = path.normalize(filePath); + if (!this.cachedExists(normalized)) { + return null; + } + const loc: MappedLocation = { path: normalized, line }; + if (column !== undefined && column > 0) { + loc.column = column; + } + return loc; + } + resolveBreakpoint(requestedPath: string, line: number): ResolvedBreakpoint | null { const file = this.executedByFile.get(path.normalize(requestedPath)); if (!file) { @@ -118,14 +133,12 @@ export class DwarfSourceMapper implements SourceMapper { sourceTextForIndex(index: number): string | null { const loc = this.locations[index] ?? null; - if (loc === null) { - return null; - } - const lines = this.cachedLines(loc.path); - if (lines === null) { - return null; - } - return lines[loc.line - 1] ?? null; + return loc === null ? null : this.sourceTextAt(loc.path, loc.line); + } + + sourceTextAt(filePath: string, line: number): string | null { + const lines = this.cachedLines(path.normalize(filePath)); + return lines === null ? null : lines[line - 1] ?? null; } /** Read and split a source file once per normalized path; null on failure. */ diff --git a/src/sourcemap/NullSourceMapper.ts b/src/sourcemap/NullSourceMapper.ts index 875c8ba..10eb783 100644 --- a/src/sourcemap/NullSourceMapper.ts +++ b/src/sourcemap/NullSourceMapper.ts @@ -22,6 +22,10 @@ export class NullSourceMapper implements SourceMapper { return null; } + locationForFile(_path: string, _line: number, _column?: number): MappedLocation | null { + return null; + } + resolveBreakpoint(_path: string, _line: number): ResolvedBreakpoint | null { return null; } @@ -37,4 +41,8 @@ export class NullSourceMapper implements SourceMapper { sourceTextForIndex(_index: number): string | null { return null; } + + sourceTextAt(_path: string, _line: number): string | null { + return null; + } } diff --git a/src/sourcemap/SourceMapper.ts b/src/sourcemap/SourceMapper.ts index e20e7cc..82d96e6 100644 --- a/src/sourcemap/SourceMapper.ts +++ b/src/sourcemap/SourceMapper.ts @@ -43,6 +43,12 @@ export interface SourceMapper { locationForIndex(index: number): MappedLocation | null; /** Rust location for a static code offset (disassembly rows), or null. */ locationForAddress(codeOffset: number): MappedLocation | null; + /** + * A location stated OUTSIDE the line table — a DWARF inlined call site — put + * through the same usability policy as a mapped record: normalized, and null + * when the file is not on disk (docs/callstack.md, C2). + */ + locationForFile(path: string, line: number, column?: number): MappedLocation | null; /** Resolve a breakpoint request to an executed line, or null when none. */ resolveBreakpoint(path: string, line: number): ResolvedBreakpoint | null; /** Distinct executed lines in `path` within [fromLine, toLine], ascending. */ @@ -51,4 +57,6 @@ export interface SourceMapper { lineKeyForIndex(index: number): string | null; /** Raw source text of the line the record at `index` maps to, or null. */ sourceTextForIndex(index: number): string | null; + /** Raw source text of an explicit file/line (any frame's position), or null. */ + sourceTextAt(path: string, line: number): string | null; } diff --git a/src/sourcemap/VariableResolver.ts b/src/sourcemap/VariableResolver.ts index 6155e14..19b0fa0 100644 --- a/src/sourcemap/VariableResolver.ts +++ b/src/sourcemap/VariableResolver.ts @@ -1,23 +1,54 @@ /** - * Capability interface for resolving in-scope variables at a PC and decoding - * their runtime values, mirroring the `SourceMapper`/`NullSourceMapper` split. - * `NullVariableResolver` is the degraded no-DWARF path (every query is empty); - * `DwarfVariableResolver` drives the real pipeline: `ScopeIndex` locates the - * enclosing function and its variables, `selectLocation`/`evalLocation` resolve - * where each value lives, and `decodeValue` renders it against the `TypeRegistry`. + * Capability interface for the source-level view of a PC: which function it is + * in, which Rust frames were inlined into it, which variables are in scope, and + * what their runtime values are. It mirrors the `SourceMapper`/`NullSourceMapper` + * split — `NullVariableResolver` is the degraded no-DWARF path (every query is + * empty), `DwarfVariableResolver` drives the real pipeline: `ScopeIndex` locates + * the enclosing function, its inlined instances and their variables, + * `selectLocation`/`evalLocation` resolve where each value lives, and + * `decodeValue` renders it against the `TypeRegistry`. + * + * Frames live here rather than in a separate resolver because they are the same + * DWARF lookup: an inlined frame IS a scope, carrying its own name, call site and + * declarations (docs/callstack.md, C2). What this layer adds over the raw + * `ScopeIndex` is resolution of a call site's line-program FILE INDEX into a + * path, which needs the line table alongside `.debug_info`. * * Pure module (no `vscode` imports, no external deps). */ -import { ScopeVar } from '../dwarf/ScopeIndex'; +import { InlineScope, ScopeVar } from '../dwarf/ScopeIndex'; import { RuntimeState, evalLocation } from '../dwarf/locexpr'; import { DecodedValue, decodeValue } from '../dwarf/ValueDecoder'; import { selectLocation } from '../dwarf/debugLoc'; import { DwarfDebugInfo } from '../dwarf/DebugInfo'; +import { DwarfLineTable } from '../dwarf/LineTable'; + +/** One Rust frame that was inlined into the function containing the PC. */ +export interface InlineFrame { + /** The inlined function's name, or undefined when DWARF names it nowhere. */ + name?: string; + /** + * Where the inlined call was written — the position of the frame directly + * BELOW this one. Absent when DWARF states no call site or names a file this + * table cannot resolve. + */ + callSite?: { path: string; line: number; column?: number }; + /** The parameters and variables this frame declares, in scope at the PC. */ + variables: ScopeVar[]; +} export interface VariableResolver { hasVariables(): boolean; functionNameAt(pc: number): string | null; + /** + * The enclosing function's name qualified by its DWARF namespaces and types + * (`control::__while_call::invoke_raw`), or null. This is the frame label; + * `functionNameAt` is the bare DIE name. + */ + qualifiedFunctionNameAt(pc: number): string | null; + /** Rust frames inlined into the function at `pc`, OUTERMOST first. */ + inlineFramesAt(pc: number): InlineFrame[]; variablesInScope(pc: number): ScopeVar[]; decodeVariable(v: ScopeVar, state: RuntimeState, pc: number): DecodedValue; } @@ -30,6 +61,12 @@ export class NullVariableResolver implements VariableResolver { functionNameAt(): string | null { return null; } + qualifiedFunctionNameAt(): string | null { + return null; + } + inlineFramesAt(): InlineFrame[] { + return []; + } variablesInScope(): ScopeVar[] { return []; } @@ -40,7 +77,14 @@ export class NullVariableResolver implements VariableResolver { /** Resolves and decodes variables from a wasm module's DWARF debug info. */ export class DwarfVariableResolver implements VariableResolver { - constructor(private readonly dwarf: DwarfDebugInfo) {} + /** + * `lineTable` is optional: without it inlined frames still resolve, they just + * report no call-site path (their file index cannot be looked up). + */ + constructor( + private readonly dwarf: DwarfDebugInfo, + private readonly lineTable?: DwarfLineTable, + ) {} hasVariables(): boolean { return this.dwarf.scopes.hasFunctions(); @@ -50,6 +94,14 @@ export class DwarfVariableResolver implements VariableResolver { return this.dwarf.scopes.functionNameAt(pc); } + qualifiedFunctionNameAt(pc: number): string | null { + return this.dwarf.scopes.functionAt(pc)?.qualifiedName ?? null; + } + + inlineFramesAt(pc: number): InlineFrame[] { + return this.dwarf.scopes.inlineScopesAt(pc).map((scope) => this.toInlineFrame(scope)); + } + variablesInScope(pc: number): ScopeVar[] { return this.dwarf.scopes.variablesInScope(pc); } @@ -79,4 +131,23 @@ export class DwarfVariableResolver implements VariableResolver { return { display: '' }; } } + + /** One inline scope with its call-site file index resolved to a path. */ + private toInlineFrame(scope: InlineScope): InlineFrame { + const frame: InlineFrame = { variables: scope.variables }; + if (scope.name !== undefined) { + frame.name = scope.name; + } + const path = + scope.stmtListOffset !== undefined && scope.callFileIndex !== undefined + ? this.lineTable?.filePath(scope.stmtListOffset, scope.callFileIndex) + : undefined; + if (path !== undefined && scope.callLine !== undefined) { + frame.callSite = { path, line: scope.callLine }; + if (scope.callColumn !== undefined) { + frame.callSite.column = scope.callColumn; + } + } + return frame; + } } diff --git a/src/trace/projectStop.ts b/src/trace/projectStop.ts index 050b7a9..3ff4f4d 100644 --- a/src/trace/projectStop.ts +++ b/src/trace/projectStop.ts @@ -23,6 +23,7 @@ import { summarizeScVal, } from '../soroban/scvalJson'; import { Durability } from '../komet/trace'; +import { FrameKind, buildCallStack } from '../debugAdapter/callStack'; /** A serializable single-stop projection. */ export interface SourceStop { @@ -36,6 +37,12 @@ export interface SourceStop { pc: string | null; /** functionNameAt(pc), or null. */ function: string | null; + /** + * The call stack at this stop, innermost frame first (docs/callstack.md) — the + * same derivation the IDE's Callstack view shows, so a CLI trace and a debug + * session never disagree about who called whom. Never empty. + */ + frames: StopFrame[]; /** renderInstr(record.instr). */ instr: string; /** Mapped source location, or null when unmapped. */ @@ -54,6 +61,21 @@ export interface SourceStop { ledger?: StopLedger; } +/** One call-stack frame of a stop (docs/callstack.md). */ +export interface StopFrame { + /** 0 = innermost. */ + level: number; + name: string; + /** Which rung of the naming ladder placed this frame: rust/inline/wasm/contract. */ + kind: FrameKind; + /** Hex code offset, e.g. "0x2d", or null. */ + pc: string | null; + /** Where the frame stands, or null when unmapped. */ + source: { path: string; line: number; column?: number } | null; + /** Set for a frame the user did not write (toolchain, dependency, or sourceless). */ + subtle?: true; +} + /** The ledger projection of one stop (docs/state-inspection.md, Presentation). */ export interface StopLedger { /** Executing contract as a `C…` strkey, or null before any contract call. */ @@ -216,6 +238,7 @@ export function projectSourceStop( depth: stopModel.depths[index], pc: pcHex, function: functionName, + frames: projectFrames(resolved, stopModel, index), instr: renderInstr(record.instr), source, variables, @@ -239,6 +262,32 @@ export function projectSourceStop( return stop; } +/** + * The stop's call stack in the CLI's JSON schema. `variables` are deliberately + * NOT repeated per frame: a stop's `variables` are the innermost frame's, and a + * per-frame expansion would multiply the output size of every stop. + */ +function projectFrames( + resolved: ResolvedTrace, + stopModel: StopModel, + index: number, +): StopFrame[] { + const input = { resolved, frames: stopModel.frames, ranges: stopModel.ranges }; + return buildCallStack(input, index).map((frame) => { + const projected: StopFrame = { + level: frame.level, + name: frame.name, + kind: frame.kind, + pc: frame.pc === null ? null : '0x' + frame.pc.toString(16), + source: frame.source === null ? null : { ...frame.source }, + }; + if (frame.subtle) { + projected.subtle = true; + } + return projected; + }); +} + /** * Flatten the shared ledger snapshot at `index` into the CLI's JSON schema, * flagging the storage entries that moved since `previousIndex`. diff --git a/src/wasm/Disassembly.ts b/src/wasm/Disassembly.ts index 6002f56..8dfb94b 100644 --- a/src/wasm/Disassembly.ts +++ b/src/wasm/Disassembly.ts @@ -15,6 +15,7 @@ import { BinaryReader } from 'wasmparser'; import { WasmDisassembler } from 'wasmparser/dist/cjs/WasmDis'; import { parseWasmSections, WasmFormatError } from './sections'; +import { demangleRust, functionNames, importedFunctionCount } from './names'; import { renderInstr } from '../komet/mnemonics'; import { TraceModel } from '../debugAdapter/TraceModel'; import { FunctionRange } from '../debugAdapter/stops'; @@ -101,12 +102,23 @@ export class Disassembly { bytes: bytes.subarray(p.fileOffset, end), }; }); - const functionRanges = functionBodyOffsets.map( - (b): FunctionRange => ({ + // Body order is function-index order after the imports, so the i-th body is + // function index `imported + i` — the index the `name` section keys on. + const names = functionNames(bytes); + const imported = importedFunctionCount(bytes); + const functionRanges = functionBodyOffsets.map((b, i): FunctionRange => { + const index = imported + i; + const symbol = names.get(index); + const range: FunctionRange = { start: b.start - codeSection.payloadStart, end: b.end - codeSection.payloadStart, - }), - ); + index, + }; + if (symbol !== undefined) { + range.name = demangleRust(symbol); + } + return range; + }); return new Disassembly(instructions, functionRanges); } diff --git a/src/wasm/names.ts b/src/wasm/names.ts new file mode 100644 index 0000000..6a57b3c --- /dev/null +++ b/src/wasm/names.ts @@ -0,0 +1,195 @@ +/** + * Wasm function symbols: the `name` custom section, the import count that maps + * body order to function index, and Rust symbol demangling. + * + * This is the naming ladder's second rung (docs/callstack.md, C4). When a module + * carries DWARF, frames are named from the DIE tree; when it does not — a + * release build with `debugInfo: false`, or any wasm whose `.debug_*` sections + * were stripped — the `name` section is usually still there, and it holds the + * Rust symbol of every function. Demangled, `_ZN7control7Control10while_call17h…E` + * reads `control::Control::while_call`, which is what a wasm-level call stack + * shows instead of a bare function index. + * + * Both readers are DELIBERATELY lenient: a truncated or unexpected name + * subsection yields the names read so far rather than an error, because a + * cosmetic section must never fail a debug session. Structural wasm errors + * (bad magic, a section running past EOF) still throw from `parseWasmSections`. + * + * Pure module (no `vscode` imports). + */ + +import { BinaryReader, BinaryReaderState, ExternalKind } from 'wasmparser'; +import { parseWasmSections, readUleb } from './sections'; + +/** The `name` section's subsection id for the function-name map. */ +const FUNCTION_NAMES_SUBSECTION = 1; +/** Wasm section id of the import section. */ +const IMPORT_SECTION_ID = 2; + +/** + * Function names by wasm function index (imports included in the numbering), as + * written in the `name` custom section — still mangled. Empty when the module + * carries no `name` section or no function-name subsection. + */ +export function functionNames(bytes: Uint8Array): Map { + const names = new Map(); + const section = parseWasmSections(bytes).customSection('name'); + if (!section) { + return names; + } + let offset = 0; + while (offset < section.length) { + const id = section[offset]; + let size: number; + let payloadStart: number; + try { + [size, payloadStart] = readUleb(section, offset + 1); + } catch { + return names; // Truncated subsection header; keep what we have. + } + const payloadEnd = payloadStart + size; + if (payloadEnd > section.length) { + return names; + } + if (id === FUNCTION_NAMES_SUBSECTION) { + readNameMap(section.subarray(payloadStart, payloadEnd), names); + return names; // Function names appear once; later subsections name locals. + } + offset = payloadEnd; + } + return names; +} + +/** + * Read a `namemap` — `count` followed by `(index, name)` pairs — into `out`, + * stopping at the first entry that does not fit (a truncated section). + */ +function readNameMap(payload: Uint8Array, out: Map): void { + let offset: number; + let count: number; + try { + [count, offset] = readUleb(payload, 0); + } catch { + return; + } + for (let i = 0; i < count; i++) { + try { + const [index, afterIndex] = readUleb(payload, offset); + const [length, afterLength] = readUleb(payload, afterIndex); + const end = afterLength + length; + if (end > payload.length) { + return; + } + out.set(index, Buffer.from(payload.subarray(afterLength, end)).toString('utf8')); + offset = end; + } catch { + return; + } + } +} + +/** + * How many functions the module IMPORTS. Wasm numbers imported functions first, + * so the i-th function BODY (the i-th entry of `Disassembly.functionRanges`) is + * function index `importedFunctionCount(bytes) + i` — the index the `name` + * section keys on. + */ +export function importedFunctionCount(bytes: Uint8Array): number { + const data = new ArrayBuffer(bytes.length); + new Uint8Array(data).set(bytes); + const reader = new BinaryReader(); + reader.setData(data, 0, bytes.length); + let count = 0; + while (reader.read()) { + if (reader.state === BinaryReaderState.BEGIN_SECTION) { + // Stop once the walk is past the import section (id 2) rather than + // decoding every instruction of the code section for nothing. Custom + // sections (id 0) may appear anywhere, so they never end the walk. + const id = (reader.result as { id: number }).id; + if (id > IMPORT_SECTION_ID) { + break; + } + } + if ( + reader.state === BinaryReaderState.IMPORT_SECTION_ENTRY && + (reader.result as { kind: number }).kind === ExternalKind.Function + ) { + count++; + } + } + return count; +} + +/** Legacy-mangling hash segment: `h` followed by 16 hex digits. */ +const HASH_SEGMENT_RE = /^h[0-9a-f]{16}$/; + +/** The fixed `$…$` escapes rustc's legacy mangling emits. */ +const ESCAPES: Record = { + SP: ' ', + BP: '*', + RF: '&', + LT: '<', + GT: '>', + LP: '(', + RP: ')', + C: ',', +}; + +/** + * Demangle a Rust LEGACY-mangled symbol (`_ZN…E`), the scheme rustc still emits + * by default: length-prefixed path segments, a trailing disambiguating hash + * segment, and `$…$` escapes for characters illegal in a symbol name. So + * `_ZN7control4bump17h2628dce790f861d2E` becomes `control::bump`. + * + * Anything else — a plain name, a C symbol, or a v0-mangled symbol (`_R…`, + * which rustc emits only under `-Csymbol-mangling-version=v0`) — is returned + * unchanged: an undemangled symbol still names the frame, so guessing is worse + * than passing it through. + */ +export function demangleRust(symbol: string): string { + if (!symbol.startsWith('_ZN') || !symbol.endsWith('E')) { + return symbol; + } + const segments: string[] = []; + let offset = 3; + const body = symbol.slice(0, -1); + while (offset < body.length) { + const digits = /^\d+/.exec(body.slice(offset)); + if (!digits) { + return symbol; // Not length-prefixed after all; not a legacy symbol. + } + const length = Number(digits[0]); + const start = offset + digits[0].length; + if (start + length > body.length) { + return symbol; + } + segments.push(body.slice(start, start + length)); + offset = start + length; + } + if (segments.length === 0) { + return symbol; + } + if (HASH_SEGMENT_RE.test(segments[segments.length - 1])) { + segments.pop(); + } + return segments.map(unescapeSegment).join('::'); +} + +/** + * Decode one mangled path segment: the fixed `$…$` escapes, the general + * `$u$` form, `..` for `::`, and a leading `_` guarding a segment that + * would otherwise start with a digit or `$`. + */ +function unescapeSegment(segment: string): string { + // The guard is removed BEFORE unescaping: after `$LT$` has become `<` there is + // no way to tell a guarded segment from one that starts with a real `_`. + const unguarded = /^_(\$|\d)/.test(segment) ? segment.slice(1) : segment; + const unescaped = unguarded.replace(/\$(u[0-9a-fA-F]{2,6}|[A-Z]{1,2})\$/g, (match, code: string) => { + if (code.startsWith('u')) { + const point = Number.parseInt(code.slice(1), 16); + return Number.isNaN(point) ? match : String.fromCodePoint(point); + } + return ESCAPES[code] ?? match; + }); + return unescaped.replace(/\.\./g, '::'); +} diff --git a/src/wasm/sections.ts b/src/wasm/sections.ts index de137bf..c74ffba 100644 --- a/src/wasm/sections.ts +++ b/src/wasm/sections.ts @@ -130,9 +130,9 @@ export function stripDebugSections(bytes: Uint8Array): Uint8Array { } /** - * Reads a ULEB128 at `offset`; returns [value, offset after the ULEB]. - * Exported for cross-implementation agreement tests against the DWARF - * `Cursor.uleb` decoder; not part of the public wasm API. + * Reads a ULEB128 at `offset`; returns [value, offset after the ULEB]. Used by + * the `name`-section reader (`names.ts`), and by cross-implementation agreement + * tests against the DWARF `Cursor.uleb` decoder. */ export function readUleb(bytes: Uint8Array, offset: number): [number, number] { let value = 0; diff --git a/test/callStack.test.ts b/test/callStack.test.ts new file mode 100644 index 0000000..3158670 --- /dev/null +++ b/test/callStack.test.ts @@ -0,0 +1,377 @@ +/** + * Unit suite for the call stack (docs/callstack.md): + * + * buildCallStack({ resolved, frames, ranges }, index): CallFrame[] + * from src/debugAdapter/callStack.ts + * + * Values are pinned to the real fixtures, whose stacks are ground truth: + * - adder-debug (above opt-0): `add` is fully INLINED into the + * `#[contractimpl]` wrapper, so the whole Rust chain is inline frames (C2). + * - stepper-debug: `triple` is a REAL call (`#[inline(never)]`) whose caller + * `sum_triples` is itself inlined — a mixed physical/inline stack (C1 + C2). + * - control-debug (opt-0): `bump` called from `Control::while_call`, both real + * wasm functions — the case where activations alone carry the Rust chain. + * - the same traces replayed with NO wasm — the degraded ladder (C4). + */ + +import * as assert from 'assert'; +import * as fs from 'fs'; +import * as path from 'path'; +import { buildCallStack, CallFrame } from '../src/debugAdapter/callStack'; +import { buildStopModel } from '../src/debugAdapter/stopModel'; +import { RawTraceBackend } from '../src/debugAdapter/backends/RawTraceBackend'; +import { ResolvedTrace } from '../src/debugAdapter/types'; +import { parseTraceJsonl, toTraceRecord, TraceRecord } from '../src/komet/trace'; +import { TraceModel } from '../src/debugAdapter/TraceModel'; +import { Disassembly } from '../src/wasm/Disassembly'; +import { NullSourceMapper } from '../src/sourcemap/NullSourceMapper'; +import { NullVariableResolver } from '../src/sourcemap/VariableResolver'; +import { buildDebugArtifacts } from '../src/debugAdapter/artifacts'; +import { stripDebugSections } from '../src/wasm/sections'; + +const FIXTURES = path.join(__dirname, '..', '..', 'test', 'fixtures'); + +/** Resolve a fixture trace, with its wasm (symbol-rich) or without (degraded). */ +async function resolveFixture(trace: string, wasm?: string): Promise { + const args: Record = { rawTrace: path.join(FIXTURES, `${trace}.trace.jsonl`) }; + if (wasm !== undefined) { + args.wasmPath = path.join(FIXTURES, `${wasm}.wasm`); + } + return new RawTraceBackend().resolve(args as never, () => {}); +} + +/** The call stack at `index`, via the shared stop model. */ +function stackAt(resolved: ResolvedTrace, index: number): CallFrame[] { + const stops = buildStopModel(resolved); + return buildCallStack({ resolved, frames: stops.frames, ranges: stops.ranges }, index); +} + +/** `name @ file:line` per frame — the shape a reader of the view sees. */ +function outline(frames: CallFrame[]): string[] { + return frames.map( + (f) => `${f.name} @ ${f.source === null ? '-' : `${path.basename(f.source.path)}:${f.source.line}`}`, + ); +} + +describe('buildCallStack (docs/callstack.md)', () => { + describe('adder-debug: a fully inlined Rust chain (C2)', () => { + let resolved: ResolvedTrace; + before(async () => { + resolved = await resolveFixture('adder-debug', 'adder-debug'); + }); + + it('reports the inlined callee, its inliner, and the wasm activation', () => { + // Index 29 is the sole statement stop, lib.rs:16 (`a + b`) at pc 0x2d. The + // ONLY wasm activation there is the export wrapper; `add` and the macro's + // `invoke_raw` exist only as DWARF inline instances. + assert.deepStrictEqual(outline(stackAt(resolved, 29)), [ + 'add @ lib.rs:16', + 'invoke_raw @ lib.rs:12', + 'adder::__add::invoke_raw_extern @ lib.rs:12', + ]); + }); + + it('marks the inline frames as such and the activation as a rust frame (C1/C2)', () => { + const frames = stackAt(resolved, 29); + assert.deepStrictEqual( + frames.map((f) => f.kind), + ['inline', 'inline', 'rust'], + ); + assert.deepStrictEqual( + frames.map((f) => f.level), + [0, 1, 2], + ); + }); + + it('positions every frame at the same pc but at its own source line (C2)', () => { + // Inlined code has ONE pc; what differs per frame is where the call was + // written. The innermost frame stands on the line the line table names, the + // outer ones on their callee's call site. + const frames = stackAt(resolved, 29); + assert.deepStrictEqual( + frames.map((f) => f.pc), + [0x2d, 0x2d, 0x2d], + ); + assert.deepStrictEqual( + frames.map((f) => f.source?.line), + [16, 12, 12], + ); + }); + + it('reads every frame’s state from the same record when nothing was called', () => { + for (const frame of stackAt(resolved, 29)) { + assert.strictEqual(frame.stateIndex, 29); + } + }); + + it('treats workspace frames as prominent (C5)', () => { + assert.deepStrictEqual( + stackAt(resolved, 29).map((f) => f.subtle), + [false, false, false], + ); + }); + }); + + describe('stepper-debug: a real call under an inlined caller (C1 + C2)', () => { + let resolved: ResolvedTrace; + before(async () => { + resolved = await resolveFixture('stepper-debug', 'stepper-debug'); + }); + + it('shows the callee, the CALL SITE of its caller, and the wrapper chain', () => { + // Index 29 is inside `triple` (depth 1), called from lib.rs:26 + // `acc.wrapping_add(triple(i))`. The caller frame must stand on line 26 — + // the call it is suspended in — not on `sum_triples`' own first line. + assert.deepStrictEqual(outline(stackAt(resolved, 29)), [ + 'stepper::triple @ lib.rs:15', + 'sum_triples @ lib.rs:26', + 'invoke_raw @ lib.rs:20', + 'stepper::__sum_triples::invoke_raw_extern @ lib.rs:20', + ]); + }); + + it('reads an outer frame’s state from its own call instruction (C7)', () => { + const frames = stackAt(resolved, 29); + // The callee's state is the cursor's record; the caller's is the record of + // the `call` that entered it (28), where its locals were last observed. + assert.deepStrictEqual( + frames.map((f) => f.stateIndex), + [29, 28, 28, 28], + ); + }); + + it('has no caller frames at all before any call is made', () => { + // Index 21 (lib.rs:25, the `while`) runs at depth 0: one activation. + const frames = stackAt(resolved, 21); + assert.strictEqual(frames.filter((f) => f.kind !== 'inline').length, 1); + assert.deepStrictEqual(outline(frames), [ + 'sum_triples @ lib.rs:25', + 'invoke_raw @ lib.rs:20', + 'stepper::__sum_triples::invoke_raw_extern @ lib.rs:20', + ]); + }); + + it('agrees with the stepping depth about how deep the stack is', () => { + // The Callstack view and step-over/step-out are derived from the SAME frame + // reconstruction, so the number of activations is depth + 1 (C1). + const stops = buildStopModel(resolved); + for (const index of [21, 27, 29, 46, 63, 73]) { + const frames = buildCallStack( + { resolved, frames: stops.frames, ranges: stops.ranges }, + index, + ); + const activations = frames.filter((f) => f.kind !== 'inline' && f.kind !== 'contract'); + assert.strictEqual( + activations.length, + stops.depths[index] + 1, + `index ${index}: ${activations.length} activations at depth ${stops.depths[index]}`, + ); + } + }); + }); + + describe('control-debug: opt-0, where activations carry the Rust chain (C1)', () => { + let resolved: ResolvedTrace; + before(async () => { + resolved = await resolveFixture('control-while_call', 'control-debug'); + }); + + it('shows a real callee over its real caller, each on its own line', () => { + // Index 266 is `bump`'s body (lib.rs:16) at depth 3, called from + // `while_call` at lib.rs:56. + assert.deepStrictEqual(outline(stackAt(resolved, 266)), [ + 'control::bump @ lib.rs:16', + 'control::Control::while_call @ lib.rs:56', + 'control::__while_call::invoke_raw @ lib.rs:20', + 'control::__while_call::invoke_raw_extern @ lib.rs:20', + ]); + }); + + it('names a frame whose DWARF DIE is anonymous from the name section (C4)', () => { + // rustc leaves `Control::while_call`'s subprogram DIE unnamed; the demangled + // `name`-section symbol is the next rung of the ladder, and the frame is + // still located by DWARF, so it stays a rust frame. + const frame = stackAt(resolved, 266)[1]; + assert.strictEqual(frame.name, 'control::Control::while_call'); + assert.strictEqual(frame.kind, 'rust'); + }); + + it('exposes each frame’s own variables (C7)', () => { + const frames = stackAt(resolved, 266); + const names = (frame: CallFrame): string[] => + frame.variables.map((v) => v.name ?? ''); + assert.deepStrictEqual(names(frames[0]), ['x']); + // The caller's own locals, not the callee's. + for (const expected of ['n', 'acc', 'i']) { + assert.ok( + names(frames[1]).includes(expected), + `expected ${expected} among the caller's variables, got: ${names(frames[1]).join(', ')}`, + ); + } + assert.ok(!names(frames[1]).includes('x'), 'the caller must not report the callee’s x'); + }); + }); + + describe('no wasm at all: the degraded ladder (C4)', () => { + let resolved: ResolvedTrace; + before(async () => { + resolved = await resolveFixture('adder-debug'); + }); + + it('reports one addressed wasm frame, with no source and no name to give', () => { + const frames = stackAt(resolved, 29); + assert.deepStrictEqual(outline(frames), ['wasm@0x2d @ -']); + assert.strictEqual(frames[0].kind, 'wasm'); + assert.strictEqual(frames[0].pc, 0x2d); + }); + + it('does not deemphasize a sourceless frame when the session has no line info (C5)', () => { + // Everything is sourceless here, so deemphasizing would grey out the whole + // view and say nothing. + assert.strictEqual(stackAt(resolved, 29)[0].subtle, false); + }); + }); + + describe('wasm without DWARF: named from the name section (C4)', () => { + it('labels every frame with the demangled symbol and its offset in the function', () => { + // The activation structure survives losing DWARF — index 29 is still + // `triple` called from the wrapper — and each frame is named from the + // `name` section, carrying the offset that is now the only position it has. + const frames = stackAt(strippedStepper(), 29); + assert.deepStrictEqual( + frames.map((f) => f.kind), + ['wasm', 'wasm'], + ); + assert.strictEqual(frames[0].name, 'stepper::triple'); + assert.match(frames[1].name, /^sum_triples\+0x[0-9a-f]+$/); + for (const frame of frames) { + assert.strictEqual(frame.source, null); + assert.strictEqual(frame.subtle, false, 'nothing is deemphasized without line info'); + } + }); + }); + + describe('the bottom rungs of the naming ladder (C4)', () => { + it('falls back to the wasm function index when the module names nothing', () => { + // composite.wasm carries neither DWARF nor a `name` section, so a frame can + // only be identified by which function body it is in. + const frames = stackAt(unnamedModule(), 0); + assert.strictEqual(frames.length, 1); + assert.match(frames[0].name, /^func\[\d+\](\+0x[0-9a-f]+)?$/); + assert.strictEqual(frames[0].kind, 'wasm'); + }); + + it('still reports the cursor on a record ahead of the first established frame', async () => { + // adder's records 0..5 precede every visible instruction, so the frame walk + // has nothing on its stack yet. The view must still show where the cursor + // is rather than come back empty. + const resolved = await resolveFixture('adder-debug', 'adder-debug'); + const stops = buildStopModel(resolved); + assert.strictEqual(stops.frames[0], null, 'record 0 precedes the first frame'); + const frames = buildCallStack({ resolved, frames: stops.frames, ranges: stops.ranges }, 0); + assert.strictEqual(frames.length, 1); + assert.strictEqual(frames[0].level, 0); + assert.strictEqual(frames[0].stateIndex, 0); + }); + + it('reports a synthetic frame when no record has an address at all', async () => { + // Every record of this trace is synthetic (pos null): there is no pc, so no + // function, no name and no offset — but still a frame, never an empty view. + const resolved = await resolveFixture('synthetic-all-null'); + const frames = stackAt(resolved, 0); + assert.strictEqual(frames.length, 1); + assert.strictEqual(frames[0].name, ''); + assert.strictEqual(frames[0].pc, null); + }); + }); + + describe('contract boundaries (C3)', () => { + it('appends one label frame per open contract call, innermost first', () => { + const frames = stackAt(syntheticCrossContract(), 4); + const contracts = frames.filter((f) => f.kind === 'contract'); + assert.deepStrictEqual( + contracts.map((f) => f.name), + ['inner() @ 0xbbbb', 'outer() @ 0xaaaa'], + ); + // A boundary is not a code position: nothing to open, nothing to inspect. + for (const frame of contracts) { + assert.strictEqual(frame.pc, null); + assert.strictEqual(frame.stateIndex, null); + assert.strictEqual(frame.source, null); + assert.deepStrictEqual(frame.variables, []); + } + }); + + it('puts the boundary frames below every wasm frame', () => { + const frames = stackAt(syntheticCrossContract(), 4); + const firstContract = frames.findIndex((f) => f.kind === 'contract'); + assert.ok(firstContract > 0, 'expected at least one wasm frame above the boundaries'); + assert.ok( + frames.slice(firstContract).every((f) => f.kind === 'contract'), + 'a wasm frame must never appear below a contract boundary', + ); + }); + }); +}); + +/** + * stepper-debug's trace replayed against a DWARF-STRIPPED stepper wasm: real + * disassembly and a real `name` section, no line info and no DIEs. This is what a + * release build (`debugInfo: false`) gives the debugger. + */ +function strippedStepper(): ResolvedTrace { + const wasm = stripDebugSections( + new Uint8Array(fs.readFileSync(path.join(FIXTURES, 'stepper-debug.wasm'))), + ); + const records = parseTraceJsonl( + fs.readFileSync(path.join(FIXTURES, 'stepper-debug.trace.jsonl'), 'utf8'), + ); + const model = new TraceModel(records); + return { model, ...buildDebugArtifacts(wasm, model, () => {}) }; +} + +/** + * A one-record trace inside composite.wasm — a module with no DWARF and no + * `name` section. `['unknown']` is the mnemonic komet emits for opcodes its + * printer cannot decode, and position validation accepts it on the exact-address + * check alone, so the record lands inside a real function body. + */ +function unnamedModule(): ResolvedTrace { + const wasm = new Uint8Array(fs.readFileSync(path.join(FIXTURES, 'composite.wasm'))); + const body = Disassembly.fromWasm(wasm).functionRanges[0]; + const records = [ + toTraceRecord({ kind: 'instr', pos: body.start, instr: ['unknown'], stack: [], locals: {} }, 1), + ]; + const model = new TraceModel(records); + return { model, ...buildDebugArtifacts(wasm, model, () => {}) }; +} + +/** A trace with two nested contract calls open at index 4. */ +function syntheticCrossContract(): ResolvedTrace { + const A = 'a'.repeat(4); + const B = 'b'.repeat(4); + const call = (to: string, fn: string, depth: number): TraceRecord => + toTraceRecord( + { + kind: 'callContract', + from: { type: 'address', addrType: 'contract', value: A }, + to: { type: 'address', addrType: 'contract', value: to }, + function: fn, + depth, + args: [], + }, + 1, + ); + const nop = (pos: number | null): TraceRecord => + toTraceRecord({ kind: 'instr', pos, instr: ['nop'], stack: [], locals: {} }, 1); + + const records = [nop(0), call(A, 'outer', 1), nop(1), call(B, 'inner', 2), nop(2)]; + const model = new TraceModel(records); + return { + model, + source: new NullSourceMapper(), + variables: new NullVariableResolver(), + disassembly: Disassembly.fromTrace(model), + positions: records.map((r) => r.pos), + }; +} diff --git a/test/dap.test.ts b/test/dap.test.ts index 377aecb..181d0b2 100644 --- a/test/dap.test.ts +++ b/test/dap.test.ts @@ -63,6 +63,15 @@ describe('SorobanDebugSession (DAP replay)', () => { return bpResponse; } + /** + * Assert where the replay cursor is. C8: the position in the recording is + * reported in the THREAD's name (`soroban-vm [29/40]`), not in a frame label — + * a frame name states what the program is doing. + */ + async function assertAt(index: number): Promise { + assert.strictEqual(await cursorIndex(), index, 'unexpected replay cursor position'); + } + async function topFrame(): Promise { const res = await dc.stackTraceRequest(THREAD); assert.ok(res.body.stackFrames.length >= 1, 'expected at least one stack frame'); @@ -75,6 +84,15 @@ describe('SorobanDebugSession (DAP replay)', () => { assert.strictEqual((stopped as DebugProtocol.StoppedEvent).body.reason, reason); } + /** The replay cursor's trace index, read off the thread label (C8). */ + async function cursorIndex(): Promise { + const threads = await dc.threadsRequest(); + const name = threads.body.threads[0].name; + const probe = /\[(\d+)\/\d+\]$/.exec(name); + assert.ok(probe, `thread name carries no cursor probe: ${name}`); + return Number(probe[1]); + } + /** * Walk backward at instruction granularity until the cursor clamps at the * first visible record, returning the top frame there. Statement-stop @@ -84,14 +102,14 @@ describe('SorobanDebugSession (DAP replay)', () => { */ async function rewindToFirstVisible(): Promise { const INSTR = { ...THREAD, granularity: 'instruction' as const }; - let prev = ''; - let frame = await topFrame(); - while (frame.name !== prev) { - prev = frame.name; + let prev = -1; + let index = await cursorIndex(); + while (index !== prev) { + prev = index; await stopAfter(dc.stepBackRequest(INSTR), 'step'); - frame = await topFrame(); + index = await cursorIndex(); } - return frame; + return topFrame(); } it('advertises reverse debugging and stepping granularity', async () => { @@ -152,7 +170,7 @@ describe('SorobanDebugSession (DAP replay)', () => { const frame = await topFrame(); assert.ok(frame.source?.path?.endsWith(LIB_RS_SUFFIX), `unexpected source: ${frame.source?.path}`); assert.strictEqual(frame.line, 16); - assert.ok(frame.name.includes('[29/40]'), `unexpected frame name: ${frame.name}`); + await assertAt(29); assert.strictEqual(frame.instructionPointerReference, '0x2d'); }); @@ -182,7 +200,7 @@ describe('SorobanDebugSession (DAP replay)', () => { let frame = await topFrame(); assert.ok(frame.source?.path?.endsWith(LIB_RS_SUFFIX), `unexpected source: ${frame.source?.path}`); assert.strictEqual(frame.line, 16); - assert.ok(frame.name.includes('[29/40]'), `unexpected frame name: ${frame.name}`); + await assertAt(29); // (A forward statement next here would exhaust the single stop and END the // session under S20 — see the dedicated S20 test below — so it is omitted @@ -194,7 +212,7 @@ describe('SorobanDebugSession (DAP replay)', () => { await stopAfter(dc.reverseContinueRequest(THREAD), 'breakpoint'); frame = await topFrame(); assert.strictEqual(frame.line, 16); - assert.ok(frame.name.includes('[29/40]'), `unexpected frame name: ${frame.name}`); + await assertAt(29); }); it('S12/S13: a breakpoint on the S17-dropped #[contractimpl] line still resolves and fires at its run starts', async () => { @@ -220,12 +238,12 @@ describe('SorobanDebugSession (DAP replay)', () => { frame.source?.path?.endsWith(LIB_RS_SUFFIX), `unexpected source: ${frame.source?.path}`, ); - assert.ok(frame.name.includes('[6/40]'), `unexpected frame name: ${frame.name}`); + await assertAt(6); await stopAfter(dc.continueRequest(THREAD), 'breakpoint'); frame = await topFrame(); assert.strictEqual(frame.line, 12); - assert.ok(frame.name.includes('[40/40]'), `unexpected frame name: ${frame.name}`); + await assertAt(40); }); it('S20: default-granularity next past the single statement stop terminates', async () => { @@ -249,13 +267,12 @@ describe('SorobanDebugSession (DAP replay)', () => { await launchAndStop(WITH_WASM); // Rewind to the first visible record (6) before pinning the head sequence // — the statement entry now lands on record 29 (S17). - const entry = await rewindToFirstVisible(); - assert.ok(entry.name.includes('[6/40]'), `unexpected head frame name: ${entry.name}`); + await rewindToFirstVisible(); + await assertAt(6); await stopAfter(dc.stepInRequest({ ...THREAD, granularity: 'instruction' }), 'step'); const frame = await topFrame(); - assert.notStrictEqual(frame.name, entry.name); - assert.ok(frame.name.includes('[7/40]'), `unexpected frame name: ${frame.name}`); + await assertAt(7); // Record 7 is still inside the lib.rs:12 run (S16). assert.strictEqual(frame.line, 12); }); @@ -276,12 +293,12 @@ describe('SorobanDebugSession (DAP replay)', () => { await stopAfter(dc.stepInRequest(THREAD), 'step'); let frame = await topFrame(); - assert.ok(frame.name.includes('[1/40]'), `unexpected frame name: ${frame.name}`); + await assertAt(1); assert.strictEqual(frame.source, undefined); await stopAfter(dc.stepBackRequest(THREAD), 'step'); frame = await topFrame(); - assert.ok(frame.name.includes('[0/40]'), `unexpected frame name: ${frame.name}`); + await assertAt(0); }); it('exposes locals and value stack at the cursor', async () => { @@ -461,7 +478,7 @@ describe('SorobanDebugSession (DAP replay)', () => { await stopAfter(dc.stepInRequest({ ...THREAD, granularity: 'instruction' }), 'step'); } const frame = await topFrame(); - assert.ok(frame.name.includes('[6/40]'), `unexpected frame name: ${frame.name}`); + await assertAt(6); assert.strictEqual(frame.instructionPointerReference, '0x5'); }); }); @@ -518,8 +535,7 @@ describe('SorobanDebugSession (DAP replay)', () => { // With only that (unverified) breakpoint set, continue settles on the // last statement stop (record 29, :16) — never the trailing shim records. await stopAfter(dc.continueRequest(THREAD), 'step'); - const frame = await topFrame(); - assert.ok(frame.name.includes('[29/40]'), `unexpected frame name: ${frame.name}`); + await assertAt(29); }); it('triggers on the validated record at an address, not a raw global-init pos', async () => { @@ -536,7 +552,7 @@ describe('SorobanDebugSession (DAP replay)', () => { await stopAfter(dc.continueRequest(THREAD), 'breakpoint'); const frame = await topFrame(); assert.strictEqual(frame.instructionPointerReference, '0xb'); - assert.ok(frame.name.includes('[9/40]'), `unexpected frame name: ${frame.name}`); + await assertAt(9); // Function code maps to Rust; the global-init record has no source. assert.ok( frame.source?.path?.endsWith(LIB_RS_SUFFIX), @@ -576,8 +592,7 @@ describe('SorobanDebugSession (DAP replay)', () => { // No breakpoints remain, so continue settles on the last statement stop // (record 29, :16) — never the trailing #[contractimpl] shim records. await stopAfter(dc.continueRequest(THREAD), 'step'); - const frame = await topFrame(); - assert.ok(frame.name.includes('[29/40]'), `unexpected frame name: ${frame.name}`); + await assertAt(29); }); it('applies the offset field to the instruction reference', async () => { diff --git a/test/dapControlStepping.test.ts b/test/dapControlStepping.test.ts index 914b24c..ffcf330 100644 --- a/test/dapControlStepping.test.ts +++ b/test/dapControlStepping.test.ts @@ -60,8 +60,10 @@ describe('Control-flow stepping (docs/stepping.md, DAP level)', () => { const res = await dc.stackTraceRequest(THREAD); assert.ok(res.body.stackFrames.length >= 1, 'expected at least one stack frame'); const frame = res.body.stackFrames[0]; - const probe = /\[(\d+)\/\d+\]$/.exec(frame.name); - assert.ok(probe, `frame name carries no trace-index probe: ${frame.name}`); + const threads = await dc.threadsRequest(); + const label = threads.body.threads[0].name; + const probe = /\[(\d+)\/\d+\]$/.exec(label); + assert.ok(probe, `thread label carries no cursor probe: ${label}`); return { index: Number(probe[1]), line: frame.line, col: frame.column, path: frame.source?.path }; } diff --git a/test/dapFrames.test.ts b/test/dapFrames.test.ts new file mode 100644 index 0000000..b3e1b13 --- /dev/null +++ b/test/dapFrames.test.ts @@ -0,0 +1,288 @@ +/** + * DAP-level suite for the Callstack view (docs/callstack.md, C1–C8), driven over + * the real adapter by @vscode/debugadapter-testsupport. + * + * test/callStack.test.ts pins the frame derivation at the pure level; this suite + * pins what a DAP CLIENT sees: how many frames it gets, how they are labelled and + * hinted, what paging returns, and — the part a call stack is actually FOR — that + * selecting an outer frame inspects that frame's state and not the innermost + * one's. + */ + +import * as assert from 'assert'; +import * as path from 'path'; +import { DebugClient } from '@vscode/debugadapter-testsupport'; +import { DebugProtocol } from '@vscode/debugprotocol'; + +const ADAPTER = path.join(__dirname, 'support', 'adapterEntry.js'); +const FIXTURES = path.join(__dirname, '..', '..', 'test', 'fixtures'); + +const STEPPER = { + rawTrace: path.join(FIXTURES, 'stepper-debug.trace.jsonl'), + wasmPath: path.join(FIXTURES, 'stepper-debug.wasm'), +}; +const ADDER = { + rawTrace: path.join(FIXTURES, 'adder-debug.trace.jsonl'), + wasmPath: path.join(FIXTURES, 'adder-debug.wasm'), +}; +const ADDER_RAW = { rawTrace: ADDER.rawTrace }; +const INCREMENT = { + rawTrace: path.join(FIXTURES, 'increment-debug.trace.jsonl'), + wasmPath: path.join(FIXTURES, 'increment-debug.wasm'), +}; + +const THREAD = { threadId: 1 }; +const STMT = { ...THREAD, granularity: 'statement' as const }; + +describe('Callstack view (docs/callstack.md, DAP level)', () => { + let dc: DebugClient; + + beforeEach(async () => { + dc = new DebugClient('node', ADAPTER, 'soroban'); + await dc.start(); + }); + + afterEach(async () => { + await dc.stop(); + }); + + /** Launch and wait for the entry stop. */ + async function launchAndStop(launchArgs: object): Promise { + const [, , stopped] = await Promise.all([ + dc.configurationSequence(), + dc.launch(launchArgs as never), + dc.waitForEvent('stopped'), + ]); + assert.strictEqual((stopped as DebugProtocol.StoppedEvent).body.reason, 'entry'); + } + + async function stopAfter(request: Promise): Promise { + await Promise.all([request, dc.waitForEvent('stopped')]); + } + + async function frames(args: object = {}): Promise { + return dc.stackTraceRequest({ ...THREAD, ...args }); + } + + /** `name @ file:line` per frame. */ + function outline(response: DebugProtocol.StackTraceResponse): string[] { + return response.body.stackFrames.map( + (f) => `${f.name} @ ${f.source ? `${path.basename(f.source.path ?? '')}:${f.line}` : '-'}`, + ); + } + + /** The scopes of one frame, by frame id. */ + async function scopesOf(frameId: number): Promise { + return (await dc.scopesRequest({ frameId })).body.scopes; + } + + /** `name=value` for every variable of a named scope of a frame. */ + async function scopeContents(frameId: number, scope: string): Promise { + const found = (await scopesOf(frameId)).find((s) => s.name === scope); + assert.ok(found, `frame ${frameId} offers no ${scope} scope`); + const res = await dc.variablesRequest({ variablesReference: found.variablesReference }); + return res.body.variables.map((v) => `${v.name}=${v.value}`); + } + + describe('the stack a client receives (C1, C2, C6)', () => { + it('reports the whole Rust chain, innermost first, with totalFrames', async () => { + await launchAndStop(STEPPER); + // Entry stop is lib.rs:25 in `sum_triples`, which is INLINED into the + // export wrapper: one activation, three frames. + const res = await frames(); + assert.deepStrictEqual(outline(res), [ + 'sum_triples @ lib.rs:25', + 'invoke_raw @ lib.rs:20', + 'stepper::__sum_triples::invoke_raw_extern @ lib.rs:20', + ]); + assert.strictEqual(res.body.totalFrames, 3); + }); + + it('grows by a frame when stepping into a real call, and shows the call site', async () => { + await launchAndStop(STEPPER); + // :25 -> :26 (the call line) -> into `triple`. + await stopAfter(dc.nextRequest(STMT)); + await stopAfter(dc.stepInRequest(STMT)); + assert.deepStrictEqual(outline(await frames()), [ + 'stepper::triple @ lib.rs:15', + 'sum_triples @ lib.rs:26', + 'invoke_raw @ lib.rs:20', + 'stepper::__sum_triples::invoke_raw_extern @ lib.rs:20', + ]); + }); + + it('gives every frame a distinct id and its own instruction pointer (C6)', async () => { + await launchAndStop(STEPPER); + await stopAfter(dc.nextRequest(STMT)); + await stopAfter(dc.stepInRequest(STMT)); + const stack = (await frames()).body.stackFrames; + assert.strictEqual(new Set(stack.map((f) => f.id)).size, stack.length); + for (const frame of stack) { + assert.match(frame.instructionPointerReference ?? '', /^0x[0-9a-f]+$/); + } + // The callee runs in `triple`'s body; its caller is suspended at the call. + assert.notStrictEqual( + stack[0].instructionPointerReference, + stack[1].instructionPointerReference, + ); + }); + + it('honors the client’s paging window (C6)', async () => { + await launchAndStop(STEPPER); + const full = (await frames()).body.stackFrames; + const page = await frames({ startFrame: 1, levels: 1 }); + assert.strictEqual(page.body.stackFrames.length, 1); + assert.strictEqual(page.body.totalFrames, full.length); + assert.strictEqual(page.body.stackFrames[0].id, full[1].id); + assert.strictEqual(page.body.stackFrames[0].name, full[1].name); + }); + + it('reports the same frame for the same id across requests (C6)', async () => { + await launchAndStop(STEPPER); + const first = (await frames()).body.stackFrames; + const again = (await frames()).body.stackFrames; + assert.deepStrictEqual( + again.map((f) => [f.id, f.name, f.line]), + first.map((f) => [f.id, f.name, f.line]), + ); + }); + + it('reports the line’s first non-whitespace column on every mapped frame (S19)', async () => { + await launchAndStop(STEPPER); + for (const frame of (await frames()).body.stackFrames) { + if (frame.source) { + assert.ok(frame.column > 0, `frame ${frame.name} reports column ${frame.column}`); + } + } + }); + }); + + describe('presentation (C3, C5, C8)', () => { + it('carries the recording position in the thread label, not a frame name', async () => { + await launchAndStop(ADDER); + const threads = await dc.threadsRequest(); + assert.match(threads.body.threads[0].name, /^soroban-vm \[\d+\/40\]$/); + for (const frame of (await frames()).body.stackFrames) { + assert.ok( + !/\[\d+\/\d+\]/.test(frame.name), + `a frame name must not carry the cursor: ${frame.name}`, + ); + } + }); + + it('updates the thread label as the cursor moves', async () => { + await launchAndStop(ADDER); + const before = (await dc.threadsRequest()).body.threads[0].name; + await stopAfter(dc.stepBackRequest({ ...THREAD, granularity: 'instruction' })); + assert.notStrictEqual((await dc.threadsRequest()).body.threads[0].name, before); + }); + + it('labels a contract boundary as such and hangs it below the code frames (C3)', async () => { + await launchAndStop(INCREMENT); + const stack = (await frames()).body.stackFrames; + const boundary = stack.filter((f) => f.presentationHint === 'label'); + assert.strictEqual(boundary.length, 1, `expected one boundary frame in: ${outline({ body: { stackFrames: stack } } as never).join(' | ')}`); + assert.match(boundary[0].name, /^\w+\(\) @ /); + assert.strictEqual(stack[stack.length - 1].id, boundary[0].id); + assert.strictEqual(boundary[0].source, undefined); + }); + + it('deemphasizes a frame outside the workspace, without hiding it (C5)', async () => { + // Instruction-stepping into the SDK's conversion glue reaches frames whose + // source is a crates.io path that does not exist on this machine. + await launchAndStop(INCREMENT); + const seen: DebugProtocol.StackFrame[] = []; + for (let i = 0; i < 40 && seen.length === 0; i++) { + const stack = (await frames()).body.stackFrames; + seen.push(...stack.filter((f) => f.presentationHint === 'subtle')); + await stopAfter(dc.stepInRequest({ ...THREAD, granularity: 'instruction' })); + } + assert.ok(seen.length > 0, 'expected at least one deemphasized frame while stepping'); + for (const frame of seen) { + assert.notStrictEqual(frame.name, '', 'a deemphasized frame is still named'); + } + }); + + it('offers one addressed frame and no source when there is no wasm at all (C4)', async () => { + await launchAndStop(ADDER_RAW); + const stack = (await frames()).body.stackFrames; + assert.strictEqual(stack.length, 1); + assert.match(stack[0].name, /^wasm@0x[0-9a-f]+$/); + assert.strictEqual(stack[0].source, undefined); + assert.strictEqual(stack[0].line, 0); + }); + }); + + describe('inspecting a selected frame (C7)', () => { + it('reads an outer frame’s wasm locals from that frame’s own record', async () => { + await launchAndStop(STEPPER); + await stopAfter(dc.nextRequest(STMT)); + await stopAfter(dc.stepInRequest(STMT)); + const stack = (await frames()).body.stackFrames; + + const callee = await scopeContents(stack[0].id, 'Locals'); + const caller = await scopeContents(stack[1].id, 'Locals'); + assert.notDeepStrictEqual( + caller, + callee, + `the caller must not report the callee's locals: ${callee.join(', ')}`, + ); + // `triple(x)` has one local; `sum_triples` is mid-loop with several. + assert.ok(callee.length >= 1 && caller.length > callee.length, `${callee.length} vs ${caller.length}`); + }); + + it('shows each frame’s own Rust variables', async () => { + await launchAndStop(STEPPER); + await stopAfter(dc.nextRequest(STMT)); + await stopAfter(dc.stepInRequest(STMT)); + const stack = (await frames()).body.stackFrames; + + // `triple`'s parameter is `x`; the frame below it is `sum_triples`, which + // has no `x` of its own. + const callee = await scopeContents(stack[0].id, 'Variables'); + assert.ok( + callee.some((v) => v.startsWith('x=')), + `expected x among triple's variables, got: ${callee.join(', ')}`, + ); + const caller = await scopeContents(stack[1].id, 'Variables'); + assert.ok( + !caller.some((v) => v.startsWith('x=')), + `the caller must not report the callee's x, got: ${caller.join(', ')}`, + ); + }); + + it('offers the VM-wide scopes on every code frame', async () => { + await launchAndStop(INCREMENT); + const stack = (await frames()).body.stackFrames; + for (const frame of stack.filter((f) => f.presentationHint !== 'label')) { + const names = (await scopesOf(frame.id)).map((s) => s.name); + assert.ok(names.includes('Ledger'), `frame ${frame.name} offers: ${names.join(', ')}`); + assert.ok(names.includes('Locals'), `frame ${frame.name} offers: ${names.join(', ')}`); + } + }); + + it('offers nothing to inspect on a contract boundary (C3)', async () => { + await launchAndStop(INCREMENT); + const stack = (await frames()).body.stackFrames; + const boundary = stack.find((f) => f.presentationHint === 'label'); + assert.ok(boundary, 'expected a boundary frame'); + assert.deepStrictEqual(await scopesOf(boundary.id), []); + }); + + it('keeps a frame’s children expandable after another frame is selected', async () => { + // Handles are reset per STOP, not per scopes request: a client that expands + // frame 0, selects frame 1, and comes back must not get an empty tree. + await launchAndStop(STEPPER); + await stopAfter(dc.nextRequest(STMT)); + await stopAfter(dc.stepInRequest(STMT)); + const stack = (await frames()).body.stackFrames; + + const scope = (await scopesOf(stack[0].id)).find((s) => s.name === 'Locals'); + assert.ok(scope); + const before = await dc.variablesRequest({ variablesReference: scope.variablesReference }); + await scopesOf(stack[1].id); + const after = await dc.variablesRequest({ variablesReference: scope.variablesReference }); + assert.deepStrictEqual(after.body.variables, before.body.variables); + }); + }); +}); diff --git a/test/dapStepping.test.ts b/test/dapStepping.test.ts index 8dcc1f4..58b1adb 100644 --- a/test/dapStepping.test.ts +++ b/test/dapStepping.test.ts @@ -51,7 +51,7 @@ const INSTR = { ...THREAD, granularity: 'instruction' as const }; /** What the top stack frame shows at a stop. */ interface Stop { - /** Trace index, parsed from the frame name's '[/]' probe. */ + /** Trace index, read off the thread label's '[/]' probe (C8). */ index: number; line: number; /** 1-based source column reported on the frame (S19: first non-whitespace). */ @@ -76,8 +76,10 @@ describe('Stepping spec (docs/stepping.md, DAP level)', () => { const res = await dc.stackTraceRequest(THREAD); assert.ok(res.body.stackFrames.length >= 1, 'expected at least one stack frame'); const frame = res.body.stackFrames[0]; - const probe = /\[(\d+)\/\d+\]$/.exec(frame.name); - assert.ok(probe, `frame name carries no trace-index probe: ${frame.name}`); + const threads = await dc.threadsRequest(); + const label = threads.body.threads[0].name; + const probe = /\[(\d+)\/\d+\]$/.exec(label); + assert.ok(probe, `thread label carries no cursor probe: ${label}`); return { index: Number(probe[1]), line: frame.line, diff --git a/test/dapVariables.test.ts b/test/dapVariables.test.ts index f7d5668..9b447bf 100644 --- a/test/dapVariables.test.ts +++ b/test/dapVariables.test.ts @@ -43,9 +43,25 @@ describe('SorobanDebugSession source-level Variables view', () => { return res.body.stackFrames[0]; } - /** The scopes offered for the current top frame. */ + /** + * The frame whose name contains `part`. The adder fixture is built above + * opt-level 0, so `add` survives only as an INLINE frame (docs/callstack.md, + * C2) and the parameters of the `#[contractimpl]` wrapper belong to the + * wrapper's own frame — which is the one these tests inspect. + */ + async function frameNamed(part: string): Promise { + const res = await dc.stackTraceRequest(THREAD); + const frame = res.body.stackFrames.find((f) => f.name.includes(part)); + assert.ok( + frame, + `no frame named like ${part}; got: ${res.body.stackFrames.map((f) => f.name).join(' | ')}`, + ); + return frame; + } + + /** The scopes offered for the frame owning the wrapper's parameters. */ async function topScopes(): Promise { - const frame = await topFrame(); + const frame = await frameNamed('invoke_raw_extern'); const res = await dc.scopesRequest({ frameId: frame.id }); return res.body.scopes; } @@ -99,7 +115,8 @@ describe('SorobanDebugSession source-level Variables view', () => { await launchAndStop(NO_WASM); // NullVariableResolver reports no functions -> the Variables scope is never // prepended, so a trace without DWARF sees exactly [Locals, Value Stack]. - const names = (await topScopes()).map((s) => s.name); + const frame = await topFrame(); + const names = (await dc.scopesRequest({ frameId: frame.id })).body.scopes.map((s) => s.name); assert.deepStrictEqual(names, ['Locals', 'Value Stack']); }); diff --git a/test/dwarfSourceMapper.test.ts b/test/dwarfSourceMapper.test.ts index 1eb30e5..2e25ba2 100644 --- a/test/dwarfSourceMapper.test.ts +++ b/test/dwarfSourceMapper.test.ts @@ -322,6 +322,42 @@ describe('sourcemap/DwarfSourceMapper (adder debug fixture)', () => { `duplicate existence checks: ${calls.sort().join(', ')}`, ); }); + + // A DWARF inlined call site is stated as a file/line pair rather than an + // address, and an outer frame's position comes from it (docs/callstack.md, C2). + describe('locationForFile (frame positions stated outside the line table)', () => { + it('normalizes an existing file and keeps a positive column', () => { + const loc = mapper.locationForFile(`${path.dirname(libRs)}/../src/lib.rs`, 12, 5); + assertLibRsLocation(loc, 12); + assert.strictEqual(loc!.column, 5); + }); + + it('omits a column DWARF states as 0 (unknown)', () => { + assert.strictEqual(mapper.locationForFile(libRs, 12, 0)?.column, undefined); + assert.strictEqual(mapper.locationForFile(libRs, 12)?.column, undefined); + }); + + it('is null for line 0 and for a file that is not on disk', () => { + // Line 0 is DWARF's "compiler-generated, no source line"; a file the user + // cannot open must not become a frame position either. + assert.strictEqual(mapper.locationForFile(libRs, 0), null); + assert.strictEqual(mapper.locationForFile('/nowhere/absent.rs', 3), null); + }); + }); + + describe('sourceTextAt', () => { + it('reads any line of a file, agreeing with sourceTextForIndex', () => { + // Index 29 maps to lib.rs:16; asking for that file/line directly must give + // the same text a frame at that record would show (S19's input). + assert.strictEqual(mapper.sourceTextAt(libRs, 16), mapper.sourceTextForIndex(29)); + assert.ok((mapper.sourceTextAt(libRs, 16) ?? '').includes('a + b')); + }); + + it('is null past the end of the file and for an unreadable one', () => { + assert.strictEqual(mapper.sourceTextAt(libRs, 100000), null); + assert.strictEqual(mapper.sourceTextAt('/nowhere/absent.rs', 1), null); + }); + }); }); describe('sourcemap/NullSourceMapper', () => { @@ -331,8 +367,11 @@ describe('sourcemap/NullSourceMapper', () => { assert.strictEqual(mapper.hasLineInfo(), false); assert.strictEqual(mapper.locationForIndex(0), null); assert.strictEqual(mapper.locationForAddress(0), null); + assert.strictEqual(mapper.locationForFile('/any/file.rs', 1), null); assert.strictEqual(mapper.lineKeyForIndex(0), null); assert.strictEqual(mapper.resolveBreakpoint('/any/file.rs', 1), null); assert.deepStrictEqual(mapper.executedLines('/any/file.rs', 1, 99), []); + assert.strictEqual(mapper.sourceTextForIndex(0), null); + assert.strictEqual(mapper.sourceTextAt('/any/file.rs', 1), null); }); }); diff --git a/test/justMyCode.test.ts b/test/justMyCode.test.ts index ed53ec0..5c27376 100644 --- a/test/justMyCode.test.ts +++ b/test/justMyCode.test.ts @@ -151,6 +151,10 @@ class StubSourceMapper implements SourceMapper { return null; } + locationForFile(): MappedLocation | null { + return null; + } + resolveBreakpoint(): ResolvedBreakpoint | null { return null; } @@ -171,6 +175,10 @@ class StubSourceMapper implements SourceMapper { const info = this.infos[index]; return info ? info.text : null; } + + sourceTextAt(): string | null { + return null; + } } /** A `nop` record: no call/return opcode, so computeDepths yields depth 0. */ diff --git a/test/projectStop.test.ts b/test/projectStop.test.ts index 04aa8e5..3e2daed 100644 --- a/test/projectStop.test.ts +++ b/test/projectStop.test.ts @@ -77,6 +77,27 @@ describe('projectSourceStop (docs/trace-cli-internal.md, serializable stop proje assert.strictEqual(v.truncated, undefined); } }); + + it('projects the whole call stack, innermost first (docs/callstack.md)', () => { + const sm = buildStopModel(resolved); + const stop = projectSourceStop(resolved, sm, 29); + + // The adder is built above opt-0, so `add` survives only as an inline frame + // inside the #[contractimpl] wrapper: one activation, three frames (C2). + assert.deepStrictEqual( + stop.frames.map((f) => [f.level, f.name, f.kind, f.pc, f.source?.line]), + [ + [0, 'add', 'inline', '0x2d', 16], + [1, 'invoke_raw', 'inline', '0x2d', 12], + [2, 'adder::__add::invoke_raw_extern', 'rust', '0x2d', 12], + ], + ); + // `subtle` is a marker: absent, never `false`, for a workspace frame (C5). + for (const frame of stop.frames) { + assert.strictEqual(frame.subtle, undefined); + assert.ok(frame.source!.path.endsWith('examples/adder/src/lib.rs')); + } + }); }); describe('stepper-debug idx 29 (function `triple`)', () => { diff --git a/test/replayCursor.test.ts b/test/replayCursor.test.ts index 9bd09df..e08e971 100644 --- a/test/replayCursor.test.ts +++ b/test/replayCursor.test.ts @@ -39,6 +39,9 @@ function stopModel(opts: { return { validatedPosToIndices: opts.validatedPosToIndices ?? new Map(), visibleIndices, + // The cursor reads depths, never the frames they are projected from. + frames: depths.map((depth) => ({ fn: -1, depth, callSite: null, caller: null })), + ranges: [], depths, rawRunStarts: opts.rawRunStarts ?? runStarts, runStarts, @@ -204,10 +207,12 @@ describe('resolveBreakpoints', () => { hasLineInfo: () => true, locationForIndex: (): MappedLocation | null => null, locationForAddress: (): MappedLocation | null => null, + locationForFile: (): MappedLocation | null => null, resolveBreakpoint: (): ResolvedBreakpoint | null => ({ line: 1, indices }), executedLines: () => [], lineKeyForIndex: () => null, sourceTextForIndex: () => null, + sourceTextAt: () => null, }; } diff --git a/test/scopeIndex.test.ts b/test/scopeIndex.test.ts index 5e296dd..b00e1cd 100644 --- a/test/scopeIndex.test.ts +++ b/test/scopeIndex.test.ts @@ -11,6 +11,9 @@ import { DW_TAG_formal_parameter, DW_TAG_variable, DW_TAG_lexical_block, + DW_TAG_inlined_subroutine, + DW_TAG_namespace, + DW_TAG_structure_type, DW_AT_name, DW_AT_low_pc, DW_AT_high_pc, @@ -18,6 +21,13 @@ import { DW_AT_location, DW_AT_type, DW_AT_frame_base, + DW_AT_stmt_list, + DW_AT_call_file, + DW_AT_call_line, + DW_AT_call_column, + DW_AT_abstract_origin, + DW_AT_specification, + DW_AT_linkage_name, } from '../src/dwarf/constants'; const FIXTURES = path.join(__dirname, '..', '..', 'test', 'fixtures'); @@ -340,7 +350,182 @@ describe('dwarf/ScopeIndex', () => { const hit = scope.functionAt(0x410); assert.ok(hit, 'the anonymous subprogram is still located by range'); assert.strictEqual(hit.name, undefined, 'it genuinely has no DIE name'); + assert.strictEqual(hit.qualifiedName, undefined, 'no name, nothing to qualify'); assert.strictEqual(scope.functionNameAt(0x410), 'wasm_func_1040'); }); }); + + // --- Frames: qualified names and inlined instances (docs/callstack.md) ---- + + describe('qualifiedName (docs/callstack.md C4)', () => { + it('prefixes the DIE name with its enclosing namespaces and types', () => { + const fn = die(730, DW_TAG_subprogram, [ + [DW_AT_name, str('bump')], + [DW_AT_low_pc, uint(0x10)], + [DW_AT_high_pc, uint(0x10)], + ]); + const impl = die(720, DW_TAG_structure_type, [[DW_AT_name, str('Control')]], [fn]); + const ns = die(710, DW_TAG_namespace, [[DW_AT_name, str('control')]], [impl]); + const cu = die(700, DW_TAG_compile_unit, [], [ns]); + const scope = new ScopeIndex(debugInfoOf(cu)); + + assert.strictEqual(scope.functionAt(0x14)?.qualifiedName, 'control::Control::bump'); + // The bare name is unchanged — it is what `functionNameAt` reports. + assert.strictEqual(scope.functionNameAt(0x14), 'bump'); + }); + + it('ignores an unnamed enclosing scope rather than emitting an empty segment', () => { + const fn = die(830, DW_TAG_subprogram, [ + [DW_AT_name, str('f')], + [DW_AT_low_pc, uint(0x10)], + [DW_AT_high_pc, uint(0x10)], + ]); + const anonymous = die(820, DW_TAG_namespace, [], [fn]); + const cu = die(800, DW_TAG_compile_unit, [], [anonymous]); + assert.strictEqual(new ScopeIndex(debugInfoOf(cu)).functionAt(0x10)?.qualifiedName, 'f'); + }); + }); + + describe('inlineScopesAt (docs/callstack.md C2)', () => { + /** + * `outer` (0x100..0x1ff) contains an inlined `middle` (0x110..0x11f) which + * itself contains an inlined `inner` (0x118..0x11b). `middle` declares `m`. + */ + function nested(): ScopeIndex { + const inner = die(940, DW_TAG_inlined_subroutine, [ + [DW_AT_name, str('inner')], + [DW_AT_low_pc, uint(0x118)], + [DW_AT_high_pc, uint(0x4)], + [DW_AT_call_file, uint(2)], + [DW_AT_call_line, uint(77)], + [DW_AT_call_column, uint(9)], + ]); + const m = die(935, DW_TAG_variable, [[DW_AT_name, str('m')], [DW_AT_location, block(0x91, 0x10)]]); + const middle = die( + 930, + DW_TAG_inlined_subroutine, + [ + [DW_AT_name, str('middle')], + [DW_AT_low_pc, uint(0x110)], + [DW_AT_high_pc, uint(0x10)], + [DW_AT_call_file, uint(1)], + [DW_AT_call_line, uint(42)], + ], + [m, inner], + ); + const outer = die( + 920, + DW_TAG_subprogram, + [ + [DW_AT_name, str('outer')], + [DW_AT_low_pc, uint(0x100)], + [DW_AT_high_pc, uint(0x100)], + [DW_AT_frame_base, block(0xed, 0x00, 0x00)], + ], + [middle], + ); + const cu = die(900, DW_TAG_compile_unit, [[DW_AT_stmt_list, uint(64)]], [outer]); + return new ScopeIndex(debugInfoOf(cu)); + } + + it('reports the covering instances outermost first, with their call sites', () => { + const scopes = nested().inlineScopesAt(0x119); + assert.deepStrictEqual( + scopes.map((s) => [s.name, s.callFileIndex, s.callLine, s.callColumn]), + [ + ['middle', 1, 42, undefined], + ['inner', 2, 77, 9], + ], + ); + // Every instance names the line program its call file index belongs to. + assert.deepStrictEqual(scopes.map((s) => s.stmtListOffset), [64, 64]); + }); + + it('reports only the instances whose own range covers the pc', () => { + const index = nested(); + assert.deepStrictEqual( + index.inlineScopesAt(0x112).map((s) => s.name), + ['middle'], + ); + assert.deepStrictEqual(index.inlineScopesAt(0x150), []); + // Outside every function there is nothing to expand. + assert.deepStrictEqual(index.inlineScopesAt(0x900), []); + }); + + it('gives each instance its OWN declarations, with the frame base threaded in', () => { + const scopes = nested().inlineScopesAt(0x119); + const middle = scopes[0]; + assert.deepStrictEqual(middle.variables.map((v) => v.name), ['m']); + assert.ok(middle.variables[0].frameBaseExpr, 'the enclosing frame base must be threaded in'); + // `m` belongs to `middle`, not to the deeper instance… + assert.deepStrictEqual(scopes[1].variables, []); + // …and not to the enclosing function either, which never descends into an + // inlined instance. + assert.deepStrictEqual(nested().variablesInScope(0x119), []); + }); + + it('skips an instance with no readable range instead of placing it anywhere', () => { + // No low_pc/high_pc and no ranges: the instance cannot be placed, and a + // guessed frame would misreport the program (C2). + const rangeless = die(1030, DW_TAG_inlined_subroutine, [[DW_AT_name, str('nowhere')]]); + // A tombstoned instance is dropped for the same reason. + const tombstoned = die(1035, DW_TAG_inlined_subroutine, [ + [DW_AT_name, str('dropped')], + [DW_AT_low_pc, uint(0xffffffff)], + [DW_AT_high_pc, uint(0x10)], + ]); + const fn = die( + 1020, + DW_TAG_subprogram, + [ + [DW_AT_name, str('host')], + [DW_AT_low_pc, uint(0x10)], + [DW_AT_high_pc, uint(0x10)], + ], + [rangeless, tombstoned], + ); + const cu = die(1000, DW_TAG_compile_unit, [], [fn]); + assert.deepStrictEqual(new ScopeIndex(debugInfoOf(cu)).inlineScopesAt(0x14), []); + }); + + it('resolves the name through abstract_origin, specification, and linkage_name', () => { + // rustc points an instance at an abstract subprogram that carries only a + // DW_AT_specification, whose declaration holds the name. Nothing else does. + const declaration = die(1140, DW_TAG_subprogram, [[DW_AT_name, str('wrapping_add')]]); + const abstract = die(1130, DW_TAG_subprogram, [[DW_AT_specification, ref(1140)]]); + const mangledOnly = die(1150, DW_TAG_subprogram, [ + [DW_AT_linkage_name, str('_ZN4core3fmt5writeE')], + ]); + const instance = die(1160, DW_TAG_inlined_subroutine, [ + [DW_AT_abstract_origin, ref(1130)], + [DW_AT_low_pc, uint(0x10)], + [DW_AT_high_pc, uint(0x8)], + ]); + const mangledInstance = die(1170, DW_TAG_inlined_subroutine, [ + [DW_AT_abstract_origin, ref(1150)], + [DW_AT_low_pc, uint(0x18)], + [DW_AT_high_pc, uint(0x8)], + ]); + const nameless = die(1180, DW_TAG_inlined_subroutine, [ + [DW_AT_low_pc, uint(0x20)], + [DW_AT_high_pc, uint(0x8)], + ]); + const fn = die( + 1120, + DW_TAG_subprogram, + [ + [DW_AT_name, str('host')], + [DW_AT_low_pc, uint(0x10)], + [DW_AT_high_pc, uint(0x20)], + ], + [instance, mangledInstance, nameless], + ); + const cu = die(1100, DW_TAG_compile_unit, [], [fn, declaration, abstract, mangledOnly]); + const index = new ScopeIndex(debugInfoOf(cu)); + + assert.strictEqual(index.inlineScopesAt(0x12)[0].name, 'wrapping_add'); + assert.strictEqual(index.inlineScopesAt(0x1a)[0].name, '_ZN4core3fmt5writeE'); + assert.strictEqual(index.inlineScopesAt(0x22)[0].name, undefined); + }); + }); }); diff --git a/test/wasmNames.test.ts b/test/wasmNames.test.ts new file mode 100644 index 0000000..b32c391 --- /dev/null +++ b/test/wasmNames.test.ts @@ -0,0 +1,153 @@ +/** + * The wasm symbol layer behind wasm-level call-stack frames (docs/callstack.md, + * C4): the `name` custom section, the import count that maps body order to + * function index, and Rust legacy demangling. + * + * Real fixtures pin the mapping (a name read for a body must be the name of + * THAT body), and hand-built sections pin the leniency: a truncated name + * section must degrade to the names read so far, never throw. + */ + +import * as assert from 'assert'; +import * as fs from 'fs'; +import * as path from 'path'; +import { + demangleRust, + functionNames, + importedFunctionCount, +} from '../src/wasm/names'; +import { Disassembly } from '../src/wasm/Disassembly'; + +const FIXTURES = path.join(__dirname, '..', '..', 'test', 'fixtures'); +const read = (name: string): Uint8Array => new Uint8Array(fs.readFileSync(path.join(FIXTURES, name))); + +/** A wasm module with just a header and one custom section. */ +function moduleWithCustomSection(name: string, payload: number[]): Uint8Array { + const nameBytes = Buffer.from(name, 'utf8'); + const content = [nameBytes.length, ...nameBytes, ...payload]; + return new Uint8Array([ + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, // header + 0x00, content.length, ...content, // custom section + ]); +} + +/** + * A `name` section carrying only a function-name subsection. `claimed` + * overstates the entry count, which is what a truncated section looks like. + */ +function nameSection(entries: [number, string][], claimed = entries.length): Uint8Array { + const map: number[] = [claimed]; + for (const [index, name] of entries) { + const bytes = Buffer.from(name, 'utf8'); + map.push(index, bytes.length, ...bytes); + } + return moduleWithCustomSection('name', [1, map.length, ...map]); +} + +describe('wasm function names', () => { + describe('functionNames', () => { + it('reads the function-name map of a real contract', () => { + const names = functionNames(read('stepper-debug.wasm')); + assert.strictEqual(names.get(0), '_ZN7stepper6triple17h35eddc3334b434dbE'); + assert.strictEqual(names.get(1), 'sum_triples'); + }); + + it('is empty for a module with no name section', () => { + assert.strictEqual(functionNames(read('composite.wasm')).size, 0); + }); + + it('reads what it can from a truncated name section instead of throwing', () => { + const entries: [number, string][] = [ + [0, 'first'], + [1, 'second'], + ]; + assert.deepStrictEqual([...functionNames(nameSection(entries))], entries); + // A map claiming four entries but holding two: the two survive. + assert.deepStrictEqual([...functionNames(nameSection(entries, 4))], entries); + }); + + it('degrades to empty on a malformed section rather than failing a session', () => { + // A subsection claiming more bytes than the section holds… + assert.strictEqual(functionNames(moduleWithCustomSection('name', [1, 99, 1])).size, 0); + // …a name whose length runs past the payload… + assert.strictEqual(functionNames(moduleWithCustomSection('name', [1, 4, 1, 0, 40, 0x66])).size, 0); + // …and a subsection header cut off after its id. + assert.strictEqual(functionNames(moduleWithCustomSection('name', [1])).size, 0); + }); + + it('skips subsections that are not the function-name map', () => { + // Subsection 0 is the module name; the function map follows it. + const moduleName = [0, 3, 2, 0x68, 0x69]; + const functions = [1, 5, 1, 7, 2, 0x66, 0x6e]; + const names = functionNames(moduleWithCustomSection('name', [...moduleName, ...functions])); + assert.deepStrictEqual([...names], [[7, 'fn']]); + }); + }); + + describe('importedFunctionCount', () => { + it('counts the imported host functions of a real contract', () => { + // increment-debug.wasm imports three host functions; the arithmetic-only + // fixtures import none at all (they carry no import section). + assert.strictEqual(importedFunctionCount(read('increment-debug.wasm')), 3); + assert.strictEqual(importedFunctionCount(read('stepper-debug.wasm')), 0); + }); + + it('offsets body order into function-index space', () => { + // The i-th function body is function index importCount + i, so the name a + // range reports must be the name of that body's own function. stepper's + // three bodies are `triple`, the `#[contractimpl]` wrapper, and the SDK's + // section shim, in that order. + const bytes = read('stepper-debug.wasm'); + const ranges = Disassembly.fromWasm(bytes).functionRanges; + assert.strictEqual(ranges[0].index, importedFunctionCount(bytes)); + assert.strictEqual(ranges[0].name, 'stepper::triple'); + assert.strictEqual(ranges[1].name, 'sum_triples'); + assert.strictEqual(ranges[1].index, 1); + }); + + it('leaves a range unnamed when the module carries no name section', () => { + for (const range of Disassembly.fromWasm(read('composite.wasm')).functionRanges) { + assert.strictEqual(range.name, undefined); + assert.strictEqual(typeof range.index, 'number'); + } + }); + + it('names nothing at all for a trace-derived disassembly', () => { + // Disassembly.fromTrace knows no function structure, so there are no + // ranges to name — the wasm-level frame ladder ends at the address. + const model = { records: [{ pos: 4, instr: ['nop'] }] } as never; + assert.deepStrictEqual(Disassembly.fromTrace(model).functionRanges, []); + }); + }); + + describe('demangleRust', () => { + it('demangles a legacy symbol and drops its hash segment', () => { + assert.strictEqual(demangleRust('_ZN7control7Control10while_call17h0b04c88804cf85f6E'), 'control::Control::while_call'); + assert.strictEqual(demangleRust('_ZN7control4bump17h2628dce790f861d2E'), 'control::bump'); + }); + + it('decodes the $…$ escapes and `..` path separators', () => { + assert.strictEqual( + demangleRust('_ZN60_$LT$soroban_sdk..env..Env$u20$as$u20$core..clone..Clone$GT$5clone17h1357aacfed26b0c7E'), + '::clone', + ); + assert.strictEqual(demangleRust('_ZN1a5b$C$c17h0000000000000000E'), 'a::b,c'); + }); + + it('passes through anything that is not legacy-mangled', () => { + // In order: a plain symbol, a v0-mangled one (documented as not demangled), + // the empty string, a body that is not length-prefixed, a length running + // past the end, and a `_ZN…E` with no segments at all. + for (const symbol of [ + 'sum_triples', + '_RNvC7control4bump', + '', + '_ZNnot_a_lengthE', + '_ZN99tooshortE', + '_ZNE', + ]) { + assert.strictEqual(demangleRust(symbol), symbol); + } + }); + }); +}); From e98b3263c1a864c0631d0b45d32eb65e6798f9e3 Mon Sep 17 00:00:00 2001 From: Raoul Date: Fri, 21 Aug 2026 10:20:26 +0000 Subject: [PATCH 02/13] refactor!: rename everything user-facing from soroban to stellar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The extension is published as `stellar-debugger`, so the identifiers a user types or reads should not say `soroban`. Every one of them is a breaking change after the first public release and free before it, which is why they all move now: the debug type is `"type": "stellar"`, the settings are `stellar.kometNode.path` and `stellar.cliPath` (the old `soroban.stellar.path` read badly under any product name), the command is `stellar.debug`, the CLIs are `stellar-trace` and `stellar-dap`, and the thread label is `stellar-vm [n/m]`. Launch-config names, snippets, error messages, docs and examples follow. Internal identifiers deliberately keep the name — `SorobanDebugSession`, `SorobanLaunchArgs`, `src/soroban/**` — because they refer to the Soroban protocol layer rather than to the product, and renaming them would churn the tree without changing anything a user sees. Prose keeps "Soroban" wherever it names the platform. The CLI docs also state that the marketplace build does not install `stellar-trace` or `stellar-dap`; they are built from this repository. --- .devcontainer/devcontainer.json | 2 +- docs/dap-cli-internal.md | 2 +- docs/dap-cli.md | 20 +++++++------ docs/debug-config.md | 20 ++++++------- docs/state-inspection.md | 2 +- docs/trace-cli-internal.md | 4 +-- docs/trace-cli.md | 24 ++++++++------- examples/.vscode/launch.json | 36 +++++++++++----------- examples/README.md | 18 +++++------ package-lock.json | 4 +-- package.json | 40 ++++++++++++------------- src/cli/flags.ts | 2 +- src/cli/shell.ts | 2 +- src/debugAdapter/SorobanDebugSession.ts | 2 +- src/debugAdapter/types.ts | 2 +- src/extension.ts | 26 ++++++++-------- src/pipeline/config.ts | 2 +- src/server/cliArgs.ts | 14 ++++----- src/server/dapServer.ts | 2 +- src/server/main.ts | 2 +- src/trace/cliArgs.ts | 22 +++++++------- src/trace/main.ts | 2 +- test/dap.test.ts | 4 +-- test/dapControlStepping.test.ts | 2 +- test/dapFrames.test.ts | 4 +-- test/dapLedger.test.ts | 2 +- test/dapMemoryVariables.test.ts | 2 +- test/dapServer.test.ts | 4 +-- test/dapStepping.test.ts | 2 +- test/dapVariables.test.ts | 2 +- test/multitxConfig.test.ts | 30 +++++++++---------- test/sequenceRunner.e2e.test.ts | 10 +++---- test/sequenceRunner.test.ts | 12 ++++---- test/serverCli.test.ts | 4 +-- test/traceCli.test.ts | 4 +-- 35 files changed, 168 insertions(+), 164 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 8e29ee5..f0858b8 100755 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,5 +1,5 @@ { - "name": "simbolik-komet", + "name": "stellar-debugger", "build": { "dockerfile": "Dockerfile" }, diff --git a/docs/dap-cli-internal.md b/docs/dap-cli-internal.md index 14852c5..5cfc554 100644 --- a/docs/dap-cli-internal.md +++ b/docs/dap-cli-internal.md @@ -1,4 +1,4 @@ -# `soroban-dap` internals +# `stellar-dap` internals > **Audience:** `contributor` · `maintainer` · `integrator` (internals) > diff --git a/docs/dap-cli.md b/docs/dap-cli.md index be91d2d..74b8706 100644 --- a/docs/dap-cli.md +++ b/docs/dap-cli.md @@ -1,13 +1,13 @@ -# `soroban-dap` — standalone DAP server (TCP) +# `stellar-dap` — standalone DAP server (TCP) > **Audience:** `other-editor user` (nvim-dap / IntelliJ / Emacs) · `tooling integrator` > -> **TL;DR:** `soroban-dap` serves the Soroban debug adapter over a TCP socket +> **TL;DR:** `stellar-dap` serves the Stellar debug adapter over a TCP socket > (DAP's canonical "server mode"), so debuggers *other* than VS Code can drive > it. For the one-shot JSONL trace CLI, see [`trace-cli.md`](./trace-cli.md); for > internals, see [`dap-cli-internal.md`](./dap-cli-internal.md). -`soroban-dap` runs the debug adapter as a TCP server. Each client connection +`stellar-dap` runs the debug adapter as a TCP server. Each client connection gets its own independent session; the launch configuration is sent by the client over the wire, exactly as in the editor. @@ -19,11 +19,13 @@ npm run build ``` This produces `dist/dap-server.js`. Run it directly with -`node dist/dap-server.js …`, or expose it as the `soroban-dap` command by +`node dist/dap-server.js …`, or expose it as the `stellar-dap` command by installing the package (`npm install -g .`, or `npm link` for local development). (`npm run build` also builds the trace CLI — see [`trace-cli.md`](./trace-cli.md).) +The marketplace build of the extension does not install these CLIs; they are built from this repository. + Debugging a real contract needs the same tools as the editor — the [Stellar CLI](https://developers.stellar.org/docs/tools/cli) and [komet-node](https://github.com/runtimeverification/komet-node) on your `PATH` @@ -32,13 +34,13 @@ with a recorded `rawTrace` (offline replay). ## Usage -`soroban-dap --help`: +`stellar-dap --help`: ```text -soroban-dap — serve the Soroban debug adapter over a TCP socket +stellar-dap — serve the Stellar debug adapter over a TCP socket Usage: - soroban-dap [--port ] [--host ] + stellar-dap [--port ] [--host ] Options: --port TCP port to listen on (default 4711). @@ -63,9 +65,9 @@ launch configuration at the port with `debugServer`: ```jsonc { - "type": "soroban", + "type": "stellar", "request": "launch", - "name": "Attach to soroban-dap", + "name": "Attach to stellar-dap", "debugServer": 4711, "rawTrace": "test/fixtures/adder-debug.trace.jsonl", "wasmPath": "test/fixtures/adder-debug.wasm" diff --git a/docs/debug-config.md b/docs/debug-config.md index 04c0840..3c62733 100644 --- a/docs/debug-config.md +++ b/docs/debug-config.md @@ -1,8 +1,8 @@ # Debug configuration reference -> **Audience:** `soroban developer` · `getting started` · `writing launch.json` +> **Audience:** `stellar contract developer` · `getting started` · `writing launch.json` > -> **TL;DR:** A `soroban` launch configuration describes an ordered sequence of +> **TL;DR:** A `stellar` launch configuration describes an ordered sequence of > transactions run against one fresh local ledger, and names which transaction > to trace and debug. You set up whatever state your call depends on (deploy > other contracts, run a constructor, seed storage) as earlier transactions, @@ -29,7 +29,7 @@ A configuration is one JSON object in your `.vscode/launch.json` under ```jsonc { - "type": "soroban", + "type": "stellar", "request": "launch", "name": "…", // shown in the Run and Debug dropdown "transactions": [ … ], // the ordered sequence (required) @@ -76,7 +76,7 @@ Notes on semantics that shape how you author a sequence: | `id` | ✅ | Handle name. Later `invoke` steps reference it via their `contract` field, and `trace` can select this deploy's transaction by this id. Must be unique. | | `contract` | one of `contract`/`wasm` | Path to a contract crate directory (containing `Cargo.toml`) to build. | | `wasm` | one of `contract`/`wasm` | Path to a prebuilt `.wasm`. Overrides building from `contract`. | -| `buildCommand` | | Command used to build a `contract` directory. Defaults to `stellar contract build` (or the `soroban.stellar.path` setting). Ignored when `wasm` is given. | +| `buildCommand` | | Command used to build a `contract` directory. Defaults to `stellar contract build` (or the `stellar.cliPath` setting). Ignored when `wasm` is given. | | `debugInfo` | | Build with DWARF debug info for Rust source mapping (default `true`). Set `false` to debug at the wasm level only. Ignored when `wasm` is given. | ### `invoke` step @@ -149,7 +149,7 @@ work in path fields like `contract` and `wasm`. | `wasmPath` | Replay mode only: a `.wasm` supplying disassembly and DWARF source mapping for the replayed trace. | Two VS Code settings let you point at executables that aren't on your `PATH`: -`soroban.stellar.path` and `soroban.kometNode.path`. +`stellar.cliPath` and `stellar.kometNode.path`. ## Replay mode @@ -160,7 +160,7 @@ wasm-level fallback: ```jsonc { - "type": "soroban", + "type": "stellar", "request": "launch", "name": "Replay add(4, 3)", "rawTrace": "${workspaceFolder}/traces/add.trace.jsonl", @@ -168,7 +168,7 @@ wasm-level fallback: } ``` -Record a trace with the [`soroban-trace`](./trace-cli.md) CLI. +Record a trace with the [`stellar-trace`](./trace-cli.md) CLI. ## Examples @@ -180,7 +180,7 @@ defaults to the last step. ```jsonc { - "type": "soroban", + "type": "stellar", "request": "launch", "name": "Debug add(1, 2)", "transactions": [ @@ -200,7 +200,7 @@ setup runs but the session opens on the call you care about. ```jsonc { - "type": "soroban", + "type": "stellar", "request": "launch", "name": "Debug router.swap", "transactions": [ @@ -233,7 +233,7 @@ named `args`: ```jsonc { - "type": "soroban", + "type": "stellar", "request": "launch", "name": "Debug pool.submit", "transactions": [ diff --git a/docs/state-inspection.md b/docs/state-inspection.md index 386f3b4..4bc3791 100644 --- a/docs/state-inspection.md +++ b/docs/state-inspection.md @@ -4,7 +4,7 @@ > > **TL;DR:** The precise contract for what state the debugger shows at a replay cursor beyond the wasm value stack and locals — the module's **wasm globals** (G1–G4) and the **Stellar ledger** (L1–L14): contract storage across all three durabilities with TTLs, account balances, ledger sequence/timestamp, contract instance metadata, the host object table, and the contract-call stack. Defines the trace-record contract each rule depends on, how state is reconstructed at an arbitrary cursor (including rollback of failed sub-calls), and how every rule degrades when a trace predates the field it needs. -The contract between the trace producer (komet's K semantics, carried verbatim by komet-node) and the debugger's state views: the `Globals` and `Ledger` scopes in the VS Code Variables view, the same scopes over the DAP server, and the `globals`/`ledger` projections in the `soroban-trace` CLI. +The contract between the trace producer (komet's K semantics, carried verbatim by komet-node) and the debugger's state views: the `Globals` and `Ledger` scopes in the VS Code Variables view, the same scopes over the DAP server, and the `globals`/`ledger` projections in the `stellar-trace` CLI. The test suite (`test/trace.test.ts`, `test/ledgerImage.test.ts`, `test/scvalJson.test.ts`, `test/dapLedger.test.ts`, `test/prop/ledgerImage.property.test.ts`) pins these rules; every rule ID below is cited by at least one test. For how the cursor *moves*, see [`stepping.md`](stepping.md). This document is only about what is *visible* once it has come to rest. diff --git a/docs/trace-cli-internal.md b/docs/trace-cli-internal.md index 7c3a231..30a7ac0 100644 --- a/docs/trace-cli-internal.md +++ b/docs/trace-cli-internal.md @@ -1,8 +1,8 @@ -# `soroban-trace` internals +# `stellar-trace` internals > **Audience:** `contributor` · `maintainer` · `integrator` (internals) > -> **TL;DR:** How `soroban-trace` turns a resolved trace into Rust-source-level +> **TL;DR:** How `stellar-trace` turns a resolved trace into Rust-source-level > JSONL, and the `vscode`-free shared core it sits on (also used by the DAP > server — see [`dap-cli-internal.md`](./dap-cli-internal.md)). Documents the > `SourceStop`/`TraceVar` schema and the ground-truth fixtures. User-facing diff --git a/docs/trace-cli.md b/docs/trace-cli.md index e0e7967..9273a13 100644 --- a/docs/trace-cli.md +++ b/docs/trace-cli.md @@ -1,9 +1,9 @@ -# `soroban-trace` — Rust-level execution trace (CLI) +# `stellar-trace` — Rust-level execution trace (CLI) -> **Audience:** `soroban developer` (outside VS Code) · `CI / scripting user` · +> **Audience:** `stellar contract developer` (outside VS Code) · `CI / scripting user` · > `AI agent integrator` > -> **TL;DR:** `soroban-trace` builds and runs a contract once and prints a +> **TL;DR:** `stellar-trace` builds and runs a contract once and prints a > Rust-source-level execution trace as JSONL — one record per source statement, > with the in-scope variables at that point. Built for scripts, CI, and AI > agents that want to *read* an execution rather than step through it @@ -11,7 +11,7 @@ > the standalone DAP server, see [`dap-cli.md`](./dap-cli.md); for internals, see > [`trace-cli-internal.md`](./trace-cli-internal.md). -`soroban-trace` is a thin front-end over the same replay engine the VS Code +`stellar-trace` is a thin front-end over the same replay engine the VS Code extension uses. It emits one JSON object per line: a leading `meta` record, one `stop` per source-level statement (in execution order), and a trailing `result`. @@ -24,10 +24,12 @@ npm run build ``` This produces `dist/trace.js`. Run it directly with `node dist/trace.js …`, or -expose it as the `soroban-trace` command by installing the package +expose it as the `stellar-trace` command by installing the package (`npm install -g .`, or `npm link` for local development). (`npm run build` also builds the DAP server — see [`dap-cli.md`](./dap-cli.md).) +The marketplace build of the extension does not install these CLIs; they are built from this repository. + Live mode (the primary use below) builds and runs a contract, so it needs the same tools as the editor — the [Stellar CLI](https://developers.stellar.org/docs/tools/cli) and @@ -37,14 +39,14 @@ needs no toolchain. ## Usage -`soroban-trace --help`: +`stellar-trace --help`: ```text -soroban-trace — emit a Rust source-level execution trace as JSONL +stellar-trace — emit a Rust source-level execution trace as JSONL Usage: - soroban-trace --raw-trace [--wasm ] [options] (offline replay) - soroban-trace --contract --function [options] (build & run live) + stellar-trace --raw-trace [--wasm ] [options] (offline replay) + stellar-trace --contract --function [options] (build & run live) Options: --raw-trace Recorded JSONL trace to replay (offline mode). @@ -59,8 +61,8 @@ Options: -h, --help Show this help. Examples: - soroban-trace --raw-trace run.jsonl --wasm contract.wasm - soroban-trace --contract . --function add --args-json '{"a":1,"b":2}' + stellar-trace --raw-trace run.jsonl --wasm contract.wasm + stellar-trace --contract . --function add --args-json '{"a":1,"b":2}' ``` ## Quick start (build → deploy → run → trace) diff --git a/examples/.vscode/launch.json b/examples/.vscode/launch.json index afca173..2463db2 100644 --- a/examples/.vscode/launch.json +++ b/examples/.vscode/launch.json @@ -2,21 +2,21 @@ "version": "0.2.0", "configurations": [ { - "name": "Soroban: Replay add(4, 3) trace", - "type": "soroban", + "name": "Stellar: Replay add(4, 3) trace", + "type": "stellar", "request": "launch", "rawTrace": "${workspaceFolder}/traces/add.trace.jsonl" }, { - "name": "Soroban: Replay add(4, 3) with symbols", - "type": "soroban", + "name": "Stellar: Replay add(4, 3) with symbols", + "type": "stellar", "request": "launch", "rawTrace": "${workspaceFolder}/../test/fixtures/adder-debug.trace.jsonl", "wasmPath": "${workspaceFolder}/../test/fixtures/adder-debug.wasm" }, { - "name": "Soroban: Debug store(42) [live pipeline]", - "type": "soroban", + "name": "Stellar: Debug store(42) [live pipeline]", + "type": "stellar", "request": "launch", "transactions": [ { "kind": "deploy", "id": "greeter", "contract": "${workspaceFolder}/greeter" }, @@ -24,8 +24,8 @@ ] }, { - "name": "Soroban: Debug add(1, 2) [live pipeline]", - "type": "soroban", + "name": "Stellar: Debug add(1, 2) [live pipeline]", + "type": "stellar", "request": "launch", "transactions": [ { "kind": "deploy", "id": "adder", "contract": "${workspaceFolder}/adder" }, @@ -33,8 +33,8 @@ ] }, { - "name": "Soroban: Debug increment(5) [live pipeline]", - "type": "soroban", + "name": "Stellar: Debug increment(5) [live pipeline]", + "type": "stellar", "request": "launch", "transactions": [ { "kind": "deploy", "id": "increment", "contract": "${workspaceFolder}/increment" }, @@ -42,29 +42,29 @@ ] }, { - "name": "Soroban: Replay control while_call(3) with symbols", - "type": "soroban", + "name": "Stellar: Replay control while_call(3) with symbols", + "type": "stellar", "request": "launch", "rawTrace": "${workspaceFolder}/../test/fixtures/control-while_call.trace.jsonl", "wasmPath": "${workspaceFolder}/../test/fixtures/control-debug.wasm" }, { - "name": "Soroban: Replay control count(3) with symbols", - "type": "soroban", + "name": "Stellar: Replay control count(3) with symbols", + "type": "stellar", "request": "launch", "rawTrace": "${workspaceFolder}/../test/fixtures/control-count.trace.jsonl", "wasmPath": "${workspaceFolder}/../test/fixtures/control-debug.wasm" }, { - "name": "Soroban: Replay control branch(3) with symbols", - "type": "soroban", + "name": "Stellar: Replay control branch(3) with symbols", + "type": "stellar", "request": "launch", "rawTrace": "${workspaceFolder}/../test/fixtures/control-branch.trace.jsonl", "wasmPath": "${workspaceFolder}/../test/fixtures/control-debug.wasm" }, { - "name": "Soroban: Debug control while_call(3) [live pipeline]", - "type": "soroban", + "name": "Stellar: Debug control while_call(3) [live pipeline]", + "type": "stellar", "request": "launch", "transactions": [ { "kind": "deploy", "id": "control", "contract": "${workspaceFolder}/control" }, diff --git a/examples/README.md b/examples/README.md index ef05539..3643af3 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,13 +1,13 @@ -# Soroban Debugger — example workspace +# Stellar Debugger — example workspace -> **Audience:** `new user` · `soroban developer` (getting started) +> **Audience:** `new user` · `stellar contract developer` (getting started) > > **TL;DR:** A guided tour of the ready-to-run example contracts and launch > configs. Start with the zero-dependency **Replay … with symbols** configs to > see source-level, forward-and-backward debugging in seconds — no toolchain > needed — then graduate to the full build-and-run pipeline. -This folder is a **self-contained example workspace** for the Soroban Debugger +This folder is a **self-contained example workspace** for the Stellar Debugger (komet) extension. Pressing **F5** ("Run Extension") in the extension repo opens this folder in an Extension Development Host with the extension already loaded, so you have a real Soroban project to debug immediately. @@ -39,21 +39,21 @@ Each contract is an independent crate (its own `Cargo.toml`/`Cargo.lock`/ Open the Run and Debug view and pick a config from `.vscode/launch.json`: -1. **Soroban: Replay add(4, 3) with symbols** — zero dependencies. Replays the +1. **Stellar: Replay add(4, 3) with symbols** — zero dependencies. Replays the bundled trace together with its matching debug wasm: stack frames open `adder/src/lib.rs`, breakpoints verify on Rust lines (sliding forward to the nearest executed line), stepping is statement-granular, and right-clicking the stack frame offers **Open Disassembly View** (annotated wasm, instruction breakpoints, instruction-granular stepping — also backwards). Start here. -2. **Soroban: Replay add(4, 3) trace** — the same trace without the wasm: the +2. **Stellar: Replay add(4, 3) trace** — the same trace without the wasm: the no-DWARF fallback. Frames carry only an instruction pointer; you debug in the Disassembly View. -3. **Soroban: Replay control while_call(3) / count(3) / branch(3) with symbols** +3. **Stellar: Replay control while_call(3) / count(3) / branch(3) with symbols** — zero-dependency replays of the control fixtures, one per Rust construct: step into `bump` and back out of a `while` loop, watch a `for` body stop once per iteration, or see an `if`/`else` enter only the taken arm. -4. **Soroban: Debug store(42) / add(1, 2) / increment(5) / control while_call(3)** +4. **Stellar: Debug store(42) / add(1, 2) / increment(5) / control while_call(3)** — the full turnkey pipeline: builds the crate **with DWARF debug info at opt-level 0** (the extension injects `CARGO_PROFILE_RELEASE_DEBUG=true` / `CARGO_PROFILE_RELEASE_STRIP=none` / `CARGO_PROFILE_RELEASE_OPT_LEVEL=0`; no @@ -75,9 +75,9 @@ then add a launch config whose `transactions` deploy it and invoke a function: ```jsonc { - "type": "soroban", + "type": "stellar", "request": "launch", - "name": "Soroban: Debug my_fn", + "name": "Stellar: Debug my_fn", "transactions": [ { "kind": "deploy", "id": "mine", "contract": "${workspaceFolder}/my_crate" }, { "kind": "invoke", "contract": "mine", "function": "my_fn", "args": { "x": 1 } } diff --git a/package-lock.json b/package-lock.json index 6280d76..7fce580 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "simbolik-komet", + "name": "stellar-debugger", "version": "0.0.1", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "simbolik-komet", + "name": "stellar-debugger", "version": "0.0.1", "license": "BSD-3-Clause", "dependencies": { diff --git a/package.json b/package.json index 0b5aa1f..f7a465f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { - "name": "simbolik-komet", - "displayName": "Soroban Debugger (komet)", + "name": "stellar-debugger", + "displayName": "Stellar Debugger", "description": "Time-travel debugger for Stellar/Soroban smart contracts, backed by komet-node", "version": "0.0.1", "publisher": "runtimeverification", @@ -22,22 +22,22 @@ ], "main": "./dist/extension.js", "bin": { - "soroban-dap": "dist/dap-server.js", - "soroban-trace": "dist/trace.js" + "stellar-dap": "dist/dap-server.js", + "stellar-trace": "dist/trace.js" }, "activationEvents": [ "onDebug" ], "contributes": { "configuration": { - "title": "Soroban Debugger (komet)", + "title": "Stellar Debugger", "properties": { - "soroban.kometNode.path": { + "stellar.kometNode.path": { "type": "string", "default": "komet-node", "markdownDescription": "Path to the `komet-node` executable. Defaults to `komet-node` found on your `PATH`; set an absolute path to override. A launch configuration's `node.command` takes precedence over this setting." }, - "soroban.stellar.path": { + "stellar.cliPath": { "type": "string", "default": "stellar", "markdownDescription": "Path to the `stellar` CLI executable, used to build contracts (as ` contract build`). Defaults to `stellar` found on your `PATH`; set an absolute path to override. A launch configuration's `buildCommand` takes precedence over this setting." @@ -46,9 +46,9 @@ }, "commands": [ { - "command": "soroban.debug", - "title": "Soroban: Debug Contract Function", - "category": "Soroban" + "command": "stellar.debug", + "title": "Stellar: Debug Contract Function", + "category": "Stellar" } ], "breakpoints": [ @@ -58,8 +58,8 @@ ], "debuggers": [ { - "type": "soroban", - "label": "Soroban (komet)", + "type": "stellar", + "label": "Stellar (komet)", "languages": [ "rust" ], @@ -101,7 +101,7 @@ }, "buildCommand": { "type": "string", - "markdownDescription": "`deploy` only: command used to build a `contract` directory. Overrides the `soroban.stellar.path` setting. Defaults to ` contract build`." + "markdownDescription": "`deploy` only: command used to build a `contract` directory. Overrides the `stellar.cliPath` setting. Defaults to ` contract build`." }, "debugInfo": { "type": "boolean", @@ -113,7 +113,7 @@ "description": "invoke only: name of the contract function to call." }, "args": { - "markdownDescription": "`invoke` only: arguments, as an object keyed by the function's parameter names (composites, enums `{ \"tag\": ... }`, tuples/vecs as arrays, `i128` as a decimal string, addresses as `G…`/`C…` strings). Values are encoded against the contract's own spec. The tokens `${sourceAddress}` and `${contract:}` are expanded inside string values." + "markdownDescription": "`invoke` only: arguments, as an object keyed by the function's parameter names (composites, enums `{ \"tag\": ... }`, tuples/vecs as arrays, `i128` as a decimal string, addresses as `G\u2026`/`C\u2026` strings). Values are encoded against the contract's own spec. The tokens `${sourceAddress}` and `${contract:}` are expanded inside string values." } } } @@ -153,7 +153,7 @@ }, "command": { "type": "string", - "description": "Path/command used to spawn komet-node. Overrides the `soroban.kometNode.path` setting (which defaults to `komet-node` on your PATH)." + "description": "Path/command used to spawn komet-node. Overrides the `stellar.kometNode.path` setting (which defaults to `komet-node` on your PATH)." }, "ioDir": { "type": "string", @@ -181,9 +181,9 @@ }, "initialConfigurations": [ { - "type": "soroban", + "type": "stellar", "request": "launch", - "name": "Soroban: Debug add(1, 2)", + "name": "Stellar: Debug add(1, 2)", "transactions": [ { "kind": "deploy", @@ -204,12 +204,12 @@ ], "configurationSnippets": [ { - "label": "Soroban: Debug contract function", + "label": "Stellar: Debug contract function", "description": "Build, deploy, and time-travel debug a Soroban contract function", "body": { - "type": "soroban", + "type": "stellar", "request": "launch", - "name": "Soroban: Debug ${1:function}", + "name": "Stellar: Debug ${1:function}", "transactions": [ { "kind": "deploy", diff --git a/src/cli/flags.ts b/src/cli/flags.ts index a96a9fd..b620674 100644 --- a/src/cli/flags.ts +++ b/src/cli/flags.ts @@ -1,5 +1,5 @@ /** - * The argv tokenizer both CLI front doors (`soroban-trace`, `soroban-dap`) parse + * The argv tokenizer both CLI front doors (`stellar-trace`, `stellar-dap`) parse * with, so they agree on what an option looks like and on how a bad one reads. * * Deliberately minimal — no `--flag=value`, no clustering, no positionals: every diff --git a/src/cli/shell.ts b/src/cli/shell.ts index be4ff9d..7dcaed7 100644 --- a/src/cli/shell.ts +++ b/src/cli/shell.ts @@ -1,5 +1,5 @@ /** - * The process shell both CLI entry points (`soroban-trace`, `soroban-dap`) run + * The process shell both CLI entry points (`stellar-trace`, `stellar-dap`) run * their parse result through, so they agree on the exit codes and on which * stream each kind of output goes to: * diff --git a/src/debugAdapter/SorobanDebugSession.ts b/src/debugAdapter/SorobanDebugSession.ts index 261e355..9575ae3 100644 --- a/src/debugAdapter/SorobanDebugSession.ts +++ b/src/debugAdapter/SorobanDebugSession.ts @@ -318,7 +318,7 @@ export class SorobanDebugSession extends DebugSession { protected threadsRequest(response: DebugProtocol.ThreadsResponse): void { const position = this.model && !this.model.isEmpty ? ` [${this.model.cursor}/${this.model.length - 1}]` : ''; - response.body = { threads: [new Thread(THREAD_ID, `soroban-vm${position}`)] }; + response.body = { threads: [new Thread(THREAD_ID, `stellar-vm${position}`)] }; this.sendResponse(response); } diff --git a/src/debugAdapter/types.ts b/src/debugAdapter/types.ts index 8f4500a..28cd488 100644 --- a/src/debugAdapter/types.ts +++ b/src/debugAdapter/types.ts @@ -12,7 +12,7 @@ import { VariableResolver } from '../sourcemap/VariableResolver'; import { Disassembly } from '../wasm/Disassembly'; import { TxStep, TraceSelector } from '../pipeline/config'; -/** Attributes of a `soroban` launch configuration (mirrors package.json). */ +/** Attributes of a `stellar` launch configuration (mirrors package.json). */ export interface SorobanLaunchArgs extends DebugProtocol.LaunchRequestArguments { /** * The ordered transaction sequence (deploy / invoke steps) to run. Build diff --git a/src/extension.ts b/src/extension.ts index d5bbfbf..74c5f34 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,5 +1,5 @@ /** - * Extension entry point. Wires the Soroban debug type into VSCode: + * Extension entry point. Wires the Stellar debug type into VSCode: * - a DebugConfigurationProvider that fills in sensible defaults, and * - an inline DebugAdapterDescriptorFactory that runs the trace-replay * DebugSession in-process (the trace is fully materialized, so there is no @@ -17,9 +17,9 @@ import { SorobanLaunchArgs } from './debugAdapter/types'; export function activate(context: vscode.ExtensionContext): void { const provider = new SorobanConfigurationProvider(); context.subscriptions.push( - vscode.debug.registerDebugConfigurationProvider('soroban', provider), - vscode.debug.registerDebugAdapterDescriptorFactory('soroban', new SorobanAdapterFactory()), - vscode.commands.registerCommand('soroban.debug', () => startDebugFromActiveEditor()), + vscode.debug.registerDebugConfigurationProvider('stellar', provider), + vscode.debug.registerDebugAdapterDescriptorFactory('stellar', new SorobanAdapterFactory()), + vscode.commands.registerCommand('stellar.debug', () => startDebugFromActiveEditor()), ); } @@ -45,9 +45,9 @@ class SorobanConfigurationProvider implements vscode.DebugConfigurationProvider if (!config.type && !config.request && !config.name) { // Launched with no launch.json: offer a minimal default if a function name // can't be inferred, bail with a hint. - config.type = 'soroban'; + config.type = 'stellar'; config.request = 'launch'; - config.name = 'Soroban: Debug'; + config.name = 'Stellar: Debug'; } if (config.request === undefined) { config.request = 'launch'; @@ -55,7 +55,7 @@ class SorobanConfigurationProvider implements vscode.DebugConfigurationProvider applyBinaryPaths(config, folder); if (!config.rawTrace && !Array.isArray(config.transactions)) { return vscode.window - .showErrorMessage('Soroban debug: a `transactions` array (or a `rawTrace` file) is required in the launch configuration.') + .showErrorMessage('Stellar debug: a `transactions` array (or a `rawTrace` file) is required in the launch configuration.') .then(() => undefined); } return config; @@ -65,7 +65,7 @@ class SorobanConfigurationProvider implements vscode.DebugConfigurationProvider /** * Resolve the locations of the external binaries the pipeline shells out to * (`komet-node` and the `stellar` CLI). A launch configuration's own fields win; - * otherwise fall back to the `soroban.*` settings, which default to the binaries + * otherwise fall back to the `stellar.*` settings, which default to the binaries * on `$PATH`. This keeps the `vscode`-free pipeline modules oblivious to VSCode * settings — they just receive a resolved command. */ @@ -73,7 +73,7 @@ function applyBinaryPaths( config: vscode.DebugConfiguration, folder: vscode.WorkspaceFolder | undefined, ): void { - const settings = vscode.workspace.getConfiguration('soroban', folder?.uri ?? null); + const settings = vscode.workspace.getConfiguration('stellar', folder?.uri ?? null); const kometNodePath = settings.get('kometNode.path')?.trim() || 'komet-node'; const stellarPath = settings.get('stellar.path')?.trim() || 'stellar'; @@ -83,7 +83,7 @@ function applyBinaryPaths( config.node.command = kometNodePath; } // Inject the resolved build command into any `deploy` step that doesn't set - // its own, so the `soroban.stellar.path` setting still applies under the + // its own, so the `stellar.cliPath` setting still applies under the // `transactions` schema. The build command runs through a shell, so quote a // path that contains spaces. const buildCommand = `${quoteForShell(stellarPath)} contract build`; @@ -103,7 +103,7 @@ function quoteForShell(p: string): string { async function startDebugFromActiveEditor(): Promise { const folder = vscode.workspace.workspaceFolders?.[0]; if (!folder) { - vscode.window.showErrorMessage('Soroban debug: open a workspace folder first.'); + vscode.window.showErrorMessage('Stellar debug: open a workspace folder first.'); return; } const fn = await vscode.window.showInputBox({ @@ -114,9 +114,9 @@ async function startDebugFromActiveEditor(): Promise { return; } await vscode.debug.startDebugging(folder, { - type: 'soroban', + type: 'stellar', request: 'launch', - name: `Soroban: Debug ${fn}`, + name: `Stellar: Debug ${fn}`, transactions: [ { kind: 'deploy', id: 'contract', contract: folder.uri.fsPath }, { kind: 'invoke', contract: 'contract', function: fn }, diff --git a/src/pipeline/config.ts b/src/pipeline/config.ts index addb16e..09909fd 100644 --- a/src/pipeline/config.ts +++ b/src/pipeline/config.ts @@ -1,5 +1,5 @@ /** - * Normalization of a `soroban` launch configuration into a canonical, + * Normalization of a `stellar` launch configuration into a canonical, * ordered transaction sequence. * * A launch config carries an explicit `transactions` array (deploy / invoke diff --git a/src/server/cliArgs.ts b/src/server/cliArgs.ts index baa7ea9..f8ac7f4 100644 --- a/src/server/cliArgs.ts +++ b/src/server/cliArgs.ts @@ -1,5 +1,5 @@ /** - * Argv parsing for the standalone TCP DAP server CLI (`soroban-dap`). + * Argv parsing for the standalone TCP DAP server CLI (`stellar-dap`). * * `parseServerArgs` resolves `--help`, validates `--host`/`--port`, and maps a * raw argv slice onto a discriminated union the (coverage-excluded) shell @@ -9,11 +9,11 @@ import { CliParse } from '../cli/shell'; import { FlagSpec, isNonNegativeInt, parseFlags, wantsHelp } from '../cli/flags'; -/** The `soroban-dap` help text. */ -export const SERVER_USAGE = `soroban-dap — serve the Soroban debug adapter over a TCP socket +/** The `stellar-dap` help text. */ +export const SERVER_USAGE = `stellar-dap — serve the Stellar debug adapter over a TCP socket Usage: - soroban-dap [--port ] [--host ] + stellar-dap [--port ] [--host ] Options: --port TCP port to listen on (default 4711). @@ -23,17 +23,17 @@ Options: Connect any DAP client to the port (e.g. VS Code "debugServer": ). `; -/** Outcome of parsing `soroban-dap` argv. */ +/** Outcome of parsing `stellar-dap` argv. */ export type ServerParse = CliParse<{ host?: string; port: number }>; -const HINT = "Run 'soroban-dap --help' for usage."; +const HINT = "Run 'stellar-dap --help' for usage."; const DEFAULT_PORT = 4711; const MAX_PORT = 65535; const FLAGS: FlagSpec = { value: ['--host', '--port'] }; /** - * Devex front door for `soroban-dap`: resolve `--help`, validate tokens and + * Devex front door for `stellar-dap`: resolve `--help`, validate tokens and * `--port`, and map argv onto a `ServerParse`. Pure. */ export function parseServerArgs(argv: string[]): ServerParse { diff --git a/src/server/dapServer.ts b/src/server/dapServer.ts index f0822cf..3a4ab20 100644 --- a/src/server/dapServer.ts +++ b/src/server/dapServer.ts @@ -1,5 +1,5 @@ /** - * Standalone TCP DAP server (`soroban-dap`) — docs/dap-cli-internal.md, "Interface 2". + * Standalone TCP DAP server (`stellar-dap`) — docs/dap-cli-internal.md, "Interface 2". * * Opens a `net.createServer`; for each connection it creates a fresh * `SorobanDebugSession(backendFor)` (the selector overload, so the backend can diff --git a/src/server/main.ts b/src/server/main.ts index b186e73..b8e3086 100644 --- a/src/server/main.ts +++ b/src/server/main.ts @@ -1,5 +1,5 @@ /** - * Thin CLI entry for the standalone TCP DAP server (`soroban-dap`). + * Thin CLI entry for the standalone TCP DAP server (`stellar-dap`). * * Parses argv with the pure `parseServerArgs`, then — for a `run` result — * starts the server and logs the listening address to stderr. Help and usage diff --git a/src/trace/cliArgs.ts b/src/trace/cliArgs.ts index e03895f..dd35ee7 100644 --- a/src/trace/cliArgs.ts +++ b/src/trace/cliArgs.ts @@ -1,5 +1,5 @@ /** - * Argv parsing for the one-shot trace CLI (`soroban-trace`). + * Argv parsing for the one-shot trace CLI (`stellar-trace`). * * `parseTraceArgs` is the devex front door: it resolves `--help`, validates * tokens and mode selection, and maps argv onto a discriminated union the @@ -11,12 +11,12 @@ import { SorobanLaunchArgs } from '../debugAdapter/types'; import { CliParse } from '../cli/shell'; import { FlagSpec, isNonNegativeInt, parseFlags, wantsHelp } from '../cli/flags'; -/** The `soroban-trace` help text. */ -export const TRACE_USAGE = `soroban-trace — emit a Rust source-level execution trace as JSONL +/** The `stellar-trace` help text. */ +export const TRACE_USAGE = `stellar-trace — emit a Rust source-level execution trace as JSONL Usage: - soroban-trace --raw-trace [--wasm ] [options] (offline replay) - soroban-trace --contract --function [options] (build & run live) + stellar-trace --raw-trace [--wasm ] [options] (offline replay) + stellar-trace --contract --function [options] (build & run live) Options: --raw-trace Recorded JSONL trace to replay (offline mode). @@ -32,11 +32,11 @@ Options: -h, --help Show this help. Examples: - soroban-trace --raw-trace run.jsonl --wasm contract.wasm - soroban-trace --contract . --function add --args-json '{"a":1,"b":2}' + stellar-trace --raw-trace run.jsonl --wasm contract.wasm + stellar-trace --contract . --function add --args-json '{"a":1,"b":2}' `; -/** The projection options `soroban-trace` passes through to `runCliTrace`. */ +/** The projection options `stellar-trace` passes through to `runCliTrace`. */ interface TraceOpts { maxDepth?: number; maxChildren?: number; @@ -44,7 +44,7 @@ interface TraceOpts { justMyCode?: boolean; } -/** Outcome of parsing `soroban-trace` argv. */ +/** Outcome of parsing `stellar-trace` argv. */ export type TraceParse = CliParse<{ launch: SorobanLaunchArgs; /** Echoed for the trace's meta record: the invoked function (live mode). */ @@ -55,7 +55,7 @@ export type TraceParse = CliParse<{ opts: TraceOpts; }>; -const HINT = "Run 'soroban-trace --help' for usage."; +const HINT = "Run 'stellar-trace --help' for usage."; const FLAGS: FlagSpec = { value: [ @@ -72,7 +72,7 @@ const FLAGS: FlagSpec = { }; /** - * Devex front door for `soroban-trace`: resolve `--help`, validate tokens and + * Devex front door for `stellar-trace`: resolve `--help`, validate tokens and * mode selection, and map argv onto a `TraceParse`. Pure. */ export function parseTraceArgs(argv: string[]): TraceParse { diff --git a/src/trace/main.ts b/src/trace/main.ts index 521fae7..a092612 100644 --- a/src/trace/main.ts +++ b/src/trace/main.ts @@ -1,5 +1,5 @@ /** - * Thin CLI entry for the one-shot trace projection (`soroban-trace`). + * Thin CLI entry for the one-shot trace projection (`stellar-trace`). * * Parses argv with the pure `parseTraceArgs`, then — for a `run` result — * resolves a trace through the selected backend, projects it to JSONL via diff --git a/test/dap.test.ts b/test/dap.test.ts index 181d0b2..c1eda59 100644 --- a/test/dap.test.ts +++ b/test/dap.test.ts @@ -21,7 +21,7 @@ describe('SorobanDebugSession (DAP replay)', () => { let dc: DebugClient; beforeEach(async () => { - dc = new DebugClient('node', ADAPTER, 'soroban'); + dc = new DebugClient('node', ADAPTER, 'stellar'); await dc.start(); }); @@ -65,7 +65,7 @@ describe('SorobanDebugSession (DAP replay)', () => { /** * Assert where the replay cursor is. C8: the position in the recording is - * reported in the THREAD's name (`soroban-vm [29/40]`), not in a frame label — + * reported in the THREAD's name (`stellar-vm [29/40]`), not in a frame label — * a frame name states what the program is doing. */ async function assertAt(index: number): Promise { diff --git a/test/dapControlStepping.test.ts b/test/dapControlStepping.test.ts index ffcf330..4bc916e 100644 --- a/test/dapControlStepping.test.ts +++ b/test/dapControlStepping.test.ts @@ -48,7 +48,7 @@ describe('Control-flow stepping (docs/stepping.md, DAP level)', () => { let dc: DebugClient; beforeEach(async () => { - dc = new DebugClient('node', ADAPTER, 'soroban'); + dc = new DebugClient('node', ADAPTER, 'stellar'); await dc.start(); }); diff --git a/test/dapFrames.test.ts b/test/dapFrames.test.ts index b3e1b13..4acd352 100644 --- a/test/dapFrames.test.ts +++ b/test/dapFrames.test.ts @@ -38,7 +38,7 @@ describe('Callstack view (docs/callstack.md, DAP level)', () => { let dc: DebugClient; beforeEach(async () => { - dc = new DebugClient('node', ADAPTER, 'soroban'); + dc = new DebugClient('node', ADAPTER, 'stellar'); await dc.start(); }); @@ -161,7 +161,7 @@ describe('Callstack view (docs/callstack.md, DAP level)', () => { it('carries the recording position in the thread label, not a frame name', async () => { await launchAndStop(ADDER); const threads = await dc.threadsRequest(); - assert.match(threads.body.threads[0].name, /^soroban-vm \[\d+\/40\]$/); + assert.match(threads.body.threads[0].name, /^stellar-vm \[\d+\/40\]$/); for (const frame of (await frames()).body.stackFrames) { assert.ok( !/\[\d+\/\d+\]/.test(frame.name), diff --git a/test/dapLedger.test.ts b/test/dapLedger.test.ts index 5586653..1d5db6a 100644 --- a/test/dapLedger.test.ts +++ b/test/dapLedger.test.ts @@ -22,7 +22,7 @@ describe('SorobanDebugSession Globals + Ledger scopes (docs/state-inspection.md) let dc: DebugClient; beforeEach(async () => { - dc = new DebugClient('node', ADAPTER, 'soroban'); + dc = new DebugClient('node', ADAPTER, 'stellar'); await dc.start(); }); diff --git a/test/dapMemoryVariables.test.ts b/test/dapMemoryVariables.test.ts index 114025f..ad6bd09 100644 --- a/test/dapMemoryVariables.test.ts +++ b/test/dapMemoryVariables.test.ts @@ -31,7 +31,7 @@ describe('SorobanDebugSession memory-backed Rust variables (end-to-end)', () => let dc: DebugClient; beforeEach(async () => { - dc = new DebugClient('node', ADAPTER, 'soroban'); + dc = new DebugClient('node', ADAPTER, 'stellar'); await dc.start(); }); diff --git a/test/dapServer.test.ts b/test/dapServer.test.ts index 4a04245..2cfde07 100644 --- a/test/dapServer.test.ts +++ b/test/dapServer.test.ts @@ -47,7 +47,7 @@ describe('startDapServer (standalone TCP DAP server)', () => { /** Connect a fresh DebugClient to the server's TCP port. */ async function connect(): Promise { - const dc = new DebugClient('node', 'unused', 'soroban'); + const dc = new DebugClient('node', 'unused', 'stellar'); clients.push(dc); await dc.start(srv.port); return dc; @@ -114,7 +114,7 @@ describe('startDapServer (standalone TCP DAP server)', () => { // A dedicated server whose sole connection uses the spy backend. const leakSrv = await startDapServer({ port: 0, backendFor: () => spy }); try { - const dc = new DebugClient('node', 'unused', 'soroban'); + const dc = new DebugClient('node', 'unused', 'stellar'); await dc.start(leakSrv.port); // Drive a full launch so the backend selector resolves to the concrete diff --git a/test/dapStepping.test.ts b/test/dapStepping.test.ts index 58b1adb..9af9c95 100644 --- a/test/dapStepping.test.ts +++ b/test/dapStepping.test.ts @@ -64,7 +64,7 @@ describe('Stepping spec (docs/stepping.md, DAP level)', () => { let dc: DebugClient; beforeEach(async () => { - dc = new DebugClient('node', ADAPTER, 'soroban'); + dc = new DebugClient('node', ADAPTER, 'stellar'); await dc.start(); }); diff --git a/test/dapVariables.test.ts b/test/dapVariables.test.ts index 9b447bf..56e9a04 100644 --- a/test/dapVariables.test.ts +++ b/test/dapVariables.test.ts @@ -19,7 +19,7 @@ describe('SorobanDebugSession source-level Variables view', () => { let dc: DebugClient; beforeEach(async () => { - dc = new DebugClient('node', ADAPTER, 'soroban'); + dc = new DebugClient('node', ADAPTER, 'stellar'); await dc.start(); }); diff --git a/test/multitxConfig.test.ts b/test/multitxConfig.test.ts index 7d3a60f..e63d9a8 100644 --- a/test/multitxConfig.test.ts +++ b/test/multitxConfig.test.ts @@ -62,7 +62,7 @@ describe('normalizeConfig', () => { // ------------------------------------------------------------------------ describe('new transactions schema (happy path)', () => { const raw = { - type: 'soroban', + type: 'stellar', request: 'launch', transactions: [ { kind: 'deploy', id: 'pool', wasm: '/abs/pool.wasm' }, @@ -118,7 +118,7 @@ describe('normalizeConfig', () => { // ------------------------------------------------------------------------ describe('trace selector resolution', () => { const threeSteps = { - type: 'soroban', + type: 'stellar', request: 'launch', transactions: [ { kind: 'deploy', id: 'a', wasm: '/a.wasm' }, @@ -155,7 +155,7 @@ describe('normalizeConfig', () => { describe('validation rejections', () => { it('rejects an empty `transactions` array', () => { assert.throws(() => - norm({ type: 'soroban', request: 'launch', transactions: [] }), + norm({ type: 'stellar', request: 'launch', transactions: [] }), ); }); @@ -163,7 +163,7 @@ describe('normalizeConfig', () => { assert.throws( () => norm({ - type: 'soroban', + type: 'stellar', request: 'launch', transactions: [ { kind: 'deploy', id: 'pool', wasm: '/p.wasm' }, @@ -178,7 +178,7 @@ describe('normalizeConfig', () => { assert.throws( () => norm({ - type: 'soroban', + type: 'stellar', request: 'launch', transactions: [ { kind: 'deploy', id: 'dup', wasm: '/a.wasm' }, @@ -192,7 +192,7 @@ describe('normalizeConfig', () => { it('rejects a trace index that is out of range', () => { assert.throws(() => norm({ - type: 'soroban', + type: 'stellar', request: 'launch', transactions: [ { kind: 'deploy', id: 'a', wasm: '/a.wasm' }, @@ -207,7 +207,7 @@ describe('normalizeConfig', () => { assert.throws( () => norm({ - type: 'soroban', + type: 'stellar', request: 'launch', transactions: [ { kind: 'deploy', id: 'a', wasm: '/a.wasm' }, @@ -220,7 +220,7 @@ describe('normalizeConfig', () => { }); it('rejects a config with no `transactions` array', () => { - assert.throws(() => norm({ type: 'soroban', request: 'launch' })); + assert.throws(() => norm({ type: 'stellar', request: 'launch' })); }); it('rejects a leftover legacy top-level `function` with a migration error', () => { @@ -232,7 +232,7 @@ describe('normalizeConfig', () => { assert.throws( () => norm({ - type: 'soroban', + type: 'stellar', request: 'launch', function: 'add', args: [{ value: 1, type: 'u32' }], @@ -249,7 +249,7 @@ describe('normalizeConfig', () => { assert.throws( () => norm({ - type: 'soroban', + type: 'stellar', request: 'launch', function: 'add', transactions: [ @@ -268,7 +268,7 @@ describe('normalizeConfig', () => { describe('purity', () => { it('is referentially transparent for the same input', () => { const raw = { - type: 'soroban', + type: 'stellar', request: 'launch', transactions: [ { kind: 'deploy', id: 'pool', wasm: '/p.wasm' }, @@ -280,7 +280,7 @@ describe('normalizeConfig', () => { it('does not mutate the input config', () => { const raw = { - type: 'soroban', + type: 'stellar', request: 'launch', transactions: [ { kind: 'deploy', id: 'pool', wasm: '/p.wasm' }, @@ -301,7 +301,7 @@ describe('normalizeConfig', () => { // ------------------------------------------------------------------------ describe('optional invoke id + trace-by-invoke-id', () => { const raw = { - type: 'soroban', + type: 'stellar', request: 'launch', transactions: [ { kind: 'deploy', id: 'pool', wasm: '/p.wasm' }, @@ -324,7 +324,7 @@ describe('normalizeConfig', () => { it('leaves an invoke without an `id` as undefined (id is optional)', () => { const bare = norm({ - type: 'soroban', + type: 'stellar', request: 'launch', transactions: [ { kind: 'deploy', id: 'pool', wasm: '/p.wasm' }, @@ -357,7 +357,7 @@ describe('normalizeConfig', () => { describe('deploy build options: buildCommand + debugInfo', () => { it('preserves `buildCommand` + `debugInfo` declared on a new-schema deploy step', () => { const deploy = norm({ - type: 'soroban', + type: 'stellar', request: 'launch', transactions: [ { diff --git a/test/sequenceRunner.e2e.test.ts b/test/sequenceRunner.e2e.test.ts index d753320..c44a992 100644 --- a/test/sequenceRunner.e2e.test.ts +++ b/test/sequenceRunner.e2e.test.ts @@ -73,7 +73,7 @@ interface InvokeTx { id?: string; } interface TxConfig { - type: 'soroban'; + type: 'stellar'; request: 'launch'; sourceSecret?: string; node: { attach: false; command: string; port: number }; @@ -163,7 +163,7 @@ describe('SequenceRunner e2e', function () { // ------------------------------------------------------------------------ it('deploys ctor_probe, runs __constructor then admin_set, and the constructor state persists into the traced tx', async () => { const resolved = await runSequence({ - type: 'soroban', + type: 'stellar', request: 'launch', sourceSecret: SOURCE_SECRET, node: nodeSettings(), @@ -224,7 +224,7 @@ describe('SequenceRunner e2e', function () { // ------------------------------------------------------------------------ it('traces a supply invocation whose argument is a Vec<(AssetKey,i128)>', async () => { const resolved = await runSequence({ - type: 'soroban', + type: 'stellar', request: 'launch', sourceSecret: SOURCE_SECRET, node: nodeSettings(), @@ -279,7 +279,7 @@ describe('SequenceRunner e2e', function () { // ------------------------------------------------------------------------ it('does not throw when the traced last step traps, and still returns its non-empty trace', async () => { const resolved = await runSequence({ - type: 'soroban', + type: 'stellar', request: 'launch', sourceSecret: SOURCE_SECRET, node: nodeSettings(), @@ -317,7 +317,7 @@ describe('SequenceRunner e2e', function () { // ------------------------------------------------------------------------ it('executes two byte-identical invokes independently (distinct hashes, not deduped)', async () => { const resolved = await runSequence({ - type: 'soroban', + type: 'stellar', request: 'launch', sourceSecret: SOURCE_SECRET, node: nodeSettings(), diff --git a/test/sequenceRunner.test.ts b/test/sequenceRunner.test.ts index 738715f..6df94b5 100644 --- a/test/sequenceRunner.test.ts +++ b/test/sequenceRunner.test.ts @@ -184,7 +184,7 @@ describe('SequenceRunner', () => { // ------------------------------------------------------------------------ describe('ordered execution + handle registration', () => { const raw = { - type: 'soroban', + type: 'stellar', request: 'launch', transactions: [ { kind: 'deploy', id: 'probe', wasm: CTOR_WASM }, @@ -234,7 +234,7 @@ describe('SequenceRunner', () => { describe('substitution + spec-driven composite encoding (composite.wasm)', () => { it('substitutes both token kinds and spec-encodes the composite Vec<(AssetKey,i128)>', async () => { const raw = { - type: 'soroban', + type: 'stellar', request: 'launch', transactions: [ { kind: 'deploy', id: 'pool', wasm: COMPOSITE_WASM }, @@ -284,7 +284,7 @@ describe('SequenceRunner', () => { args: { requests: [[{ tag: 'Native' }, '1000']] }, }; const raw = { - type: 'soroban', + type: 'stellar', request: 'launch', transactions: [ { kind: 'deploy', id: 'pool', wasm: COMPOSITE_WASM }, @@ -319,7 +319,7 @@ describe('SequenceRunner', () => { // ------------------------------------------------------------------------ describe('no-throw on FAILED + trace still fetched', () => { const raw = { - type: 'soroban', + type: 'stellar', request: 'launch', transactions: [ { kind: 'deploy', id: 'pool', wasm: COMPOSITE_WASM }, @@ -356,7 +356,7 @@ describe('SequenceRunner', () => { // Two invokes with DISTINCT args (Other 1 / Other 2) so each maps to an // identifiable submitted tx; each also carries an `id`. const raw = { - type: 'soroban', + type: 'stellar', request: 'launch', transactions: [ { kind: 'deploy', id: 'pool', wasm: COMPOSITE_WASM }, @@ -412,7 +412,7 @@ describe('SequenceRunner', () => { // ------------------------------------------------------------------------ describe('deterministic source account', () => { const raw = { - type: 'soroban', + type: 'stellar', request: 'launch', transactions: [ { kind: 'deploy', id: 'pool', wasm: COMPOSITE_WASM }, diff --git a/test/serverCli.test.ts b/test/serverCli.test.ts index 3b5fb8a..88612d8 100644 --- a/test/serverCli.test.ts +++ b/test/serverCli.test.ts @@ -1,6 +1,6 @@ /** * Unit suite for the pure argv parser behind the DAP TCP server CLI - * (`soroban-dap`): --help and argument validation. + * (`stellar-dap`): --help and argument validation. * * parseServerArgs(argv): ServerParse from src/server/cliArgs.ts * SERVER_USAGE: string the help text @@ -50,7 +50,7 @@ describe('parseServerArgs', () => { }); it('SERVER_USAGE carries the documented stable substrings', () => { - for (const needle of ['soroban-dap', 'Usage', '--port', '--host', '-h, --help']) { + for (const needle of ['stellar-dap', 'Usage', '--port', '--host', '-h, --help']) { assert.ok(SERVER_USAGE.includes(needle), `SERVER_USAGE should contain ${needle}`); } }); diff --git a/test/traceCli.test.ts b/test/traceCli.test.ts index df71dcd..8dc28bb 100644 --- a/test/traceCli.test.ts +++ b/test/traceCli.test.ts @@ -1,6 +1,6 @@ /** * Unit suite for the pure argv parser behind the one-shot trace CLI - * (`soroban-trace`): --help and argument validation. + * (`stellar-trace`): --help and argument validation. * * parseTraceArgs(argv): TraceParse from src/trace/cliArgs.ts * TRACE_USAGE: string the help text @@ -51,7 +51,7 @@ describe('parseTraceArgs', () => { it('TRACE_USAGE carries the documented stable substrings', () => { for (const needle of [ - 'soroban-trace', + 'stellar-trace', 'Usage', '--raw-trace', '--wasm', From e3f8a1cc076f07384a0def86ebb9c34565d2f8b2 Mon Sep 17 00:00:00 2001 From: Raoul Date: Fri, 21 Aug 2026 10:20:45 +0000 Subject: [PATCH 03/13] chore: package the extension as 0.1.0 and publish it from a tag MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Marketplace metadata the listing needs: a 128x128 icon (generated from `images/icon.svg`, regeneration documented in `images/README.md`), a gallery banner, keywords, a Testing category alongside Debuggers, and `preview: true` for a first release. The version is 0.1.0. `.vscodeignore` becomes an allowlist — ignore everything, then add back `dist/`, the icon and the four metadata files. A denylist is a trap here: `vsce` packages from the disk rather than from git, and `examples/*/target` plus `test/fixtures/*/target` are roughly 6 GB of gitignored Rust build output. `vsce ls` now reports 8 files and the package is 905 KB. CI packages on every run and fails if the `.vsix` grows past 2 MB, so a regression cannot pass unnoticed. `release.yml` is tag-driven: it refuses a tag that disagrees with `package.json`, runs the suite with the e2e opt-out (CI has already run it against the real node on that commit), then publishes to the VS Code Marketplace and to Open VSX, which is where Cursor, Windsurf and VSCodium install from, and attaches the `.vsix` to a GitHub release. It needs the `VSCE_PAT` and `OVSX_PAT` secrets. Activation was the blanket `onDebug`, which woke the extension for any debug session and left the palette command relying on implicit activation; it is now `onDebugResolve:stellar` plus an explicit `onCommand:stellar.debug`. RELEASE-CHECKLIST.md tracks what is left before the tag and is meant to be deleted once the release is out. --- .github/workflows/ci.yml | 13 + .github/workflows/release.yml | 87 + .vscodeignore | 31 +- RELEASE-CHECKLIST.md | 40 + images/README.md | 10 + images/icon.png | Bin 0 -> 5746 bytes images/icon.svg | 10 + package-lock.json | 3453 +++++++++++++++++++++++++++++++-- package.json | 37 +- 9 files changed, 3500 insertions(+), 181 deletions(-) create mode 100644 .github/workflows/release.yml create mode 100644 RELEASE-CHECKLIST.md create mode 100644 images/README.md create mode 100644 images/icon.png create mode 100644 images/icon.svg diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 22f77a6..47bdd66 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,6 +39,19 @@ jobs: - name: Build run: npm run build + # Guards the allowlist-shaped .vscodeignore. `vsce` packages from the disk, + # not from git, so a denylist regression quietly ships the committed wasm + # fixtures here — and gigabytes of Rust `target/` output on a dev machine. + - name: Package, and check the .vsix stays small + run: | + npm run package + size=$(stat -c%s stellar-debugger.vsix) + echo "stellar-debugger.vsix: $size bytes" + if [ "$size" -gt 2000000 ]; then + echo "::error::the .vsix is $size bytes (> 2 MB) — check .vscodeignore with 'npx vsce ls'" + exit 1 + fi + # The end-to-end tests (test/integration.node.test.ts) run the REAL # komet-node — the only way to catch a breaking change in its RPC or trace # format. Install it the same way the devcontainer does: Nix + RV's binary diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..57c0e40 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,87 @@ +name: Release + +# Publishing is driven by a tag: `git tag v0.1.0 && git push origin v0.1.0`. +# The tagged commit must already be green on CI (which is what runs the real +# komet-node end-to-end suite); this workflow builds, packages, and publishes. +on: + push: + tags: ['v*'] + # Allow a dry run that packages and uploads the .vsix without publishing. + workflow_dispatch: + +permissions: + contents: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: npm + + - name: Install dependencies + run: npm ci + + # A tag that disagrees with package.json would publish the wrong version + # to the marketplace under a name nobody can correct later. + - name: Check the tag matches package.json + if: startsWith(github.ref, 'refs/tags/v') + run: | + manifest="$(node -p "require('./package.json').version")" + tag="${GITHUB_REF_NAME#v}" + if [ "$manifest" != "$tag" ]; then + echo "::error::tag $GITHUB_REF_NAME does not match package.json version $manifest" + exit 1 + fi + + - name: Type-check + run: npm run check-types + + - name: Lint + run: npm run lint + + # The real-komet-node e2e suite already ran on this commit in CI; opt out + # of it here (its own documented escape hatch) rather than spending ten + # minutes reinstalling Nix and the K semantics to re-prove the same thing. + - name: Test (without the real-node e2e suite) + run: npm test + env: + KOMET_NODE_E2E: '0' + + - name: Package + run: npm run package + + - name: Upload the .vsix as a build artifact + uses: actions/upload-artifact@v4 + with: + name: stellar-debugger-vsix + path: stellar-debugger.vsix + + - name: Publish to the VS Code Marketplace + if: startsWith(github.ref, 'refs/tags/v') + env: + VSCE_PAT: ${{ secrets.VSCE_PAT }} + run: npx vsce publish --packagePath stellar-debugger.vsix + + # Cursor, Windsurf and VSCodium install from Open VSX, not from the + # Microsoft marketplace, so a release that skips this is invisible to them. + - name: Publish to Open VSX + if: startsWith(github.ref, 'refs/tags/v') + env: + OVSX_PAT: ${{ secrets.OVSX_PAT }} + run: npx ovsx publish stellar-debugger.vsix + + - name: Create the GitHub release + if: startsWith(github.ref, 'refs/tags/v') + env: + GH_TOKEN: ${{ github.token }} + run: | + gh release create "$GITHUB_REF_NAME" \ + --title "$GITHUB_REF_NAME" \ + --notes "See [CHANGELOG.md](https://github.com/runtimeverification/stellar-debugger/blob/$GITHUB_REF_NAME/CHANGELOG.md)." \ + stellar-debugger.vsix diff --git a/.vscodeignore b/.vscodeignore index 66e7d3f..ff4e64c 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -1,14 +1,17 @@ -.vscode/** -.devcontainer/** -src/** -test/** -out/** -node_modules/** -.gitignore -.mocharc.json -esbuild.js -tsconfig*.json -.eslintrc.json -**/*.map -**/*.ts -!dist/** +# Allowlist-shaped: ignore everything, then add back exactly what the installed +# extension needs. A denylist is a trap here — `examples/*/target` and +# `test/fixtures/*/target` are gitignored but still on disk, and `vsce` packages +# from the disk, not from git. +** + +!dist/extension.js +!dist/dap-server.js +!dist/trace.js +!images/icon.png +!package.json +!README.md +!CHANGELOG.md +!LICENSE + +# Source maps are dev-only (`vscode:prepublish` builds minified, without them). +dist/**/*.map diff --git a/RELEASE-CHECKLIST.md b/RELEASE-CHECKLIST.md new file mode 100644 index 0000000..ddf21cb --- /dev/null +++ b/RELEASE-CHECKLIST.md @@ -0,0 +1,40 @@ +# First public release — polishing checklist + +Working doc for the v0.1.0 public release of the Stellar Debugger. Delete this file once the release is out. + +Decisions taken: full rename to `stellar` (debug type, settings, command, CLI binaries), version **0.1.0**, `examples/` stays repo-only rather than shipping in the `.vsix`, and the CLIs stay repo-built (no npm publish this release). + +## Done + +- [x] **Package identity.** `name` → `stellar-debugger`, `displayName` → `Stellar Debugger`, `version` → `0.1.0`, description rewritten; `.devcontainer/devcontainer.json` renamed too, and `package-lock.json` resynced. +- [x] **Full `soroban` → `stellar` rename of everything users type or see**: debug type `"type": "stellar"`, settings `stellar.kometNode.path` and `stellar.cliPath` (was the awkward `soroban.stellar.path`), command `stellar.debug`, binaries `stellar-dap` / `stellar-trace`, the thread label `stellar-vm [n/m]`, and every launch-config name, snippet, error message, doc and example. Internal identifiers (`SorobanDebugSession`, `SorobanLaunchArgs`, `src/soroban/**`) deliberately keep the name: they refer to the Soroban protocol layer, not to the product, and renaming them would churn the whole tree for no user-visible gain. +- [x] **Marketplace metadata.** `icon` (128×128, `images/icon.png`, generated from `images/icon.svg`), `galleryBanner`, ten `keywords`, `categories: [Debuggers, Testing]`, and `preview: true` for the first release. +- [x] **`.vscodeignore` rewritten as an allowlist.** `vsce ls` now reports exactly 8 files and `npm run package` produces a 905 KB `.vsix` — previously it would have swept in the ~5.8 GB of `examples/*/target` and `test/fixtures/*/target` that git ignores but `vsce` does not. +- [x] **Release plumbing.** `@vscode/vsce` and `ovsx` added as devDependencies with `package` / `publish:vscode` / `publish:openvsx` scripts, plus `.github/workflows/release.yml`: tag-triggered, refuses a tag that disagrees with `package.json`, runs the suite with the e2e opt-out (CI already ran it against the real node on that commit), then publishes to the VS Code Marketplace and Open VSX and attaches the `.vsix` to a GitHub release. +- [x] **CHANGELOG.** `[Unreleased]` folded into `[0.1.0] — 2026-08-21`, rewritten as a first-public-release feature list rather than a diff against a version nobody had; the fictional `[0.1.0]`-predecessor entry and its dead tag link are gone, and the komet-node floor is stated under Requirements. +- [x] **README.** New **Install** section (marketplace, `code --install-extension`, Open VSX for Cursor/Windsurf/VSCodium); komet-node **≥ v0.1.87** stated in Requirements with the note that replay needs no toolchain at all; a **Known limitations** section covering partial traces, the opt-level-0 requirement, and one-traced-transaction-per-session; the Roadmap no longer contradicts the Features (the Variables view ships — *inline* values are what's still future); `examples/` described as a repo clone rather than "bundled"; and the CLIs marked as repo-built, not installed by the extension. +- [x] **CLI docs** (`docs/trace-cli.md`, `docs/dap-cli.md`) say plainly that a marketplace install does not put `stellar-trace` / `stellar-dap` on `PATH`. +- [x] **`SECURITY.md`** (private reporting, scope, and the explicit non-vulnerability of a `launch.json` naming its own build command) and **`CODE_OF_CONDUCT.md`** (Contributor Covenant 2.1). +- [x] **Repo hygiene.** `.gitignore` covers `.env`, `.env.*` and `.deps/`; the personal `/home/node/work/...` entries are out of `.vscode/launch.json`; the stray `state.kore` is deleted. +- [x] **Personal paths out of the test data.** `test/justMyCode.test.ts` classified paths under `/home/node/work/rs-lending-xlm/...`, naming an internal project in a repo about to go public; the ground-truth paths are now neutral (`/home/dev/work/lending-pool/...`), which the classifier treats identically since it keys off `.rustup` / `.cargo/registry` / `/rustc/` markers. +- [x] **Lint covers the tests too** (`eslint src test`), and it passes. +- [x] **Activation narrowed.** `activationEvents` was the blanket `onDebug`, which woke this extension for *any* debug session and left the palette command relying on implicit activation; it is now `onDebugResolve:stellar` plus an explicit `onCommand:stellar.debug`. +- [x] **`engines.vscode: ^1.85.0` verified.** `src/extension.ts` is the only module that imports `vscode`, and every API it touches (`registerDebugConfigurationProvider`, `registerDebugAdapterDescriptorFactory`, `DebugAdapterInlineImplementation`, `getConfiguration`, `showInputBox`, `startDebugging`) long predates 1.85; the disassembly, memory and step-back features are negotiated DAP capabilities, supported well before it. The floor is truthful and conservative. +- [x] **CONTRIBUTING** documents the release process, the allowlist `.vscodeignore` invariant, and the deliberate decision to defer the ESLint 9 migration until after the release (dev-only dependency, never reaches the `.vsix`). + +## Needs a human + +- [ ] **Pin, or at least verify, the `komet-node` version CI and the devcontainer install.** Both run a bare `kup install komet-node`, so they ride whatever is newest at build time — and the trace format is a hard contract this extension rejects on mismatch, which means CI can turn red with no change in this repo. This is not hypothetical: the devcontainer in use here has komet-node `7b2c71b`, about fourteen commits stale and predating the komet v0.1.88 bump, so **all six real-node e2e tests fail locally** with `trace line 1: 'kind' must be a non-empty string`. A raw dump confirms that node still serves the old shape (`{"pos":null,"instr":["callContract"],…}`, no `kind`). Nothing in this repo is at fault, and no polishing change caused it, but the release tag has to sit on a commit whose e2e suite really passed — so rebuild the devcontainer (or `kup install komet-node --version `) and confirm green before tagging. + +- [ ] **Record a screenshot or a short GIF for the README.** This is the one real gap left: the marketplace page is the README, and a time-travel debugger sells on motion — stepping backwards, the Ledger view scrubbing with the cursor. Nothing else on this list can substitute for it. +- [ ] **Confirm the marketplace publisher and add the secrets.** `publisher: runtimeverification` must exist and be verified, with `VSCE_PAT` and `OVSX_PAT` stored as repository secrets, plus an Open VSX namespace of the same name. +- [ ] **Enable GitHub private vulnerability reporting** (Settings → Security) so the link in `SECURITY.md` resolves, and confirm `security@runtimeverification.com` is a mailbox someone actually watches — replace it if not. +- [ ] **Consider a designed icon.** `images/icon.png` is a hand-rolled rewind glyph on navy: legible at tile and tree size, but a real designer would do better. Regeneration instructions are in `images/README.md`. +- [ ] **Install the packaged `.vsix` in a clean VSCode** (no repo, no dev dependencies) and run one replay config and one live build-deploy-debug config. The replay path must work with no toolchain at all — that is the front page's claim. +- [ ] **Tag the release** on a commit that is green on CI: `git tag v0.1.0 && git push origin v0.1.0`. Then check that the marketplace and Open VSX links in the README resolve. +- [ ] **Verify the README's relative links** on the rendered marketplace page (`vsce` rewrites them against the `repository` field; the `docs/` and `examples/` links do not ship inside the `.vsix`). + +## After the release + +- [ ] Migrate to ESLint 9's flat config. +- [ ] Revisit `preview: true` once the first users have reported back. diff --git a/images/README.md b/images/README.md new file mode 100644 index 0000000..cfadd77 --- /dev/null +++ b/images/README.md @@ -0,0 +1,10 @@ +# Icon source + +`icon.svg` is the source for the marketplace tile; `icon.png` (128×128) is what `package.json` references. + +Regenerate after editing the SVG: + +```bash +convert -background none -density 384 images/icon.svg -resize 128x128 images/icon.png +convert images/icon.png -depth 8 -strip images/icon.png +``` diff --git a/images/icon.png b/images/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..131d634218f53804119132099220781702d9353f GIT binary patch literal 5746 zcma)Ag;$hcw4H&WK@dh-=}@{sVnk*LDG`(oLAnL$5)?@hP>_Zp2I=k@KvKH-fiQG; zH@wgH54?BRy5C*vTj!j0@7?$8b@mB=si8zhOiv5~fyh*p;je%-=-(v72fl4`Z+k%? zYAF@CypGrOPMWu#&RKmIY%NuvHq;TMM1eB6 zX`4KjGR7M%q;42(JI(9p>^v=+r>a(JAEo}Xjwn3ya}YNxl8{@vQm{>MZ3Y%fm(?ly zM5M(U%f0Y$__Mj_z({QTl#8)4|MV36>7x3|tzi znKd;NuS`q=GOMcG4J|EKIKQ-M;noeD{kLWhl81JTNx7}^Ht#lUVQRb%7Qb(AI}F>1 z2CUBRc=UEx_!gBeeR>W>z_qUXwl>_KO1)nu}E4H z+ACPQ7R9bYt3aj}nbDJY_+GEc<`)Q1s zoc=UHNH3>{`UzT4yfh7^O@zvfOTW2O{e{nncD(=Ov{P-R_mS0>ssQ@ z29-EJ|HQM5o{J@PC^i*9ds_PGW1dp8u98_jM~_$W@r2|e$Z@+rJv}3q*4Cy@)dr)5 z1qG*_?d|SoXJ;8F=hk8XWZe~v#zschqvM6TbJ|8mMTzW#rMi=kmSe~5y%$#I+^*p~ zgg7Jml+-_lJM8hn>$^J^gI_ZC7r3s%QtUXTY@Z^z?pO(N z7Kc8-up>RbOy600iM^#Nhc>F+JkP$YO-kdUmuwWybK|}fiO#^o!sog$Y9m?LZS3w z5fQ9hTwLXijncVIP1j5Y#S>3@55vwf-hvQX|JAuJ)#?@-oOrpqmTOQz7&W+>y*6rP zj*b$`rX9Q*aef?xFcWrH^kE7Nk`1T18@5$xqqBahaas+eCQbbJAMG1c(>ro`3dMJy z7x$g{8`fEY$~m9$dv-?KZNpu~}T`8-i5g07{6^uW^_nA(z>2ad57=J6(Nvz5Z*heA>Zop9^F{ z<>xa`fnGyN$-PZV<7eX0Estx!+DK$;KHEB%Dzxr=KA)pAm&CQE(=esaZxXUmS@pjV4 zt-q(Bpg<6$g&Jice12FxX>v7QRKyE1_^WZSHHZG#wxOenCW`We9u%t^J}y1y0tpET z@#z59XY&A0+lx zI+*Rw)OYff)GgYRk&zi3tR$M=%K)e?4j@5rW+5sO)?E2uGSd)!6#~(MdhLb00yYZ{ zi;1yr4aU>Op<{LV=Mtczr$-B7(%nXFjy|p4BWH!kXBMMFilt%uH$|D5WcKJqK@--d{&d})JuG>w6 z7Lmi0j0`4@yu7?lpUS(C6QwdeM;hjAVUq)mH6XQ*Z+LllNQBtf+Rj1%dQ`AK*9rcS z-IeV6lmMixrUsAt`W0Ws4XoZ}2txFOgQ4;iHqujHJ2sOz#x~r;fU5@8Stg}pct1mHRFHN2SI=CbAW8G91fMHS97TM6ovW)q(FXgP z?{#q1{?FO@3ycGMoYl?7r4p>Z=MeQL5de%Wp^EQsZ2wy1Z@b@ zyW@XBXT`4@$b>svtlaQzeps3S#|~868@_I{)>W%id6=gc6*`)tVH`p%-E&oUw#K!- zJ(*1wy+5czil?9j#V?xuH2kM;gY}E%#fAcb!5$-#&As{e|J8ftwMV3wher%$juT=6 zvshRq_`}Rqv?OtF-ZZcCV9dHDubzgDdsN&uy7Hn&KJmr`1Txy7k61GCzY!R>!<9cV z@$)LnsKzly*%Wa))yy2HeyjeSUSLuqeZG^&Cd=D zGl6OfzN;ls@?@yAZtz;T3Wu(I#tX+@h^RbTNOdien6R~%0$g~ntqDfdJ$pn$x6+t`fJSF5yzaET+g^vaKe($2i zDVB(UWPn3|81ownJk^zkHSr}AVB{WT%R{DMt>izk+*CUF`<-$A+Y+`m%BdHVgX z^7P!}1UFj=tI}bF^te&njXr;q9yu+n&82nrlc=W~cz*wqfLpvK5ZnfesNJS-pBhy> z73JE(WOO4{+hq06YzWwfd;-`dNdfK+!If+|uUPD_wo0TxLdJCms`!$f(UV@hX|L4 zY_Asus4>mEl8$No-$KP>&cUVFhGxBU6VP#I+<|itiztg?l@?JGruUCThVA0Z_%wU z|1fmj)^8@$Vv0(A`@D=CVaCm!jj0RF!P>#LqQO+XAcdvF;2f5A=wQ}YLCndvD|UJ+ z`mgj;iDdZ;UG#t;rg~M9!PDbH$(i)09zJMp;H^BAC|q=Of~kKNX1~w@t6gH$dB!-K znVPjG=z4a<=it=~^Z97?n+~);>mAITNgmVrB>7^PXXkp^vsiC?cbL3~5KZeaqVonl zJuuqrm^-*ifCdQ*k%2H$J`ix4P@KGi%phjCEo3Xjc8`wnrede^_;#!mMM}=hSe)je?KR z4Iw!8YsqJ4Zgr@}Pi|1KEYlu1?o(}?l+fdXCLgMNHPR>luFF7{Wtiyugl*lBys&mMuqmu%- zsp#^~Y$Ic()8#tn>GDP`d zy_LzWp)~I85QAm#07$UNg9dVZU&y_;T;{k}`}&xit6bXhF8To>>t&dp&-cgI^SUUn z-4k(#fFTC;;1N(u*t9W?l{qu}SFXUh4)Q?n;1Y~{^VbLKzt!rVFM3@DHh7(PSUvT< z$&`2jDFvIgU!x}|?k$X-kIy;I+*K}#X3*2#2p^E5Attw`3}-jnl3kjY^3G7gCh&j< z8BQ5iBbyvy|6;zMlEzbRw*8~x7t@f%;go^SIIvS-LHIP=&C&n_EEdFUTP6*~$N!T2 z+&OZc41+`6NE&xX{Y1q;_HrHK@j7zm_8paPp<{sY2Al24C%EQX2z~5|rnuIv=2o47 zKJ+E7%?W-%4C%hp#gHlYIB8nz&|Su(U2CO!ylA6Z73F%RiIU)KD5 zc`Ebg&Jl15j^xk?+D3wJI&q?+9YEC|tmxbNMOs4E z*i3GznWe4^jG_3b(b=hVxP}mGVORS9O!vlFR5OEV_V*{?XH`=U3Z}$i!PCqTX(ad8 zy1|Z;l9DVMNR(p8G$BMN0!cxMR4SB}J$ih4d<8%EG}Y5v`c(~okc1k1R1t8YJIae_L`vw#xoMbWQcQ?CsT?ZKL? zbzTcH?oZR~f|(Vx%mUtmwaqO+Hg1!?eo!o;JNUGIF50y1WF*%~n|UCRlWR1%FFQ|9x0G8hrub;7!M^G%! z<2LNvUh{0jlK^=ws3?8-m)$#YQ}l)bP)-9Kk&~^-M29)dP59yAVE{r)1|K9yAKe2e zb_P~9Hkt?2)X9Lh_@ffuU6E1|^W>YQzE~>+i1SW=l}8oRX925YQcxz0K$f{Kb*2Nc zU_aB-O~$9EiCv~a{E3mid+6FNK)2Xynwu|q}l;TdUNcELP}p zdAt#o^$H2Jz3ph)-(Gr`V*+{R<|gtl(pj1()>|)oST8i@ zK>5yxB3g0D$-$wh%AnZx;^LwbnVk*D*ME}J{lnS*#zzG^Pr-W!;#ay*>aw>xF@O38 zAeptbiNN6kFGo}bilZVUrG<4)E+pGP6}(h*bhiKAmVNEtqoc#aI3yA&NUx9tI}?V> z=M?1K`_i^BwOT~~wlCI_E}H$|2ZyN@aL(BDWKyrrD+!1HhN|ASh5D`mt%-%(o2x;u z(qnxB;I04cU)>!U8F^ngo}3sTA8#X^G_>^r+F$?adt{uX`#B+MS{hufO3MR9wC*H? zi)bzooR!Wu2e@RE4({#jShj_dsc%h|Hlwn$ExH_QXHS#5z72S|r1UE~I5;Q)l1Sgv z)APmq_wVhDj8Xwg(5JKIH4vl$+c?;D+Erg+QOT`$UO0Q4V`lTyh17?mTuhc5(Uaza zpFl2)?L-sBhPp?KkpkFJEEcnLWX|fJ{%zKYi=92EvZCVsWGtJ~Z*@*>jaRSY6tjmZ z93#w!AAE+Ico1c}9O@8Ir#zhEyGq~BN`C9U|FyHHB8ry>{^^VBN>i`*^}^M~VB;Pu zhZK<(6cE=vJukcgu%%7CSAP5epkfL*N}0Q!vB*&U^jt(lB$3Y)b3N?rx5OXNIV{H>+GV0@$@k*i#B?P+p?J`a_~J;U@=u}f%Qvc{2PZVmgK3nRM)O^H| zU%x)`7$FAQ3MXVrQ>MnMCm%x?Wj%sx;!%Jm+=L!UQ6ML&n5?Z7pUX@o*)E%=b`%}! zm|Lh}IE?3Qb78mVORW-fewFT{dFq2{GTw)>^CYm3n|{u!3Vwdqi@<11M{r41_LuERIdD|*AIvG!6suLg2QjgZeCr=Yv95oQwD`QbJ6GX^8~golUVUjs34 zYofSxe0=-{5tlP?pTQpkqM?r#telbo9_o4m9tpLPl=VRBr?D}eKktOeiuvEr@x9Xr za32{P%hA!%ao@$Fud@H~*@yG}g@@0i*XqCfRyir9aYxv0Y;5SRtgf2Gr=`hq!C)|9 z9-hedcDQ@P!GUsBcqnf#AfR2=hgg8Eq*Yf}-xZaV1k~o`S@{MA-UYOHWYOP|Kc%D8 V`c7=q1@w|ZDhLgD$#b*d{{dM(G8zB? literal 0 HcmV?d00001 diff --git a/images/icon.svg b/images/icon.svg new file mode 100644 index 0000000..75179c1 --- /dev/null +++ b/images/icon.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/package-lock.json b/package-lock.json index 7fce580..f0e2f82 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "stellar-debugger", - "version": "0.0.1", + "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "stellar-debugger", - "version": "0.0.1", + "version": "0.1.0", "license": "BSD-3-Clause", "dependencies": { "@stellar/stellar-sdk": "^14.6.1", @@ -15,8 +15,8 @@ "wasmparser": "^5.11.1" }, "bin": { - "soroban-dap": "dist/dap-server.js", - "soroban-trace": "dist/trace.js" + "stellar-dap": "dist/dap-server.js", + "stellar-trace": "dist/trace.js" }, "devDependencies": { "@stryker-mutator/core": "^9.6.1", @@ -27,11 +27,13 @@ "@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/parser": "^8.0.0", "@vscode/debugadapter-testsupport": "^1.68.0", + "@vscode/vsce": "^3.6.0", "c8": "^11.0.0", "esbuild": "^0.23.0", "eslint": "^8.57.0", "fast-check": "^4.9.0", "mocha": "^10.7.0", + "ovsx": "^0.10.1", "typescript": "^5.5.0" }, "engines": { @@ -39,6 +41,202 @@ "vscode": "^1.85.0" } }, + "node_modules/@azu/format-text": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@azu/format-text/-/format-text-1.0.2.tgz", + "integrity": "sha512-Swi4N7Edy1Eqq82GxgEECXSSLyn6GOb5htRFPzBDdUkECGXtlf12ynO5oJSpWKPwCaUssOu7NfhDcCWpIC6Ywg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@azu/style-format": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@azu/style-format/-/style-format-1.0.1.tgz", + "integrity": "sha512-AHcTojlNBdD/3/KxIKlg8sxIWHfOtQszLvOpagLTO+bjC3u7SAszu1lf//u7JJC50aUSH+BVWDD/KvaA6Gfn5g==", + "dev": true, + "license": "WTFPL", + "dependencies": { + "@azu/format-text": "^1.0.1" + } + }, + "node_modules/@azure/abort-controller": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.2.0.tgz", + "integrity": "sha512-fNAjWnA/nZ2jz31kxR/AqRaUT8ewHBw/WuBIosK0moMy1C9e5ValbDfFdIxJzVOOYaYkV/b2F1S4H/aHiqfVQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-auth": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.11.0.tgz", + "integrity": "sha512-IUZydyTUkDnYdstOW9pFOOUQlBjAepK5teihDE3x6yxsPJs/hsAaaYpeGxdxrgtOiJbBKSjKW7MDk7AEhb4LRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-util": "^1.13.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-client": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.11.0.tgz", + "integrity": "sha512-JjQWO6akOck45PH/XBrxzsQGAiKrfFl4m5iggJ0ItMIz5omRufOXWpqCPpdjKN3vKDzlSUvFjaMb7Zwf0gvAdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-rest-pipeline": "^1.22.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-process": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@azure/core-process/-/core-process-1.0.0.tgz", + "integrity": "sha512-/shnJ+ooO8WPxDhPEeI/2oRQuubn16gZ6CvlbpWbEswZfzwI9tI/sMAHmF3x1LuQ9yZYXfLW3TjzGMLEC5blKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline": { + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.25.0.tgz", + "integrity": "sha512-bMs8ekJLjX8wPV+9IPBges1SLPyuDtE9g5gLDWOpxzKcoOFQnpLGkbcT1tdw3FaAmDS1gnPmMmJ6y/T5B96kIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "@typespec/ts-http-runtime": "^0.3.4", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-tracing": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.4.0.tgz", + "integrity": "sha512-eGwxD0AtncrxeBM4tG8R55Pc3rdX1hNW2WibJAgYpCVA6E93mvvVH+LcssoVjOBrSKWS55yEIHsk0X8ctHmfOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-util": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.14.0.tgz", + "integrity": "sha512-9n2pWK61veAuN0V20t9lOuoV4CFMdyAZ1ygZzvBGk/pBBJRib/PjL9PLXa/aI2CcPpyHfqVsxxqLCYl6uZlfDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/identity": { + "version": "4.13.2", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.13.2.tgz", + "integrity": "sha512-NXL2/pCJctLxgw8bvrwwgge743kEq8LBT+O1pmV0vyUwetzFPH9auP6jhkU/cgZCPPtWoewAe3ncaGCgPo07fA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-process": "^1.0.0", + "@azure/core-rest-pipeline": "^1.17.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^5.5.0", + "@azure/msal-node": "^5.1.5", + "open": "^10.1.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/logger": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.4.0.tgz", + "integrity": "sha512-rbAE25KUfjU/s3XHUdJgceoCP5dEOpMx85J04kF+QMdta73XkuG9JGHHinch+XIoKpBdqljin+KqURpJriSzLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/msal-browser": { + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-5.19.0.tgz", + "integrity": "sha512-DHe9iRcyByGJuLPkl0K31a1JjOdRY2zX38Q07mQpSbR8zOj1EIgsWfTXhSQVyyijUxlcofVy/br7qWJbrMwVXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/msal-common": "16.13.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "16.13.0", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-16.13.0.tgz", + "integrity": "sha512-rOAy0KUcyBbdwVJ+f3uPpthXatFLLZN+/KWAsTLzk1aB23Xl9DRmmXYwSvBFOZyXj4jUQQ5FKxxRkhAFW1fOow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-node": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-5.6.0.tgz", + "integrity": "sha512-uFY9NxrWHw8PwZx7gAX6PDn+9vdfS05+levc/kwkx77IkjfaldnQbbcQzzDIZ5Hq5Zdr6/z92oAIoRWKp6MnOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/msal-common": "16.13.0", + "jsonwebtoken": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/@babel/code-frame": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", @@ -1602,128 +1800,605 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@node-rs/crc32": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/crc32/-/crc32-1.10.7.tgz", + "integrity": "sha512-OwuyRAe9Lj0GoFVBFzTS6bTAV4i+Xd68sYbNUmLnI1GVkQIqVb9mzNrpKSZkBFiQD73CdMB/uKYsvk2bxq/eZg==", "dev": true, "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "engines": { + "node": ">= 10" }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@node-rs/crc32-android-arm-eabi": "1.10.7", + "@node-rs/crc32-android-arm64": "1.10.7", + "@node-rs/crc32-darwin-arm64": "1.10.7", + "@node-rs/crc32-darwin-x64": "1.10.7", + "@node-rs/crc32-freebsd-x64": "1.10.7", + "@node-rs/crc32-linux-arm-gnueabihf": "1.10.7", + "@node-rs/crc32-linux-arm64-gnu": "1.10.7", + "@node-rs/crc32-linux-arm64-musl": "1.10.7", + "@node-rs/crc32-linux-x64-gnu": "1.10.7", + "@node-rs/crc32-linux-x64-musl": "1.10.7", + "@node-rs/crc32-win32-arm64-msvc": "1.10.7", + "@node-rs/crc32-win32-ia32-msvc": "1.10.7", + "@node-rs/crc32-win32-x64-msvc": "1.10.7" + } + }, + "node_modules/@node-rs/crc32-android-arm-eabi": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-android-arm-eabi/-/crc32-android-arm-eabi-1.10.7.tgz", + "integrity": "sha512-mWNghDkwgoc5uJhhPx/LbgLoNAxnq6Sfz4pTxi4NWG7s5l+dPe7K+L4kXb0oOfwl3Yq3Ro7CNPGLrU4cmTXhaA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">= 8" + "node": ">= 10" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@node-rs/crc32-android-arm64": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-android-arm64/-/crc32-android-arm64-1.10.7.tgz", + "integrity": "sha512-lLUVm2H5HrSm/g2379JBRsSr5RCDqobP6I5sxZd+wSq6WBH2b6goilNYhxbss8gYQZLCJA09EvyFkZFFU9VuAQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">= 8" + "node": ">= 10" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@node-rs/crc32-darwin-arm64": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-darwin-arm64/-/crc32-darwin-arm64-1.10.7.tgz", + "integrity": "sha512-8slhmrRa3B3/z+MnLgST+lR5T0Oic60YTQ3S9OIHP259GiktlmdYyebhAvy0bBcyCuScLDcW0EB3sXxWw1TCbQ==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 8" + "node": ">= 10" } }, - "node_modules/@sec-ant/readable-stream": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", - "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "node_modules/@node-rs/crc32-darwin-x64": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-darwin-x64/-/crc32-darwin-x64-1.10.7.tgz", + "integrity": "sha512-+RkQ2+jSWco0WqSPq7GWJlJwmJpIGA79OoToGTSAsqgypkls4i3PlexVTPrfepuHn3whpa4GrmjvLbRm5RXgCQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } }, - "node_modules/@sindresorhus/merge-streams": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", - "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "node_modules/@node-rs/crc32-freebsd-x64": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-freebsd-x64/-/crc32-freebsd-x64-1.10.7.tgz", + "integrity": "sha512-yqtsf23JCO1gYt3/Rkk5aoVn1rINk/J7//A9EKwGstNpBBlN3t0JKD3QpGzEnqc1vS72lEvIeO9sO3XiH+hJWw==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 10" } }, - "node_modules/@stellar/js-xdr": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@stellar/js-xdr/-/js-xdr-3.1.2.tgz", - "integrity": "sha512-VVolPL5goVEIsvuGqDc5uiKxV03lzfWdvYg1KikvwheDmTBO68CKDji3bAZ/kppZrx5iTA8z3Ld5yuytcvhvOQ==", - "license": "Apache-2.0" - }, - "node_modules/@stellar/stellar-base": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-14.1.0.tgz", - "integrity": "sha512-A8kFli6QGy22SRF45IjgPAJfUNGjnI+R7g4DF5NZYVsD1kGf7B4ITyc4OPclLV9tqNI4/lXxafGEw0JEUbHixw==", - "deprecated": "This package is now rolled into @stellar/stellar-sdk. Please use @stellar/stellar-sdk to continue receiving updates and support.", - "license": "Apache-2.0", - "dependencies": { - "@noble/curves": "^1.9.6", - "@stellar/js-xdr": "^3.1.2", - "base32.js": "^0.1.0", - "bignumber.js": "^9.3.1", - "buffer": "^6.0.3", - "sha.js": "^2.4.12" - }, + "node_modules/@node-rs/crc32-linux-arm-gnueabihf": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm-gnueabihf/-/crc32-linux-arm-gnueabihf-1.10.7.tgz", + "integrity": "sha512-AB/I1GO9LDIIHiur2bexqPy30740AmBjEhO8ij9k9desVO41dN5/ddTU2+xbf9TYt2XXvku1qYbtf5YHAAVFAw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=20.0.0" + "node": ">= 10" } }, - "node_modules/@stellar/stellar-sdk": { - "version": "14.6.1", - "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-14.6.1.tgz", - "integrity": "sha512-A1rQWDLdUasXkMXnYSuhgep+3ZZzyuXJKdt5/KAIc0gkmSp906HTvUpbT4pu+bVr41tu0+J4Ugz9J4BQAGGytg==", - "license": "Apache-2.0", - "dependencies": { - "@stellar/stellar-base": "^14.1.0", - "axios": "^1.13.3", - "bignumber.js": "^9.3.1", - "commander": "^14.0.2", - "eventsource": "^2.0.2", - "feaxios": "^0.0.23", - "randombytes": "^2.1.0", - "toml": "^3.0.0", - "urijs": "^1.19.1" - }, - "bin": { - "stellar-js": "bin/stellar-js" - }, + "node_modules/@node-rs/crc32-linux-arm64-gnu": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm64-gnu/-/crc32-linux-arm64-gnu-1.10.7.tgz", + "integrity": "sha512-0lPFuudkW+bpeXUZAqz6FSml6Z2JvF52UGSALvnDS8Qyg3wKBNWjcXy78Pw1wiIGao/AAFFr74I3OwCMzYujuQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=20.0.0" + "node": ">= 10" } }, - "node_modules/@stryker-mutator/api": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@stryker-mutator/api/-/api-9.6.1.tgz", - "integrity": "sha512-g8VNoFWQWbx0pdal3Vt8jVCZW+v3sc3gi94iI0GVtVgUGTqphAjJF6EAruPTx0lqvtonsaAxn5TD36hcG1d6Wg==", + "node_modules/@node-rs/crc32-linux-arm64-musl": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-arm64-musl/-/crc32-linux-arm64-musl-1.10.7.tgz", + "integrity": "sha512-lx5m7iCmdXPGigG7AI5NiawWsiJ1HwR/w6PV8XN48HNsgzdjar0ISB8TSLtJpq+jFcj10Wcz3Rt43RA72652Vg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "Apache-2.0", - "dependencies": { - "mutation-testing-metrics": "3.7.3", - "mutation-testing-report-schema": "3.7.3", - "tslib": "~2.8.0", - "typed-inject": "~5.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=20.0.0" + "node": ">= 10" } }, - "node_modules/@stryker-mutator/core": { + "node_modules/@node-rs/crc32-linux-x64-gnu": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-x64-gnu/-/crc32-linux-x64-gnu-1.10.7.tgz", + "integrity": "sha512-If3ogA9D2XKKb8vHttu+jl3BTWT7UCTgmrXmUAwQABH45iK32AZ9OoMcrg2rWKKXgGpG6x3IslFBgzdOkObDnA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/crc32-linux-x64-musl": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-linux-x64-musl/-/crc32-linux-x64-musl-1.10.7.tgz", + "integrity": "sha512-XxuxZYJhQBlo2rRnyOOummZSyBdC+jHpXWM9XSWs1LWfsgc36IauKY+XXRAJwKwefx8lwmMjqp6T/Zq9frU87w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/crc32-win32-arm64-msvc": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-arm64-msvc/-/crc32-win32-arm64-msvc-1.10.7.tgz", + "integrity": "sha512-Rs8TGuvxgpkteSLhPqAb3DOqqRO1jiYghdMxozl+P3Ftep1hTWL8+gwYF5dtu1BtdOJpz23A+8GehSuwl96MrQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/crc32-win32-ia32-msvc": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-ia32-msvc/-/crc32-win32-ia32-msvc-1.10.7.tgz", + "integrity": "sha512-G/xNcmblMH6Z7KBX02XJPJj2UGo6eTgFa+r5ZU17O8V5P9iQLrKqs/T7Sz40otDxazD1maSXT/zA8Q7rBu2/3g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@node-rs/crc32-win32-x64-msvc": { + "version": "1.10.7", + "resolved": "https://registry.npmjs.org/@node-rs/crc32-win32-x64-msvc/-/crc32-win32-x64-msvc-1.10.7.tgz", + "integrity": "sha512-1uXrMu17uz12WPdii84NXmoQsoPdmSQViyCMJPu0KQuwnhErQCA4PoGK+dih9jY0mrcLuzR1r5wXVaE049fJ6w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/config-creator": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/config-creator/-/config-creator-10.2.2.tgz", + "integrity": "sha512-BynOBe7Hn3LJjb3CqCHZjeNB09s/vgf0baBaHVw67w7gHF0d25c3ZsZ5+vv8TgwSchRdUCRrbbcq5i2B1fJ2QQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/config-loader": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/config-loader/-/config-loader-10.2.2.tgz", + "integrity": "sha512-ndjjQNgLg4DIcMJp4iaRD6xb9ijWQZVbd9694Ol2IszBIbGPPkwZHzJYKICbTBmh6AH/pLr0CiCaWdGJU7RbpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/profiler": "^10.2.2", + "@secretlint/resolver": "^10.2.2", + "@secretlint/types": "^10.2.2", + "ajv": "^8.17.1", + "debug": "^4.4.1", + "rc-config-loader": "^4.1.3" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/config-loader/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@secretlint/config-loader/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/core": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/core/-/core-10.2.2.tgz", + "integrity": "sha512-6rdwBwLP9+TO3rRjMVW1tX+lQeo5gBbxl1I5F8nh8bgGtKwdlCMhMKsBWzWg1ostxx/tIG7OjZI0/BxsP8bUgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/profiler": "^10.2.2", + "@secretlint/types": "^10.2.2", + "debug": "^4.4.1", + "structured-source": "^4.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/formatter": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/formatter/-/formatter-10.2.2.tgz", + "integrity": "sha512-10f/eKV+8YdGKNQmoDUD1QnYL7TzhI2kzyx95vsJKbEa8akzLAR5ZrWIZ3LbcMmBLzxlSQMMccRmi05yDQ5YDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/resolver": "^10.2.2", + "@secretlint/types": "^10.2.2", + "@textlint/linter-formatter": "^15.2.0", + "@textlint/module-interop": "^15.2.0", + "@textlint/types": "^15.2.0", + "chalk": "^5.4.1", + "debug": "^4.4.1", + "pluralize": "^8.0.0", + "strip-ansi": "^7.1.0", + "table": "^6.9.0", + "terminal-link": "^4.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/formatter/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@secretlint/formatter/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@secretlint/formatter/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@secretlint/node": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/node/-/node-10.2.2.tgz", + "integrity": "sha512-eZGJQgcg/3WRBwX1bRnss7RmHHK/YlP/l7zOQsrjexYt6l+JJa5YhUmHbuGXS94yW0++3YkEJp0kQGYhiw1DMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/config-loader": "^10.2.2", + "@secretlint/core": "^10.2.2", + "@secretlint/formatter": "^10.2.2", + "@secretlint/profiler": "^10.2.2", + "@secretlint/source-creator": "^10.2.2", + "@secretlint/types": "^10.2.2", + "debug": "^4.4.1", + "p-map": "^7.0.3" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/profiler": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/profiler/-/profiler-10.2.2.tgz", + "integrity": "sha512-qm9rWfkh/o8OvzMIfY8a5bCmgIniSpltbVlUVl983zDG1bUuQNd1/5lUEeWx5o/WJ99bXxS7yNI4/KIXfHexig==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/resolver": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/resolver/-/resolver-10.2.2.tgz", + "integrity": "sha512-3md0cp12e+Ae5V+crPQYGd6aaO7ahw95s28OlULGyclyyUtf861UoRGS2prnUrKh7MZb23kdDOyGCYb9br5e4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/secretlint-formatter-sarif": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-formatter-sarif/-/secretlint-formatter-sarif-10.2.2.tgz", + "integrity": "sha512-ojiF9TGRKJJw308DnYBucHxkpNovDNu1XvPh7IfUp0A12gzTtxuWDqdpuVezL7/IP8Ua7mp5/VkDMN9OLp1doQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-sarif-builder": "^3.2.0" + } + }, + "node_modules/@secretlint/secretlint-rule-no-dotenv": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-no-dotenv/-/secretlint-rule-no-dotenv-10.2.2.tgz", + "integrity": "sha512-KJRbIShA9DVc5Va3yArtJ6QDzGjg3PRa1uYp9As4RsyKtKSSZjI64jVca57FZ8gbuk4em0/0Jq+uy6485wxIdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/secretlint-rule-preset-recommend": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-preset-recommend/-/secretlint-rule-preset-recommend-10.2.2.tgz", + "integrity": "sha512-K3jPqjva8bQndDKJqctnGfwuAxU2n9XNCPtbXVI5JvC7FnQiNg/yWlQPbMUlBXtBoBGFYp08A94m6fvtc9v+zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/source-creator": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/source-creator/-/source-creator-10.2.2.tgz", + "integrity": "sha512-h6I87xJfwfUTgQ7irWq7UTdq/Bm1RuQ/fYhA3dtTIAop5BwSFmZyrchph4WcoEvbN460BWKmk4RYSvPElIIvxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2", + "istextorbinary": "^9.5.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/types": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/types/-/types-10.2.2.tgz", + "integrity": "sha512-Nqc90v4lWCXyakD6xNyNACBJNJ0tNCwj2WNk/7ivyacYHxiITVgmLUFXTBOeCdy79iz6HtN9Y31uw/jbLrdOAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@stellar/js-xdr": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@stellar/js-xdr/-/js-xdr-3.1.2.tgz", + "integrity": "sha512-VVolPL5goVEIsvuGqDc5uiKxV03lzfWdvYg1KikvwheDmTBO68CKDji3bAZ/kppZrx5iTA8z3Ld5yuytcvhvOQ==", + "license": "Apache-2.0" + }, + "node_modules/@stellar/stellar-base": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@stellar/stellar-base/-/stellar-base-14.1.0.tgz", + "integrity": "sha512-A8kFli6QGy22SRF45IjgPAJfUNGjnI+R7g4DF5NZYVsD1kGf7B4ITyc4OPclLV9tqNI4/lXxafGEw0JEUbHixw==", + "deprecated": "This package is now rolled into @stellar/stellar-sdk. Please use @stellar/stellar-sdk to continue receiving updates and support.", + "license": "Apache-2.0", + "dependencies": { + "@noble/curves": "^1.9.6", + "@stellar/js-xdr": "^3.1.2", + "base32.js": "^0.1.0", + "bignumber.js": "^9.3.1", + "buffer": "^6.0.3", + "sha.js": "^2.4.12" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@stellar/stellar-sdk": { + "version": "14.6.1", + "resolved": "https://registry.npmjs.org/@stellar/stellar-sdk/-/stellar-sdk-14.6.1.tgz", + "integrity": "sha512-A1rQWDLdUasXkMXnYSuhgep+3ZZzyuXJKdt5/KAIc0gkmSp906HTvUpbT4pu+bVr41tu0+J4Ugz9J4BQAGGytg==", + "license": "Apache-2.0", + "dependencies": { + "@stellar/stellar-base": "^14.1.0", + "axios": "^1.13.3", + "bignumber.js": "^9.3.1", + "commander": "^14.0.2", + "eventsource": "^2.0.2", + "feaxios": "^0.0.23", + "randombytes": "^2.1.0", + "toml": "^3.0.0", + "urijs": "^1.19.1" + }, + "bin": { + "stellar-js": "bin/stellar-js" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@stryker-mutator/api": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@stryker-mutator/api/-/api-9.6.1.tgz", + "integrity": "sha512-g8VNoFWQWbx0pdal3Vt8jVCZW+v3sc3gi94iI0GVtVgUGTqphAjJF6EAruPTx0lqvtonsaAxn5TD36hcG1d6Wg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "mutation-testing-metrics": "3.7.3", + "mutation-testing-report-schema": "3.7.3", + "tslib": "~2.8.0", + "typed-inject": "~5.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@stryker-mutator/core": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/@stryker-mutator/core/-/core-9.6.1.tgz", "integrity": "sha512-WMgnvf+Wyh/yiruhNZwc8w8DlzmmjXhPjSn5MR8RhAXzlnWji8TQrUYgBUkHk9bEgSaIlB3KZHm37iiU5Q2cLQ==", @@ -1864,12 +2539,75 @@ "mocha": ">= 7.2 < 12" } }, - "node_modules/@stryker-mutator/util": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/@stryker-mutator/util/-/util-9.6.1.tgz", - "integrity": "sha512-Lk/ALVctJjFv1vvwR+CFoKzDCWvsBlq7flDUnmnpuwTrGbm156EdZD1Jjq4o8KdOap0ezUZqQNE9OAI1m2+pUQ==", + "node_modules/@stryker-mutator/util": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/@stryker-mutator/util/-/util-9.6.1.tgz", + "integrity": "sha512-Lk/ALVctJjFv1vvwR+CFoKzDCWvsBlq7flDUnmnpuwTrGbm156EdZD1Jjq4o8KdOap0ezUZqQNE9OAI1m2+pUQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@textlint/ast-node-types": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-15.8.0.tgz", + "integrity": "sha512-5CiH9COYmovWmExQgs7763DzX6Gy9zjkjJ7JxCC95wyTcjwQn/8poNF6fv3qzRlmx8CRRde8DHr9FcgAAiPzgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/linter-formatter": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/@textlint/linter-formatter/-/linter-formatter-15.8.0.tgz", + "integrity": "sha512-+oU3A235NATv6Lzi4xa4kJ65PuNJlIxesaO4AvDhDWA9FWm7y4XKWaoQCW1esgaQQ6dwnUiFKArQ8TcJ86mC4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azu/format-text": "^1.0.2", + "@azu/style-format": "^1.0.1", + "@textlint/module-interop": "15.8.0", + "@textlint/resolver": "15.8.0", + "@textlint/types": "15.8.0", + "debug": "^4.4.3", + "js-yaml": "^4.3.0", + "lodash": "^4.18.1", + "pluralize": "^2.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "table": "^6.9.0", + "text-table": "^0.2.0" + }, + "engines": { + "node": ">=20.18.0" + } + }, + "node_modules/@textlint/linter-formatter/node_modules/pluralize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-2.0.0.tgz", + "integrity": "sha512-TqNZzQCD4S42De9IfnnBvILN7HAW7riLqsCyp8lgjXeysyPlX5HhqKAcJHHHb9XskE4/a+7VGC9zzx8Ls0jOAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/module-interop": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/@textlint/module-interop/-/module-interop-15.8.0.tgz", + "integrity": "sha512-rt+OR1WYGoLOY8HkA/aBPrqufF6yUUEsKEAh7XohTsT3lp9IyZFT6zOIbjul9P4FAzsmSPkcrYjVx3Bz/IUfkg==", "dev": true, - "license": "Apache-2.0" + "license": "MIT" + }, + "node_modules/@textlint/resolver": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/@textlint/resolver/-/resolver-15.8.0.tgz", + "integrity": "sha512-E88tzfX3K8Jykk+38aJ9cy8RquD8ABVOPTO2rFEESq0wcg8x6/ypdAS8ZgR7OKiGqlRF0hkO/m5PbQwVfKM3VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/types": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/@textlint/types/-/types-15.8.0.tgz", + "integrity": "sha512-Anhc6y5736YIsvqae0U6k0YmB2M/QVHkEeOv2aydAn/WIkdI69dCOiDbe3/+RagS3qstFTSFWJzNRA2lUjv19w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "15.8.0" + } }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", @@ -1895,6 +2633,20 @@ "undici-types": "~6.21.0" } }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/sarif": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.7.tgz", + "integrity": "sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/vscode": { "version": "1.120.0", "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.120.0.tgz", @@ -2135,6 +2887,45 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@typespec/ts-http-runtime": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.8.tgz", + "integrity": "sha512-bLMpVcWZNzq6lYOybwFwOAR1IXKcHnhUNqYeHjl1bET/qE3jFPFH+p8Wrh3rU4xwdnifPxmKNESBYnvnmc75aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@typespec/ts-http-runtime/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/@typespec/ts-http-runtime/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.1.tgz", @@ -2173,6 +2964,238 @@ "integrity": "sha512-2J27dysaXmvnfuhFGhfeuxfHRXunqNPxtBoR3koiTOA9rdxWNDTa1zIFLCFMSHJ9MPTPKFcBeblsyaCJCIlQxg==", "license": "MIT" }, + "node_modules/@vscode/vsce": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.9.2.tgz", + "integrity": "sha512-XSxMosEEDO6vLxELAHVkwmhC0qe0ijZni2jB9Rcs8kQsW4lhTDQ/wMzmwFs/buotAWSnpmUp/dRWD2ufG3UYKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/identity": "^4.1.0", + "@secretlint/node": "^10.1.2", + "@secretlint/secretlint-formatter-sarif": "^10.1.2", + "@secretlint/secretlint-rule-no-dotenv": "^10.1.2", + "@secretlint/secretlint-rule-preset-recommend": "^10.1.2", + "@vscode/vsce-sign": "^2.0.0", + "azure-devops-node-api": "^12.5.0", + "chalk": "^4.1.2", + "cheerio": "^1.0.0-rc.9", + "cockatiel": "^3.1.2", + "commander": "^12.1.0", + "form-data": "^4.0.0", + "glob": "^13.0.6", + "hosted-git-info": "^4.0.2", + "jsonc-parser": "^3.2.0", + "leven": "^3.1.0", + "markdown-it": "^14.1.0", + "mime": "^1.3.4", + "minimatch": "^10.2.2", + "parse-semver": "^1.1.1", + "read": "^1.0.7", + "secretlint": "^10.1.2", + "semver": "^7.5.2", + "tmp": "^0.2.3", + "typed-rest-client": "^1.8.4", + "url-join": "^4.0.1", + "xml2js": "^0.5.0", + "yauzl": "^3.2.1", + "yazl": "^2.2.2" + }, + "bin": { + "vsce": "vsce" + }, + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "keytar": "^7.7.0" + } + }, + "node_modules/@vscode/vsce-sign": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign/-/vsce-sign-2.1.0.tgz", + "integrity": "sha512-9AQrqazrBgTgRSuwleLVXUrIUphY02/SFCh2TKYoLV/xifJAdblhdmEmw5gUrYSPQ3sRwNs9iyCMD14sATEE6g==", + "dev": true, + "hasInstallScript": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optionalDependencies": { + "@vscode/vsce-sign-alpine-arm64": "2.0.6", + "@vscode/vsce-sign-alpine-x64": "2.0.6", + "@vscode/vsce-sign-darwin-arm64": "2.0.6", + "@vscode/vsce-sign-darwin-x64": "2.0.6", + "@vscode/vsce-sign-linux-arm": "2.0.6", + "@vscode/vsce-sign-linux-arm64": "2.0.6", + "@vscode/vsce-sign-linux-x64": "2.0.6", + "@vscode/vsce-sign-win32-arm64": "2.0.6", + "@vscode/vsce-sign-win32-x64": "2.0.6" + } + }, + "node_modules/@vscode/vsce-sign-alpine-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-arm64/-/vsce-sign-alpine-arm64-2.0.6.tgz", + "integrity": "sha512-wKkJBsvKF+f0GfsUuGT0tSW0kZL87QggEiqNqK6/8hvqsXvpx8OsTEc3mnE1kejkh5r+qUyQ7PtF8jZYN0mo8Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "alpine" + ] + }, + "node_modules/@vscode/vsce-sign-alpine-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-x64/-/vsce-sign-alpine-x64-2.0.6.tgz", + "integrity": "sha512-YoAGlmdK39vKi9jA18i4ufBbd95OqGJxRvF3n6ZbCyziwy3O+JgOpIUPxv5tjeO6gQfx29qBivQ8ZZTUF2Ba0w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "alpine" + ] + }, + "node_modules/@vscode/vsce-sign-darwin-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-arm64/-/vsce-sign-darwin-arm64-2.0.6.tgz", + "integrity": "sha512-5HMHaJRIQuozm/XQIiJiA0W9uhdblwwl2ZNDSSAeXGO9YhB9MH5C4KIHOmvyjUnKy4UCuiP43VKpIxW1VWP4tQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/vsce-sign-darwin-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-x64/-/vsce-sign-darwin-x64-2.0.6.tgz", + "integrity": "sha512-25GsUbTAiNfHSuRItoQafXOIpxlYj+IXb4/qarrXu7kmbH94jlm5sdWSCKrrREs8+GsXF1b+l3OB7VJy5jsykw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/vsce-sign-linux-arm": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm/-/vsce-sign-linux-arm-2.0.6.tgz", + "integrity": "sha512-UndEc2Xlq4HsuMPnwu7420uqceXjs4yb5W8E2/UkaHBB9OWCwMd3/bRe/1eLe3D8kPpxzcaeTyXiK3RdzS/1CA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-linux-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm64/-/vsce-sign-linux-arm64-2.0.6.tgz", + "integrity": "sha512-cfb1qK7lygtMa4NUl2582nP7aliLYuDEVpAbXJMkDq1qE+olIw/es+C8j1LJwvcRq1I2yWGtSn3EkDp9Dq5FdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-linux-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-x64/-/vsce-sign-linux-x64-2.0.6.tgz", + "integrity": "sha512-/olerl1A4sOqdP+hjvJ1sbQjKN07Y3DVnxO4gnbn/ahtQvFrdhUi0G1VsZXDNjfqmXw57DmPi5ASnj/8PGZhAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-win32-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-arm64/-/vsce-sign-win32-arm64-2.0.6.tgz", + "integrity": "sha512-ivM/MiGIY0PJNZBoGtlRBM/xDpwbdlCWomUWuLmIxbi1Cxe/1nooYrEQoaHD8ojVRgzdQEUzMsRbyF5cJJgYOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vscode/vsce-sign-win32-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-x64/-/vsce-sign-win32-x64-2.0.6.tgz", + "integrity": "sha512-mgth9Kvze+u8CruYMmhHw6Zgy3GRX2S+Ed5oSokDEK5vPEwGGKnmuXua9tmFhomeAnhgJnL4DCna3TiNuGrBTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vscode/vsce/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@vscode/vsce/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vscode/vsce/node_modules/typed-rest-client": { + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz", + "integrity": "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "qs": "^6.9.1", + "tunnel": "0.0.6", + "underscore": "^1.12.1" + } + }, "node_modules/acorn": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", @@ -2245,6 +3268,22 @@ "node": ">=6" } }, + "node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", @@ -2292,6 +3331,16 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -2325,6 +3374,29 @@ "proxy-from-env": "^2.1.0" } }, + "node_modules/azure-devops-node-api": { + "version": "12.5.0", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz", + "integrity": "sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==", + "dev": true, + "license": "MIT", + "dependencies": { + "tunnel": "0.0.6", + "typed-rest-client": "^1.8.4" + } + }, + "node_modules/azure-devops-node-api/node_modules/typed-rest-client": { + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz", + "integrity": "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "qs": "^6.9.1", + "tunnel": "0.0.6", + "underscore": "^1.12.1" + } + }, "node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", @@ -2399,6 +3471,75 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/binaryextensions": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-6.11.0.tgz", + "integrity": "sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/boundary": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/boundary/-/boundary-2.0.0.tgz", + "integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/brace-expansion": { "version": "5.0.6", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", @@ -2486,8 +3627,41 @@ ], "license": "MIT", "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/c8": { @@ -2683,6 +3857,50 @@ "dev": true, "license": "MIT" }, + "node_modules/cheerio": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz", + "integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "encoding-sniffer": "^0.2.1", + "htmlparser2": "^10.1.0", + "parse5": "^7.3.0", + "parse5-htmlparser2-tree-adapter": "^7.1.0", + "parse5-parser-stream": "^7.1.2", + "undici": "^7.19.0", + "whatwg-mimetype": "^4.0.0" + }, + "engines": { + "node": ">=20.18.1" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/chokidar": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", @@ -2721,6 +3939,21 @@ "node": ">= 6" } }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true, + "license": "MIT" + }, "node_modules/cli-width": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", @@ -2743,6 +3976,16 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/cockatiel": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/cockatiel/-/cockatiel-3.2.1.tgz", + "integrity": "sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -2813,6 +4056,36 @@ "node": ">= 8" } }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/debug": { "version": "4.4.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", @@ -2843,6 +4116,34 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -2850,6 +4151,36 @@ "dev": true, "license": "MIT" }, + "node_modules/default-browser": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz", + "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -2867,6 +4198,37 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2887,6 +4249,17 @@ "minimalistic-assert": "^1.0.0" } }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/diff": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz", @@ -2917,6 +4290,65 @@ "node": ">=6.0.0" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -2931,6 +4363,33 @@ "node": ">= 0.4" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/editions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/editions/-/editions-6.22.0.tgz", + "integrity": "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "version-range": "^4.15.0" + }, + "engines": { + "ecmascript": ">= es5", + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.392", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.392.tgz", @@ -2945,6 +4404,70 @@ "dev": true, "license": "MIT" }, + "node_modules/encoding-sniffer": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", + "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "^0.6.3", + "whatwg-encoding": "^3.1.1" + }, + "funding": { + "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" + } + }, + "node_modules/encoding-sniffer/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -3294,6 +4817,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "license": "(MIT OR WTFPL)", + "optional": true, + "engines": { + "node": ">=6" + } + }, "node_modules/fast-check": { "version": "4.9.0", "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.9.0.tgz", @@ -3324,6 +4858,36 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -3563,14 +5127,37 @@ "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "license": "MIT", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/fs-extra": { + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.0.tgz", + "integrity": "sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">= 6" + "node": ">=14.14" } }, "node_modules/fs.realpath": { @@ -3678,6 +5265,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", @@ -3758,6 +5353,57 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", + "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.3", + "path-type": "^6.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -3770,6 +5416,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -3848,6 +5501,39 @@ "he": "bin/he" } }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -3855,6 +5541,63 @@ "dev": true, "license": "MIT" }, + "node_modules/htmlparser2": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "entities": "^7.0.1" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", @@ -3952,6 +5695,19 @@ "node": ">=0.8.19" } }, + "node_modules/index-to-position": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", + "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -3970,6 +5726,14 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC", + "optional": true + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -3995,6 +5759,35 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -4028,6 +5821,38 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-it-type": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/is-it-type/-/is-it-type-5.1.3.tgz", + "integrity": "sha512-AX2uU0HW+TxagTgQXOJY7+2fbFHemC7YFBwN1XqD8qQMKdtfbOC8OC3fUb4s5NU59a3662Dzwto8tWDdZYRXxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "globalthis": "^1.0.2" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -4111,6 +5936,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", @@ -4163,6 +6004,24 @@ "node": ">=8" } }, + "node_modules/istextorbinary": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-9.5.0.tgz", + "integrity": "sha512-5mbUj3SiZXCuRf9fT3ibzbSSEWiy63gFfksmGfdOzujPjW3k+z8WvIBxcJHBoQNlaZaiyB25deviif2+osLmLw==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "binaryextensions": "^6.11.0", + "editions": "^6.21.0", + "textextensions": "^6.11.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, "node_modules/js-md4": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz", @@ -4178,9 +6037,9 @@ "license": "MIT" }, "node_modules/js-yaml": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.2.0.tgz", - "integrity": "sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", "dev": true, "funding": [ { @@ -4254,6 +6113,85 @@ "node": ">=6" } }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", + "dev": true, + "license": "MIT", + "dependencies": { + "jws": "^4.0.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/keytar": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", + "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-addon-api": "^4.3.0", + "prebuild-install": "^7.0.1" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -4264,6 +6202,16 @@ "json-buffer": "3.0.1" } }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -4278,6 +6226,26 @@ "node": ">= 0.8.0" } }, + "node_modules/linkify-it": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz", + "integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -4294,6 +6262,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.groupby": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", @@ -4301,6 +6276,48 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -4308,6 +6325,20 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "license": "MIT" + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -4351,6 +6382,34 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/markdown-it": { + "version": "14.3.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.3.0.tgz", + "integrity": "sha512-RCEsPjR+sr0x+AuYp601tKTkgFG4YEPLCzHST3cQ/fhlJkqAkz1L2/Qbp1j9qw5SBwQHFBoW8+hoN5xssOF0Tw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.5.0", + "linkify-it": "^5.0.2", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -4360,6 +6419,50 @@ "node": ">= 0.4" } }, + "node_modules/mdurl": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.1.0.tgz", + "integrity": "sha512-1+HBaOx0zi/dQWht8rNv9MYf9qqpqL/kxI0hXImU6Y547zM6Sni8BQibt7ifgMcYtQg41ao3Ivd6cnSM86inpg==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -4381,6 +6484,20 @@ "node": ">= 0.6" } }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -4404,6 +6521,17 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "optional": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/minipass": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", @@ -4414,6 +6542,14 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/mocha": { "version": "10.8.2", "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", @@ -4549,6 +6685,14 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -4556,6 +6700,28 @@ "dev": true, "license": "MIT" }, + "node_modules/node-abi": { + "version": "3.94.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.94.0.tgz", + "integrity": "sha512-W5ZNO5KRPB5TkYmGVD9F6YqhsglXJzE6etpbmT+f6EQElhiX/UTG551cnsRGvLG3fyZEg9HwaDmNmj5nwJ4z9g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/node-releases": { "version": "2.0.51", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", @@ -4566,6 +6732,55 @@ "node": ">=18" } }, + "node_modules/node-sarif-builder": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/node-sarif-builder/-/node-sarif-builder-3.4.0.tgz", + "integrity": "sha512-tGnJW6OKRii9u/b2WiUViTJS+h7Apxx17qsMUjsUeNDiMMX5ZFf8F8Fcz7PAQ6omvOxHZtvDTmOYKJQwmfpjeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sarif": "^2.1.7", + "fs-extra": "^11.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -4606,6 +6821,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -4619,6 +6847,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -4629,6 +6867,25 @@ "wrappy": "1" } }, + "node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -4647,62 +6904,212 @@ "node": ">= 0.8.0" } }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/ovsx": { + "version": "0.10.12", + "resolved": "https://registry.npmjs.org/ovsx/-/ovsx-0.10.12.tgz", + "integrity": "sha512-WwMj1iQDvCk02029oxPnkFXsPrHZ+WzmoNW5pJ8JGepHtL30i2JE4s3C3wqzQqj6a35vx2hp0gV3TdfefGmvMg==", + "dev": true, + "license": "EPL-2.0", + "dependencies": { + "@vscode/vsce": "^3.7.1", + "commander": "^6.2.1", + "follow-redirects": "^1.16.0", + "is-ci": "^2.0.0", + "leven": "^3.1.0", + "semver": "^7.6.0", + "tmp": "^0.2.3", + "yauzl-promise": "^4.0.0" + }, + "bin": { + "ovsx": "bin/ovsx" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/ovsx/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.6.tgz", + "integrity": "sha512-I4Prw6ivkd6p8PiYR1tXASOAOBzIJwu0TB7fqaX0c/8c3QAehNYmX57EijyGGGBt3c/BIowGwV03RVBtXvHEVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-json/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-semver": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", + "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^5.1.0" + } + }, + "node_modules/parse-semver/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", "dev": true, "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" + "entities": "^6.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", "dev": true, "license": "MIT", "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" + "domhandler": "^5.0.3", + "parse5": "^7.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "node_modules/parse5-parser-stream": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", + "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", "dev": true, "license": "MIT", "dependencies": { - "callsites": "^3.0.0" + "parse5": "^7.0.0" }, - "engines": { - "node": ">=6" + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/parse-ms": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", - "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "engines": { - "node": ">=18" + "node": ">=0.12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/path-exists": { @@ -4752,6 +7159,26 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/path-type": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -4772,6 +7199,16 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -4781,6 +7218,35 @@ "node": ">= 0.4" } }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -4826,6 +7292,18 @@ "node": ">=10" } }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -4836,6 +7314,16 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/pure-rand": { "version": "8.4.2", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-8.4.2.tgz", @@ -4899,6 +7387,129 @@ "safe-buffer": "^5.1.0" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "optional": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc-config-loader": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.4.tgz", + "integrity": "sha512-3GiwEzklkbXTDp52UR5nT8iXgYAx1V9ZG/kDZT7p60u2GCv2XTwQq4NzinMoMpNtXhmt3WkhYXcj6HH8HdwCEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "js-yaml": "^4.1.1", + "json5": "^2.2.3", + "require-from-string": "^2.0.2" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read/node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true, + "license": "ISC" + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -5023,6 +7634,19 @@ "node": "*" } }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -5084,6 +7708,38 @@ "dev": true, "license": "MIT" }, + "node_modules/sax": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/secretlint": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/secretlint/-/secretlint-10.2.2.tgz", + "integrity": "sha512-xVpkeHV/aoWe4vP4TansF622nBEImzCY73y/0042DuJ29iKIaqgoJ8fGxre3rVSHHbxar4FdJobmTnLp9AU0eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/config-creator": "^10.2.2", + "@secretlint/formatter": "^10.2.2", + "@secretlint/node": "^10.2.2", + "@secretlint/profiler": "^10.2.2", + "debug": "^4.4.1", + "globby": "^14.1.0", + "read-pkg": "^9.0.1" + }, + "bin": { + "secretlint": "bin/secretlint.js" + }, + "engines": { + "node": ">=20.0.0" + } + }, "node_modules/semver": { "version": "7.8.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", @@ -5223,37 +7879,127 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-invariant": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/simple-invariant/-/simple-invariant-2.0.1.tgz", + "integrity": "sha512-1sbhsxqI+I2tqlmjbz99GXNmZtr6tKIyEgGGnJw/MKGblalqk/XoOYYFJlBzTKZCxx8kLaD3FD5s9BEEjx5Pyg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, "engines": { - "node": ">= 0.4" + "node": ">=14.16" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, "engines": { - "node": ">=14" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, "node_modules/source-map": { @@ -5266,6 +8012,53 @@ "node": ">= 12" } }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -5320,6 +8113,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/structured-source": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-4.0.0.tgz", + "integrity": "sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boundary": "^2.0.0" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5333,6 +8136,113 @@ "node": ">=8" } }, + "node_modules/supports-hyperlinks": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", + "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" + } + }, + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/tar-fs": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.5.tgz", + "integrity": "sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terminal-link": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-4.0.0.tgz", + "integrity": "sha512-lk+vH+MccxNqgVqSnkMVKx4VLJfnLjDBGzH16JVZjKE2DoxP57s6/vt6JmXV5I3jBcfGrxNrYtC+mPtU7WJztA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "supports-hyperlinks": "^3.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/test-exclude": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-8.0.0.tgz", @@ -5373,6 +8283,22 @@ "dev": true, "license": "MIT" }, + "node_modules/textextensions": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-6.11.0.tgz", + "integrity": "sha512-tXJwSr9355kFJI3lbCkPpUH5cP8/M0GGy2xLO34aZCjMXBaK3SoPnZwr/oWmo1FdCnELcs4npdCIOFtq9W3ruQ==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, "node_modules/tinyglobby": { "version": "0.2.17", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", @@ -5421,6 +8347,16 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/tmp": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, "node_modules/to-buffer": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", @@ -5494,6 +8430,20 @@ "node": ">=0.6.11 <=0.7.0 || >=0.7.3" } }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -5575,6 +8525,13 @@ "node": ">=14.17" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" + }, "node_modules/underscore": { "version": "1.13.8", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz", @@ -5582,6 +8539,16 @@ "dev": true, "license": "MIT" }, + "node_modules/undici": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.0.tgz", + "integrity": "sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, "node_modules/undici-types": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", @@ -5602,6 +8569,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/update-browserslist-db": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", @@ -5649,6 +8626,21 @@ "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", "license": "MIT" }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "dev": true, + "license": "MIT" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/v8-to-istanbul": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", @@ -5664,6 +8656,30 @@ "node": ">=10.12.0" } }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/version-range": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/version-range/-/version-range-4.15.0.tgz", + "integrity": "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==", + "dev": true, + "license": "Artistic-2.0", + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, "node_modules/wasmparser": { "version": "5.11.1", "resolved": "https://registry.npmjs.org/wasmparser/-/wasmparser-5.11.1.tgz", @@ -5698,6 +8714,43 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5777,6 +8830,46 @@ "dev": true, "license": "ISC" }, + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -5839,6 +8932,44 @@ "node": ">=10" } }, + "node_modules/yauzl": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.4.0.tgz", + "integrity": "sha512-jIH9yLR9wqr0wOS0TpBvo/g/2UgZH5qePVbjgRliiF0BYvOZyaBknKsF+x9Iht0O6sqgnB93rCICdOZFecJuDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yauzl-promise/-/yauzl-promise-4.0.0.tgz", + "integrity": "sha512-/HCXpyHXJQQHvFq9noqrjfa/WpQC2XYs3vI7tBiAi4QiIU1knvYhZGaO1QPjwIVMdqflxbmwgMXtYeaRiAE0CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@node-rs/crc32": "^1.7.0", + "is-it-type": "^5.1.2", + "simple-invariant": "^2.0.1" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index f7a465f..0c10d64 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,28 @@ { "name": "stellar-debugger", "displayName": "Stellar Debugger", - "description": "Time-travel debugger for Stellar/Soroban smart contracts, backed by komet-node", - "version": "0.0.1", + "description": "Time-travel debugger for Stellar/Soroban smart contracts: step your Rust source forward and backward, backed by komet-node.", + "version": "0.1.0", "publisher": "runtimeverification", "license": "BSD-3-Clause", + "preview": true, + "icon": "images/icon.png", + "galleryBanner": { + "color": "#0B1B2B", + "theme": "dark" + }, + "keywords": [ + "stellar", + "soroban", + "smart contract", + "debugger", + "time travel", + "rust", + "webassembly", + "wasm", + "komet", + "blockchain" + ], "repository": { "type": "git", "url": "https://github.com/runtimeverification/stellar-debugger.git" @@ -18,7 +36,8 @@ "node": ">=22" }, "categories": [ - "Debuggers" + "Debuggers", + "Testing" ], "main": "./dist/extension.js", "bin": { @@ -26,7 +45,8 @@ "stellar-trace": "dist/trace.js" }, "activationEvents": [ - "onDebug" + "onDebugResolve:stellar", + "onCommand:stellar.debug" ], "contributes": { "configuration": { @@ -234,7 +254,7 @@ "build": "node esbuild.js", "watch": "node esbuild.js --watch", "check-types": "tsc --noEmit", - "lint": "eslint src --ext ts", + "lint": "eslint src test --ext ts", "clean": "node -e \"require('fs').rmSync('out',{recursive:true,force:true})\"", "compile-tests": "npm run clean && tsc -p tsconfig.test.json", "pretest": "npm run compile-tests", @@ -243,7 +263,10 @@ "coverage": "c8 mocha", "precoverage:ci": "npm run compile-tests", "coverage:ci": "c8 --check-coverage --lines 92 --branches 87 --functions 96 mocha", - "mutation": "stryker run" + "mutation": "stryker run", + "package": "vsce package --out stellar-debugger.vsix", + "publish:vscode": "vsce publish", + "publish:openvsx": "ovsx publish" }, "dependencies": { "@stellar/stellar-sdk": "^14.6.1", @@ -260,11 +283,13 @@ "@typescript-eslint/eslint-plugin": "^8.0.0", "@typescript-eslint/parser": "^8.0.0", "@vscode/debugadapter-testsupport": "^1.68.0", + "@vscode/vsce": "^3.6.0", "c8": "^11.0.0", "esbuild": "^0.23.0", "eslint": "^8.57.0", "fast-check": "^4.9.0", "mocha": "^10.7.0", + "ovsx": "^0.10.1", "typescript": "^5.5.0" } } From b33f99a595fc1a38b5bcbfdec92f895fd281eaca Mon Sep 17 00:00:00 2001 From: Raoul Date: Fri, 21 Aug 2026 10:20:56 +0000 Subject: [PATCH 04/13] docs: write the changelog and README for end users The changelog was written for contributors: it explained DWARF, wasm activations, `contractspecv0`, opt-level 0 and the trace's `kind` field, none of which tells a user what they can now do. It is rewritten as 498 words instead of 1150, every entry a full sentence about observable behaviour, with the mechanism left to `docs/` and CONTRIBUTING. The `[Unreleased]` section is folded into `[0.1.0]`, and the entry for the never-released 0.0.1 is gone along with its dead tag link. The README gains an Install section (it previously said "install the extension" with no link), states that komet-node must be built with komet v0.1.87 or newer, and gains a Known limitations section covering partial traces, the opt-level-0 requirement for source stepping, and one traced transaction per session. Its Roadmap no longer contradicts its Features: the Variables view ships, inline values are what is still future. `examples/` is described as a repo clone rather than as bundled, since it does not ship in the `.vsix`. CONTRIBUTING documents the release process, the allowlist `.vscodeignore` invariant, and the decision to defer the ESLint 9 migration: ESLint 8 is end-of-life but dev-only, so it never reaches the `.vsix`. SECURITY.md and CODE_OF_CONDUCT.md are the two files a public repository is measured against and were missing. SECURITY.md states scope explicitly, including that a `launch.json` naming a malicious build command is not a vulnerability in this extension. --- CHANGELOG.md | 108 ++++++++++----------------------------------- CODE_OF_CONDUCT.md | 21 +++++++++ CONTRIBUTING.md | 19 +++++++- README.md | 46 ++++++++++++------- SECURITY.md | 23 ++++++++++ 5 files changed, 114 insertions(+), 103 deletions(-) create mode 100644 CODE_OF_CONDUCT.md create mode 100644 SECURITY.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 93b3a07..7f6f424 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,93 +1,31 @@ # Changelog -All notable changes to this extension are documented in this file. The format is -based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this -project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +All notable changes to this extension are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] -### Added - -- **Multi-transaction debug configurations.** A launch config now states an - ordered `transactions` sequence of `deploy` / `invoke` steps, run against one - accumulating local ledger, with `trace` selecting which of them feeds the - session (`"last"` by default, or an index, or a step `id`). Constructors, - seeded state and multi-step flows are debuggable, not just a single bare call. - Each transaction's status is reported in the debug console, and a step that - fails or traps no longer aborts the run — its trace is still fetched and - replayed. -- **Spec-driven arguments.** An invoke's `args` is an object keyed by the - function's own parameter names, encoded against the contract's - `contractspecv0` spec, so structs, enums, tuples, vecs and maps work without - hand-written ScVal type tags. The tokens `${sourceAddress}` and - `${contract:}` expand inside string values, wiring a deployed contract's - address into a later call. -- **Just-my-code stepping** (`justMyCode`, default true): source stepping rests - only in workspace files, skipping Rust `std`/`core` and crates.io dependency - sources. `--no-just-my-code` opts out in the CLI. -- **Stellar ledger inspection.** A new **Ledger** scope shows the chain state at - every step: contract storage across all three durabilities with their TTLs, - account balances, the ledger sequence and close time, the executing contract's - wasm hash and instance TTL, the host object table, and the open contract-call - stack. Values render as Soroban types with `C…`/`G…` addresses, and composites - expand. Storage is reconstructed from the trace's own call baselines and write - events — including undoing the writes of a sub-call that trapped — so it - matches what the contract would read. -- **WebAssembly globals.** A new **Globals** scope lists the executing module's - globals by module-relative index, for traces that carry them. -- The `soroban-trace` CLI reports the same state per stop as `globals` and - `ledger`, with a `changed` flag marking the storage entries that moved since - the previous stop, and `hasGlobals`/`hasLedger` announced in `meta`. -- **A real call stack.** The Callstack view now shows every frame that led to the current line — not one frame named after a wasm instruction. Frame *structure* comes from the trace's own wasm activations, so it is right at any optimization level, and DWARF adds the Rust frames inlining erased: an optimized build still shows `add` → `invoke_raw` → the export wrapper rather than one collapsed function. Outer frames stand on the call they are suspended in, every frame is selectable and shows *its own* locals, wasm stack and Rust variables, and the Disassembly view follows the selected frame. Names come off a precision ladder — DWARF, then the demangled `name` section, then the function index, then the code offset — so a release build with no debug info still gets `control::Control::while_call+0x1a` instead of a bare address, and the trace's contract-call boundaries close the stack as labels at the bottom. Frames the user did not write (Rust `std`/`core`, dependencies) are deemphasized rather than hidden. `soroban-trace` reports the same stack per stop as `frames`. -- New contributor specs: [`docs/state-inspection.md`](docs/state-inspection.md) (rules G1–G4, L1–L15) and [`docs/callstack.md`](docs/callstack.md) (rules C1–C8), both pinned by the test suite. - -### Changed - -- The replay cursor's position in the recording moved out of the stack frame's name and into the thread's label (`soroban-vm [29/40]`): a frame name now says what the program is doing, and where the cursor sits is a property of the recorded thread. -- **The single-invoke launch config is gone.** `contract`, `function`, `args`, - `buildCommand` and `debugInfo` no longer sit at the top level: wrap them in a - `transactions` array (see [`docs/debug-config.md`](docs/debug-config.md)). A - config still using the old shape is rejected with a message pointing at the - new one, rather than silently ignored. -- **Invoke arguments are spec-driven only.** The positional - `[{ "type", "value" }]` form is removed, along with the hand-written ScVal - encoder behind it; the contract's own spec now decides how each argument - encodes. `soroban-trace --args-json` takes the same named object. -- **Requires komet v0.1.87 or newer.** That release reorganised the trace: every - record now names itself with a `kind` field, and the operands that used to ride - inside `instr` are named fields of the record. The parser reads that shape and - rejects a record without a `kind`, so a trace recorded against an older komet - no longer replays — re-record it. Failing loudly is deliberate: a trace this - parser cannot classify would otherwise open a session with every state view - mysteriously empty. -- The cross-contract gate no longer relies on komet-node tagging each trace - record with the contract executing at it. The adapter folds that out of the - `callContract`/`endWasm` boundaries the trace already carries, so nothing needs - to be sent per record for it. +## [0.1.0] — 2026-08-21 -### Fixed +This is the first public release. The extension debugs Stellar smart contracts written in Rust, in VSCode or from the command line, and it steps backward as readily as forward. -- Debug sessions start ~8 seconds faster: rendering Stellar addresses no longer - pulls `@stellar/stellar-sdk` into the debug adapter's module graph (a local - strkey encoder replaces it), which had been delaying every session past the - DAP handshake timeout. -- The invocation's return value is reported again in the debug console (and in - the CLI's `result` line), read from the trace's own call-exit record; a call - that trapped says so. -- Byte-identical transactions in one run are no longer deduplicated by - komet-node into a single execution: every envelope carries its own account - sequence, so calling the same function twice with the same arguments really - runs twice. -- DWARF type resolution no longer hangs on malformed debug info containing a - cyclic `typedef`/qualifier chain; `stripTypedefs` now terminates on cycles. - -[Unreleased]: https://github.com/runtimeverification/stellar-debugger/compare/v0.0.1...HEAD - -## [0.0.1] - -Initial release: time-travel debugging for Stellar/Soroban smart contracts, with -Rust source-level and WebAssembly stepping (forward and backward), state -inspection, a one-click build-deploy-debug pipeline, and offline replay of -recorded runs. +### Added -[0.0.1]: https://github.com/runtimeverification/stellar-debugger/releases/tag/v0.0.1 +- You can set breakpoints in your Rust source and step through it line by line, inspecting your own variables at every stop. +- You can step backward. Stepping back, stepping back out of a call, and running backward to the previous breakpoint are all as fast as going forward, so overshooting the bug costs you nothing. +- The call stack shows every function that led to the current line, including the ones the compiler inlined away. Selecting a frame shows that frame's variables and jumps to its line. +- Stepping stays in the code you wrote. The debugger steps over Rust standard-library and dependency sources rather than into them, unless you set `justMyCode` to `false`. +- A launch configuration runs an ordered sequence of deployments and calls against one fresh local network, and names the call you want to debug. You can therefore set up state — run a constructor, deploy a second contract, seed storage — before the call under test. +- Call arguments are written as JSON, keyed by the parameter names in your contract's own signature. Structs, enums, tuples, vectors and maps all work without encoding anything by hand. +- The Ledger view shows the chain as your contract sees it at the current step: contract storage with its expiry, account balances, the ledger sequence number and close time, and the contracts currently on the call stack. It travels with you as you step. +- When you need to go below your source, the debugger also shows WebAssembly locals, the operand stack, globals and linear memory, and VSCode's Disassembly View steps through the instructions themselves in either direction. +- Debugging a contract takes one keypress. The extension builds it, starts a local network, deploys it, makes the call, and opens the session. +- A recorded run can be replayed later with no network and no toolchain installed. That makes a saved recording a reproducible bug report you can hand to someone else. +- Outside the editor, `stellar-trace` prints the execution of a call as JSON lines for use in scripts and CI, and `stellar-dap` serves the debugger over TCP so that editors such as Neovim, IntelliJ and Emacs can drive it. + +### Requirements + +- Debugging a contract requires [komet-node](https://github.com/runtimeverification/komet-node), the local Stellar network that runs it. It must be built with komet v0.1.87 or newer; an older build produces recordings this version cannot open, and says so rather than opening an empty session. +- Building and deploying a contract also requires a Rust toolchain with a WebAssembly target and the Stellar CLI. Replaying a recording requires neither. + +[Unreleased]: https://github.com/runtimeverification/stellar-debugger/compare/v0.1.0...HEAD +[0.1.0]: https://github.com/runtimeverification/stellar-debugger/releases/tag/v0.1.0 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..7e39729 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,21 @@ +# Code of conduct + +## Our pledge + +We want participating in this project to be a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our standards + +Behaviour that makes this community work: showing empathy and kindness, respecting differing opinions and experiences, giving and gracefully accepting constructive feedback, taking responsibility for our mistakes, and focusing on what is best for the project as a whole. + +Behaviour that does not: sexualised language or imagery and unwelcome sexual attention, trolling, insulting or derogatory comments, personal or political attacks, public or private harassment, publishing others' private information without permission, and anything else a reasonable person would consider inappropriate in a professional setting. + +## Enforcement + +Maintainers are responsible for clarifying and enforcing these standards, and will take fair corrective action — from removing a comment to a temporary or permanent ban — in response to behaviour they judge inappropriate. They will respect the privacy and security of anyone who reports an incident. + +Report abusive, harassing, or otherwise unacceptable behaviour privately to the maintainers, through [GitHub's private reporting](https://github.com/runtimeverification/stellar-debugger/security/advisories/new) or by contacting a maintainer directly. All complaints will be reviewed and investigated promptly and fairly. + +## Attribution + +Adapted from the [Contributor Covenant](https://www.contributor-covenant.org/version/2/1/code_of_conduct.html), version 2.1. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1411ab9..14e8ad6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ > test-first convention and how to regenerate fixtures, and a tour of how the > trace-replay adapter works internally (architecture map included). -Thanks for your interest in improving the Soroban Debugger! This document covers +Thanks for your interest in improving the Stellar Debugger! This document covers how to get a development environment running and the conventions we follow. ## Development setup @@ -37,8 +37,9 @@ npm install npm run build # bundle to dist/extension.js (esbuild) npm run watch # rebuild on change npm run check-types # tsc --noEmit -npm run lint # eslint +npm run lint # eslint over src and test npm test # recompile src+test to out/, then mocha (~4 min) +npm run package # build a .vsix (vsce) — see the release section below ``` `npm test` clears `out/` before compiling: `tsc` leaves the output of a deleted @@ -50,6 +51,20 @@ extension loaded and the [`examples/`](examples/) workspace open. Pick a configuration from the Run and Debug view — the **Replay … with symbols** configs need no toolchain at all. +## Releasing + +Releases are driven by a tag, and [`.github/workflows/release.yml`](.github/workflows/release.yml) does the rest: + +1. Move the CHANGELOG's `[Unreleased]` entries under a new version heading with today's date, and update the link definitions at the bottom. +2. Bump `version` in `package.json` (the workflow refuses to publish a tag that disagrees with it). +3. Merge that, then `git tag v && git push origin v` on a commit that is already green on CI — CI, not the release workflow, is what runs the real `komet-node` end-to-end suite. + +The workflow then packages the `.vsix`, publishes it to the VS Code Marketplace and to [Open VSX](https://open-vsx.org) (which is where Cursor, Windsurf and VSCodium install from), and attaches it to a GitHub release. It needs two repository secrets, `VSCE_PAT` and `OVSX_PAT`. + +`.vscodeignore` is written as an allowlist — ignore everything, then add back `dist/`, the icon, and the four metadata files. Keep it that way: `examples/*/target` and `test/fixtures/*/target` are gitignored but still sit on disk, and `vsce` packages from the disk, so a denylist eventually ships gigabytes of Rust build output. Check with `npx vsce ls` after touching it. + +The pinned ESLint 8 is end-of-life. It is a dev-only dependency that never reaches the `.vsix`, so the migration to ESLint 9's flat config is deliberately a post-release chore rather than release-blocking work. + ## Testing conventions - **Write tests first.** New behavior should arrive with a failing test that diff --git a/README.md b/README.md index 3fb2a34..e1aa1c1 100644 --- a/README.md +++ b/README.md @@ -34,14 +34,23 @@ directions. To build, deploy, and debug a contract you'll need: -- A Rust toolchain with a wasm target (`wasm32v1-none` or - `wasm32-unknown-unknown`) +- A Rust toolchain with a wasm target (`wasm32v1-none` or `wasm32-unknown-unknown`) - The [**Stellar CLI**](https://developers.stellar.org/docs/tools/cli) -- [**komet-node**](https://github.com/runtimeverification/komet-node), the local - Stellar network the debugger runs your contract on +- [**komet-node**](https://github.com/runtimeverification/komet-node), the local Stellar network the debugger runs your contract on. It must bundle **komet v0.1.87 or newer** — that is a komet-node at or after the commit that bumped to komet v0.1.88 (`7545bd8`); `kup install komet-node` installs the newest. An older build records the previous trace shape, which this extension rejects rather than replaying: a trace it cannot classify would open a session with every state view mysteriously empty. -The extension ships with a [devcontainer](.devcontainer/Dockerfile) that has all -of this preinstalled if you'd rather not set it up by hand. +Replaying an already-recorded trace needs none of the above — no toolchain, no network, no komet-node. + +The repository ships a [devcontainer](.devcontainer/Dockerfile) with all of it preinstalled if you'd rather not set it up by hand. + +## Install + +Install **Stellar Debugger** from the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=runtimeverification.stellar-debugger), or from the command line: + +```bash +code --install-extension runtimeverification.stellar-debugger +``` + +Cursor, Windsurf and VSCodium install the same extension from [Open VSX](https://open-vsx.org/extension/runtimeverification/stellar-debugger). ## Getting started @@ -49,18 +58,15 @@ of this preinstalled if you'd rather not set it up by hand. 2. Open your Soroban contract project. 3. Add a debug configuration (below) and press **F5**. -The bundled [`examples/`](examples/) workspace has several ready-to-run -contracts and configurations — including offline replays that need no toolchain -at all — so you can see the debugger working in seconds. See -[`examples/README.md`](examples/README.md) for a tour. +To see it working before pointing it at your own code, clone this repository and open its [`examples/`](examples/) workspace: it has several ready-to-run contracts and configurations — including offline replays that need no toolchain at all. See [`examples/README.md`](examples/README.md) for a tour. ## Usage -Add a `soroban` configuration to your `.vscode/launch.json`. A configuration describes an ordered sequence of transactions run against one fresh local ledger, and names which transaction to trace and debug — the last one by default. This lets you set up whatever state the call under test depends on (deploy other contracts, run a constructor, seed storage) before the transaction you actually want to step through. +Add a `stellar` configuration to your `.vscode/launch.json`. A configuration describes an ordered sequence of transactions run against one fresh local ledger, and names which transaction to trace and debug — the last one by default. This lets you set up whatever state the call under test depends on (deploy other contracts, run a constructor, seed storage) before the transaction you actually want to step through. ```jsonc { - "type": "soroban", + "type": "stellar", "request": "launch", "name": "Debug supply", "transactions": [ @@ -118,26 +124,34 @@ An **`invoke`** step calls a function on a deployed handle: Two substitution tokens are expanded inside string `args` values: `${sourceAddress}` (the source account's address) and `${contract:}` (the deployed address behind a handle). -Two settings let you point at executables that aren't on your `PATH`: `soroban.stellar.path` and `soroban.kometNode.path`. For the full reference — multi-contract systems, every argument shape, and offline replay — see [`docs/debug-config.md`](docs/debug-config.md). +Two settings let you point at executables that aren't on your `PATH`: `stellar.cliPath` and `stellar.kometNode.path`. For the full reference — multi-contract systems, every argument shape, and offline replay — see [`docs/debug-config.md`](docs/debug-config.md). ### Beyond the editor The debugger is also available outside VS Code: -- [**`soroban-trace`**](docs/trace-cli.md) — a one-shot CLI that prints a +- [**`stellar-trace`**](docs/trace-cli.md) — a one-shot CLI that prints a Rust-level execution trace as JSONL, for scripts, CI, and AI agents. -- [**`soroban-dap`**](docs/dap-cli.md) — the debug adapter served over TCP, so other +- [**`stellar-dap`**](docs/dap-cli.md) — the debug adapter served over TCP, so other editors (nvim-dap, IntelliJ, Emacs) can drive it. +Both are built from this repository rather than installed by the extension: clone it, `npm install && npm run build`, and either run `node dist/trace.js` directly or `npm install -g .` to put `stellar-trace` and `stellar-dap` on your `PATH`. + ## Contributing Contributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md) for how to build, run, and test the extension, and for an overview of how it works internally. +## Known limitations + +- **A trace can stop short of the invocation's end.** komet-node's tracer halts at instructions it cannot decode (it reports them as `unknown`), so depending on codegen some contracts replay only partially. The session opens and steps normally; it just ends earlier than the call did. +- **Source stepping wants an unoptimized build.** The live pipeline builds with debug info at opt-level 0 for exactly this reason — at higher optimization levels a whole function can collapse onto a single line. See [`docs/stepping.md`](docs/stepping.md). +- **One transaction per session.** A launch config can run a whole sequence of transactions, but exactly one of them (`trace`) is the one you step through. + ## Roadmap -- A source-level Variables view with inline values +- Variable values shown inline in the editor, next to your code - Column-level breakpoints ## License diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..e995bb6 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,23 @@ +# Security policy + +## Supported versions + +Security fixes land on the latest released version of the extension. There are no long-term support branches. + +## Reporting a vulnerability + +Please **do not** open a public issue for a security problem. + +Report it privately through [GitHub's private vulnerability reporting](https://github.com/runtimeverification/stellar-debugger/security/advisories/new), or by email to . Include the version of the extension, the version of `komet-node`, and enough detail to reproduce — a launch configuration or a recorded trace file is ideal. + +We aim to acknowledge a report within three business days and to keep you updated as we work on a fix. We will credit you in the advisory unless you'd rather stay anonymous. + +## Scope + +This extension executes contracts on a **local** `komet-node` and shells out to the Stellar CLI to build them. Things we consider security-relevant: + +- A launch configuration, a contract, or a recorded trace file causing code execution beyond the documented build and node commands. +- The extension leaking a `sourceSecret`, or any other credential from a launch configuration, into logs, telemetry, or a network request. +- Debugging an untrusted contract or replaying an untrusted trace compromising the editor host. + +Note that a launch configuration deliberately names commands to run (`buildCommand`, `node.command`). A workspace you open is trusted to the extent VSCode's workspace trust says it is; a malicious `launch.json` naming a malicious build command is not a vulnerability in this extension. From 74147ba75bc970431f68a6061dd42d7b6768197f Mon Sep 17 00:00:00 2001 From: Raoul Date: Fri, 21 Aug 2026 10:21:04 +0000 Subject: [PATCH 05/13] chore: keep local paths and artifacts out of the repo `.gitignore` now covers `.env`, `.env.*` and `.deps/`, all of which exist untracked in a working tree, so no secret or three-repo checkout can be committed by accident. `.vscode/launch.json` carried two personal configurations pointing at `/home/node/work/...`, and `test/justMyCode.test.ts` classified paths under `/home/node/work/rs-lending-xlm/...`, naming an internal project in a repository about to go public. The test's ground-truth paths are now neutral; the classifier keys off the `.rustup`, `.cargo/registry` and `/rustc/` markers, so it treats them identically. The stray `state.kore` in the root is deleted. --- .gitignore | 4 ++++ test/justMyCode.test.ts | 8 ++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 1dbc5e3..62fb920 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,10 @@ reports/ *.vsix .DS_Store *.log +.env +.env.* +# Local checkouts of komet / komet-node / wasm-semantics for dev iteration. +.deps/ state.kore .claude/ test/fixtures/sample-contract/target/ diff --git a/test/justMyCode.test.ts b/test/justMyCode.test.ts index 5c27376..f7d726b 100644 --- a/test/justMyCode.test.ts +++ b/test/justMyCode.test.ts @@ -33,18 +33,18 @@ import { TraceRecord } from '../src/komet/trace'; // --------------------------------------------------------------------------- /** WORKSPACE — a user contract crate. */ -const WS_LIB = '/home/node/work/rs-lending-xlm/contracts/price-aggregator/src/lib.rs'; +const WS_LIB = '/home/dev/work/lending-pool/contracts/price-aggregator/src/lib.rs'; /** WORKSPACE — a shared common module in the same tree. */ -const WS_ORACLE = '/home/node/work/rs-lending-xlm/common/src/types/oracle.rs'; +const WS_ORACLE = '/home/dev/work/lending-pool/common/src/types/oracle.rs'; /** WORKSPACE — a bare relative path (no toolchain marker). */ const WS_BARE = 'src/lib.rs'; /** NON-WORKSPACE — rustup toolchain std/core source. */ const FOREIGN_RUSTUP = - '/home/node/.rustup/toolchains/1.95-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs'; + '/home/dev/.rustup/toolchains/1.95-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs'; /** NON-WORKSPACE — a crates.io dependency under the cargo registry. */ const FOREIGN_CARGO = - '/home/node/.cargo/registry/src/index.crates.io-6f17d22bba15001f/soroban-sdk-22.0.0/src/lib.rs'; + '/home/dev/.cargo/registry/src/index.crates.io-6f17d22bba15001f/soroban-sdk-22.0.0/src/lib.rs'; /** NON-WORKSPACE — a rustc-embedded std source path. */ const FOREIGN_RUSTC = '/rustc/25ef9e3d85d934b27d9dada2f9dd52b1dc63bb04/library/std/src/panic.rs'; From 5a9704c0c3ac134cea53f1462f66027fc9b5d858 Mon Sep 17 00:00:00 2001 From: Raoul Date: Fri, 21 Aug 2026 11:57:26 +0000 Subject: [PATCH 06/13] feat: say which dependency is missing and how to install it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A user without one of the external dependencies previously read a symptom rather than a cause. A missing komet-node spent sixty silent seconds polling a port nothing was listening on and then blamed the health check, though the `ENOENT` was known at second zero and logged where nobody looks. A missing Stellar CLI produced `build command exited with code 127`. A komet-node older than komet v0.1.87 built, deployed and invoked the contract before failing with `trace line 1: 'kind' must be a non-empty string`, which reads as a corrupt file rather than as a version to upgrade. `src/diagnostics/setup.ts` now owns those messages. Each names what could not be done, why, the command that installs the missing piece and the setting that points at it, and closes with a link to the README's new Troubleshooting section — appended by the `SetupError` constructor, so no caller can forget it. The module is pure and free of `vscode`, so the same wording reaches the editor modal, the debug console, `stellar-trace` and `stellar-dap`. Behaviour, not only wording, changes in three places. `KometProcess` records a failed spawn or an early exit and exposes `whenFailed()`, which `LiveBackend` races against the health check: a node that cannot start now fails the launch at once, and one that dies during boot is reported with its exit code and its own last output instead of as a timeout. `ContractBuilder` keeps a bounded tail of the build output and classifies a non-zero exit from it — a missing Stellar CLI, a missing Rust toolchain, a missing wasm target, a command that is not the Stellar CLI, or an ordinary compile failure — because an exit code cannot tell those apart. A trace record without `kind` raises `StaleTraceError`, still a `TraceParseError` so existing handlers are unaffected, naming komet v0.1.87. A missing program the output does not identify is named without a guess at which dependency it belongs to: telling someone their missing `foo` is a missing Stellar CLI would be a wrong answer stated confidently. `waitForHealthy` takes a `giveUp` predicate so the poll loop stops when the node is already known to be doomed, `node.healthTimeoutMs` makes the health deadline configurable (and the failure path testable), and both CLIs print a setup error as its message alone — a stack trace in front of an explanation only buries the fix. --- CHANGELOG.md | 15 + README.md | 29 +- docs/debug-config.md | 2 +- package.json | 5 + src/build/ContractBuilder.ts | 49 ++- src/cli/shell.ts | 9 +- src/debugAdapter/SorobanDebugSession.ts | 19 +- src/debugAdapter/backends/LiveBackend.ts | 40 +- src/debugAdapter/backends/RawTraceBackend.ts | 15 +- src/debugAdapter/types.ts | 6 + src/diagnostics/files.ts | 27 ++ src/diagnostics/setup.ts | 390 +++++++++++++++++++ src/extension.ts | 6 +- src/komet/KometClient.ts | 13 +- src/komet/KometProcess.ts | 89 ++++- src/komet/trace.ts | 24 ++ src/pipeline/SequenceRunner.ts | 25 +- test/contractBuilder.test.ts | 59 +++ test/kometClient.test.ts | 14 + test/kometProcess.test.ts | 109 ++++++ test/setupBackends.test.ts | 187 +++++++++ test/setupErrors.test.ts | 354 +++++++++++++++++ test/support/mockKometNode.ts | 15 + test/trace.test.ts | 34 ++ 24 files changed, 1502 insertions(+), 33 deletions(-) create mode 100644 src/diagnostics/files.ts create mode 100644 src/diagnostics/setup.ts create mode 100644 test/kometProcess.test.ts create mode 100644 test/setupBackends.test.ts create mode 100644 test/setupErrors.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f6f424..fb11905 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,21 @@ All notable changes to this extension are documented in this file. The format is ## [Unreleased] +### Changed + +- When a dependency is missing, the debugger now says which one, how to install it, and where to set its path, and links to the README's new Troubleshooting section. This replaces messages like `build command exited with code 127` and `trace line 1: 'kind' must be a non-empty string`, which named a symptom rather than a cause. +- A komet-node that cannot be started — not installed, or not executable — fails the launch immediately instead of after the 60-second health-check timeout. +- A komet-node that exits during startup is reported with its exit code and its own last output, rather than as a health-check timeout. +- A komet-node older than komet v0.1.87 is now diagnosed as out of date, both when it rejects the `traceTransaction` request and when it returns the pre-v0.1.87 trace shape. +- An attach-mode launch (`node.attach`) that finds nothing listening says so, instead of suggesting an install you already have. +- A failed contract build is classified from its output: a missing Stellar CLI, a missing Rust toolchain, a missing WebAssembly target, and an ordinary compile failure each get their own message and fix. +- An unreadable `rawTrace` or `wasmPath` names the attribute it came from and why the file could not be read, instead of surfacing a raw `ENOENT`. +- `stellar-trace` and `stellar-dap` print these messages on their own, without a stack trace in front of them. + +### Added + +- `node.healthTimeoutMs` sets how long to wait for komet-node to start answering requests (default 60 s). + ## [0.1.0] — 2026-08-21 This is the first public release. The extension debugs Stellar smart contracts written in Rust, in VSCode or from the command line, and it steps backward as readily as forward. diff --git a/README.md b/README.md index e1aa1c1..1f55ea8 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ To build, deploy, and debug a contract you'll need: Replaying an already-recorded trace needs none of the above — no toolchain, no network, no komet-node. -The repository ships a [devcontainer](.devcontainer/Dockerfile) with all of it preinstalled if you'd rather not set it up by hand. +The repository ships a [devcontainer](.devcontainer/Dockerfile) with all of it preinstalled if you'd rather not set it up by hand. If something is missing, the debugger says which tool it is and how to get it, and links back to [Troubleshooting](#troubleshooting) below. ## Install @@ -98,7 +98,7 @@ Top-level attributes: | `transactions` | Ordered, non-empty array of `deploy` / `invoke` steps (see below) — the live sequence to run. | | `trace` | Which transaction feeds the debug session: `"last"` (default), a 0-based index into `transactions`, or a step `id` (a deploy's `id` or an invoke's optional `id`). | | `sourceSecret` | Source account secret (`S…`) used to sign every transaction. A deterministic account is derived if omitted. Its address is available in `args` as `${sourceAddress}`. | -| `node` | Local-network connection/spawn settings: `attach`, `host`, `port`, `command`, `ioDir`. | +| `node` | Local-network connection/spawn settings: `attach`, `host`, `port`, `command`, `ioDir`, `timeoutMs`, `healthTimeoutMs`. | | `rawTrace` | Replay a previously recorded run from a file instead of building and deploying (optionally with `wasmPath` for source mapping). | A **`deploy`** step uploads a contract and registers a handle: @@ -137,6 +137,31 @@ The debugger is also available outside VS Code: Both are built from this repository rather than installed by the extension: clone it, `npm install && npm run build`, and either run `node dist/trace.js` directly or `npm install -g .` to put `stellar-trace` and `stellar-dap` on your `PATH`. +## Troubleshooting + +Every message the debugger raises about a missing dependency links here. Each row is what it says and what to do about it. + +| What you see | What it means | What to do | +|---|---|---| +| *komet-node could not be started: there is no executable named `komet-node` on your `PATH`* | The local network is not installed. | `kup install komet-node`. If it lives off your `PATH`, set the `stellar.kometNode.path` setting (or `node.command` in the launch configuration) to its full path. | +| *komet-node could not be started: … is not executable* | The file is there but has no execute bit. | `chmod +x `, or point the setting at the right file. | +| *komet-node exited … before it was ready to serve requests* | The node started and died; its own output is quoted in the message and in the Debug Console. | Most often port 8000 is already taken by an earlier run — set `node.port` to a free port, or stop the other process. | +| *komet-node did not become ready within 60s* | The node is running but never answered. | Check the Debug Console for its output. A very large contract can need longer to boot: raise `node.healthTimeoutMs`. | +| *No komet-node answered at http://… — your launch configuration sets `node.attach`* | Nothing is listening where you told the debugger to attach. | Start a node yourself (`komet-node --host --port `), or drop `node.attach` and let the debugger spawn one. | +| *This execution trace was recorded by a komet-node that is too old* | The installed node predates komet v0.1.87 and records the old trace shape. | `kup install komet-node`, then run again. Re-record any saved trace file with the upgraded node. | +| *komet-node does not support the `traceTransaction` request* | Same cause, seen one step earlier: the node cannot trace at all. | `kup install komet-node`. | +| *The contract build failed: `stellar` was not found* | No Stellar CLI. | Install the [Stellar CLI](https://developers.stellar.org/docs/tools/cli), or point `stellar.cliPath` (or a deploy step's `buildCommand`) at it. | +| *The contract build failed: `cargo` was not found* | No Rust toolchain. | Install one from [rustup.rs](https://rustup.rs). | +| *The contract build failed: the Rust WebAssembly target is missing* | The toolchain has no wasm target. | `rustup target add wasm32v1-none` (toolchains older than Rust 1.84 use `wasm32-unknown-unknown`). | +| *The contract build failed: `` exited with code …* | An ordinary build failure; the message quotes the tail and the Debug Console has the whole log. | Fix the build as you would from a terminal — the same command run by hand reproduces it. | +| *The contract build reported success but produced no WebAssembly file* | The build ran but wrote no `.wasm` where the debugger looks. | Check that the directory is a contract crate (a `Cargo.toml` with `crate-type = ["cdylib"]`) and that the build command really builds it. | +| *Cannot read the recorded trace (`rawTrace`) at …* | The replay input is missing or unreadable. | Point `rawTrace` at an existing JSONL trace, or record one with `stellar-trace --out `. | + +Two things worth knowing before you start diagnosing: + +- **Replay needs nothing.** A configuration with `rawTrace` uses no komet-node, no Stellar CLI and no Rust toolchain, so it is the quickest way to tell a broken toolchain apart from a broken configuration. +- **The Debug Console has the full log.** Every message above is also written there, along with the output of komet-node and of the build, which is usually where the specific cause is named. + ## Contributing Contributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md) for how to diff --git a/docs/debug-config.md b/docs/debug-config.md index 3c62733..64a42c3 100644 --- a/docs/debug-config.md +++ b/docs/debug-config.md @@ -144,7 +144,7 @@ work in path fields like `contract` and `wasm`. | `transactions` | The ordered live sequence (required for live mode). | | `trace` | Which transaction to debug (see [`trace`](#trace)). | | `sourceSecret` | Source account secret (`S…`) used to sign every transaction. A deterministic account is derived and self-seeded if omitted; its address is available as `${sourceAddress}`. | -| `node` | Local-network connection/spawn settings: `attach`, `host`, `port`, `command`, `ioDir`, and `timeoutMs` (per-RPC timeout, default 10 min — raise it for very large contracts that take longer to upload or execute). | +| `node` | Local-network connection/spawn settings: `attach`, `host`, `port`, `command`, `ioDir`, `timeoutMs` (per-RPC timeout, default 10 min — raise it for very large contracts that take longer to upload or execute), and `healthTimeoutMs` (how long to wait for the node to start answering, default 60 s; a node that cannot be started at all is reported at once regardless). | | `rawTrace` | Replay mode: path to a recorded JSONL trace to replay instead of running a live sequence. | | `wasmPath` | Replay mode only: a `.wasm` supplying disassembly and DWARF source mapping for the replayed trace. | diff --git a/package.json b/package.json index 0c10d64..5e322b9 100644 --- a/package.json +++ b/package.json @@ -183,6 +183,11 @@ "type": "number", "markdownDescription": "Per-RPC timeout in milliseconds before a komet-node request is aborted. Defaults to 600000 (10 minutes); raise it for very large contracts that take longer to upload or execute.", "default": 600000 + }, + "healthTimeoutMs": { + "type": "number", + "markdownDescription": "How long to wait (milliseconds) for komet-node to start answering requests before giving up. Defaults to 60000 (1 minute). A node that cannot be started at all is reported immediately, whatever this is set to.", + "default": 60000 } }, "default": {} diff --git a/src/build/ContractBuilder.ts b/src/build/ContractBuilder.ts index 0facc82..699108c 100644 --- a/src/build/ContractBuilder.ts +++ b/src/build/ContractBuilder.ts @@ -12,6 +12,7 @@ import { spawn } from 'child_process'; import { promises as fs } from 'fs'; import * as path from 'path'; import { ProgressReporter } from '../debugAdapter/types'; +import { buildFailure, buildSpawnFailure, noWasmProduced } from '../diagnostics/setup'; import { parseWasmSections } from '../wasm/sections'; const TARGET_DIRS = ['wasm32v1-none', 'wasm32-unknown-unknown']; @@ -32,13 +33,23 @@ export interface BuildOptions { debugInfo?: boolean; } +/** + * A build that could not produce a wasm. The message is written for the user by + * `diagnostics/setup` — a missing Stellar CLI, a missing Rust toolchain or wasm + * target, or the build's own output — so callers can surface it verbatim. + */ export class ContractBuildError extends Error { + readonly userFacing = true; + constructor(message: string) { super(message); this.name = 'ContractBuildError'; } } +/** How many trailing output lines are kept to explain a failed build. */ +const OUTPUT_TAIL_LINES = 40; + export class ContractBuilder { async build(opts: BuildOptions, report: ProgressReporter): Promise { const debugInfo = opts.debugInfo !== false; @@ -54,7 +65,7 @@ export class ContractBuilder { : process.env; await this.run(command, opts.contractDir, env, report); - const wasm = await this.findWasm(opts.contractDir); + const wasm = await this.findWasm(opts.contractDir, command); report(`Built wasm: ${wasm}`); if (debugInfo) { await this.warnIfMissingDebugLine(wasm, report); @@ -62,17 +73,37 @@ export class ContractBuilder { return wasm; } + /** + * Run the build command, streaming its output to the console and keeping the + * tail. A non-zero exit is classified into a user-facing diagnosis (missing + * CLI, missing toolchain, missing wasm target, or a plain compile failure) by + * `diagnostics/setup`, which is why the tail is collected at all: the exit + * code alone cannot tell those apart. + */ private run(command: string, cwd: string, env: NodeJS.ProcessEnv, report: ProgressReporter): Promise { return new Promise((resolve, reject) => { const child = spawn(command, { cwd, env, shell: true }); - child.stdout.on('data', (d) => report(d.toString().trimEnd())); - child.stderr.on('data', (d) => report(d.toString().trimEnd())); - child.on('error', (err) => reject(new ContractBuildError(`failed to run '${command}': ${err.message}`))); - child.on('close', (code) => { + const output: string[] = []; + const onOutput = (chunk: Buffer) => { + const text = chunk.toString().trimEnd(); + report(text); + output.push(text); + if (output.length > OUTPUT_TAIL_LINES) { + output.splice(0, output.length - OUTPUT_TAIL_LINES); + } + }; + child.stdout.on('data', onOutput); + child.stderr.on('data', onOutput); + child.on('error', (err) => + reject(new ContractBuildError(buildSpawnFailure({ command, error: err }).message)), + ); + child.on('close', (code, signal) => { if (code === 0) { resolve(); } else { - reject(new ContractBuildError(`build command exited with code ${code}`)); + reject( + new ContractBuildError(buildFailure({ command, cwd, code, signal, output }).message), + ); } }); }); @@ -86,7 +117,7 @@ export class ContractBuilder { * (and the name section). Fall back to `release/*.wasm` only when `deps/` * has no wasm at all. */ - private async findWasm(contractDir: string): Promise { + private async findWasm(contractDir: string, command: string): Promise { const depsCandidates: { path: string; mtimeMs: number }[] = []; const releaseCandidates: { path: string; mtimeMs: number }[] = []; for (const target of TARGET_DIRS) { @@ -96,9 +127,7 @@ export class ContractBuilder { } const candidates = depsCandidates.length > 0 ? depsCandidates : releaseCandidates; if (candidates.length === 0) { - throw new ContractBuildError( - `no wasm found under ${contractDir}/target/{${TARGET_DIRS.join(',')}}/release after build`, - ); + throw new ContractBuildError(noWasmProduced({ contractDir, command }).message); } candidates.sort((a, b) => b.mtimeMs - a.mtimeMs); return candidates[0].path; diff --git a/src/cli/shell.ts b/src/cli/shell.ts index 7dcaed7..bc9dc0f 100644 --- a/src/cli/shell.ts +++ b/src/cli/shell.ts @@ -7,10 +7,17 @@ * usage -> stderr, exit 2 * run -> the command; a thrown error goes to stderr, exit 1 * + * A setup error (a missing komet-node, an absent toolchain, an unreadable + * trace) is printed as its message alone: it is already an explanation, and a + * stack trace in front of it only buries the fix. Anything else keeps its stack, + * because anything else is a bug. + * * Coverage-excluded along with the entry points, being the same category of * process-level plumbing: the parsers it dispatches are unit-tested directly. */ +import { formatErrorDetail } from '../diagnostics/setup'; + /** A command's parse result: show help, report a usage error, or run with `R`. */ export type CliParse = | { kind: 'help'; text: string } @@ -32,7 +39,7 @@ export function runCli( return; } run(parsed).catch((err) => { - process.stderr.write(String(err instanceof Error ? (err.stack ?? err.message) : err) + '\n'); + process.stderr.write(formatErrorDetail(err) + '\n'); process.exit(1); }); } diff --git a/src/debugAdapter/SorobanDebugSession.ts b/src/debugAdapter/SorobanDebugSession.ts index 9575ae3..bd110e2 100644 --- a/src/debugAdapter/SorobanDebugSession.ts +++ b/src/debugAdapter/SorobanDebugSession.ts @@ -42,6 +42,7 @@ import { ledgerNodes, ledgerSnapshot } from './ledgerView'; import { globalNodes, localNodes, stackNodes } from './wasmView'; import { makeRuntimeState } from './runtimeState'; import { DecodedValue, ChildVar } from '../dwarf/ValueDecoder'; +import { formatErrorDetail, isUserFacing } from '../diagnostics/setup'; const THREAD_ID = 1; @@ -210,13 +211,19 @@ export class SorobanDebugSession extends DebugSession { this.cursor.toEntry(); this.reportStop('entry'); } catch (e) { - // sendErrorResponse surfaces only a one-line, non-copyable modal. Mirror - // the full error (with stack) into the debug console first, so the details - // land in the same copyable log as the rest of the launch output. + // sendErrorResponse surfaces only a modal. Mirror the error into the debug + // console first, so the details land in the same copyable log as the rest + // of the launch output. + // + // A setup error (missing komet-node, absent toolchain, unreadable trace) + // is already written for the user and says how to fix itself, so it is + // surfaced verbatim, with no stack and no "Failed to start" preamble in + // front of the explanation. Anything else is a bug: it keeps the preamble + // and, in the console, its stack. + const setup = isUserFacing(e); const message = e instanceof Error ? e.message : String(e); - const detail = e instanceof Error ? (e.stack ?? e.message) : String(e); - this.log(`Failed to start debug session: ${detail}`); - this.sendErrorResponse(response, 2000, `Failed to start debug session: ${message}`); + this.log(setup ? message : `Failed to start debug session: ${formatErrorDetail(e)}`); + this.sendErrorResponse(response, 2000, setup ? message : `Failed to start debug session: ${message}`); this.sendEvent(new TerminatedEvent()); } } diff --git a/src/debugAdapter/backends/LiveBackend.ts b/src/debugAdapter/backends/LiveBackend.ts index 5aef8be..310e9b2 100644 --- a/src/debugAdapter/backends/LiveBackend.ts +++ b/src/debugAdapter/backends/LiveBackend.ts @@ -20,7 +20,9 @@ import { KometProcess } from '../../komet/KometProcess'; import { normalizeConfig } from '../../pipeline/config'; import { SequenceRunner } from '../../pipeline/SequenceRunner'; import { ProgressReporter, ResolvedTrace, SessionBackend, SorobanLaunchArgs } from '../types'; +import { kometUnreachable } from '../../diagnostics/setup'; +/** Default deadline for the node to answer `getHealth`; `node.healthTimeoutMs` overrides. */ const HEALTH_TIMEOUT_MS = 60_000; // Generous per-RPC default: large contracts can take minutes for komet-node to @@ -50,13 +52,49 @@ export class LiveBackend implements SessionBackend { timeoutMs: node.timeoutMs ?? DEFAULT_RPC_TIMEOUT_MS, }); report(`Waiting for komet-node at ${client.url} ...`); - await client.waitForHealthy(HEALTH_TIMEOUT_MS); + await this.waitUntilServing(client, { + attach: node.attach ?? false, + timeoutMs: node.healthTimeoutMs ?? HEALTH_TIMEOUT_MS, + port, + }); // Execute the whole sequence: seed the source account, deploy, invoke, and // resolve the traced tx into a replayable trace regardless of its status. return new SequenceRunner(client).run(normalized, { sourceSecret: args.sourceSecret }, report); } + /** + * Wait for the node to answer `getHealth`, and explain it when it never does. + * + * A node we spawned can fail in a way we learn about immediately — no such + * binary, or an exit during boot — so the health wait races + * `KometProcess.whenFailed()`: that turns a 60-second timeout into an instant, + * accurate message. When the node does come up, the failure promise is simply + * abandoned (it resolves rather than rejects, so nothing goes unhandled). + */ + private async waitUntilServing( + client: KometClient, + opts: { attach: boolean; timeoutMs: number; port: number }, + ): Promise { + // `giveUp` ends the poll loop as soon as the node is known to be doomed, so + // no request keeps hitting a dead port after this method has thrown. + const healthy = client + .waitForHealthy(opts.timeoutMs, undefined, () => this.process?.currentFailure() !== undefined) + .then(() => 'healthy' as const); + const failure = this.process?.whenFailed(); + const outcome = await Promise.race(failure ? [healthy, failure] : [healthy]).catch(() => { + // The deadline passed. If the process died meanwhile, its own reason is + // the better one; otherwise the node is up but mute. + throw ( + this.process?.currentFailure() ?? + kometUnreachable({ url: client.url, ...opts }) + ); + }); + if (outcome !== 'healthy') { + throw outcome; + } + } + async dispose(): Promise { if (this.process) { await this.process.stop(); diff --git a/src/debugAdapter/backends/RawTraceBackend.ts b/src/debugAdapter/backends/RawTraceBackend.ts index e8f1f77..5126f2c 100644 --- a/src/debugAdapter/backends/RawTraceBackend.ts +++ b/src/debugAdapter/backends/RawTraceBackend.ts @@ -9,7 +9,7 @@ * Pure module (uses fs, no `vscode` imports). */ -import { promises as fs } from 'fs'; +import { readFileOrExplain, readTextOrExplain } from '../../diagnostics/files'; import { parseTraceJsonl } from '../../komet/trace'; import { TraceModel } from '../TraceModel'; import { buildDebugArtifacts, traceDerivedArtifacts } from '../artifacts'; @@ -21,12 +21,21 @@ export class RawTraceBackend implements SessionBackend { throw new Error('RawTraceBackend requires the `rawTrace` launch attribute (path to a JSONL trace).'); } report(`Reading trace from ${args.rawTrace}`); - const jsonl = await fs.readFile(args.rawTrace, 'utf8'); + const jsonl = await readTextOrExplain( + args.rawTrace, + 'the recorded trace (`rawTrace`)', + 'Record one with `stellar-trace --out `, or point `rawTrace` at an existing JSONL trace.', + ); const model = new TraceModel(parseTraceJsonl(jsonl)); if (args.wasmPath) { report(`Reading contract wasm from ${args.wasmPath}`); - const wasm = await fs.readFile(args.wasmPath); + const wasm = await readFileOrExplain( + args.wasmPath, + 'the contract wasm (`wasmPath`)', + 'It should be the same `.wasm` the trace was recorded from. Drop `wasmPath` to replay ' + + 'without source mapping.', + ); return { model, ...buildDebugArtifacts(wasm, model, report) }; } // Without wasm there is nothing to validate positions against, and nothing diff --git a/src/debugAdapter/types.ts b/src/debugAdapter/types.ts index 28cd488..7f740d7 100644 --- a/src/debugAdapter/types.ts +++ b/src/debugAdapter/types.ts @@ -40,6 +40,12 @@ export interface SorobanLaunchArgs extends DebugProtocol.LaunchRequestArguments * longer to upload/execute. */ timeoutMs?: number; + /** + * How long (ms) to wait for the node to answer `getHealth` before giving up + * with a diagnosis. Defaults to 60s. A node that fails to spawn or exits + * during boot is reported at once regardless of this deadline. + */ + healthTimeoutMs?: number; }; /** Optional source account secret; a fresh account is seeded if omitted. */ sourceSecret?: string; diff --git a/src/diagnostics/files.ts b/src/diagnostics/files.ts new file mode 100644 index 0000000..1d5f506 --- /dev/null +++ b/src/diagnostics/files.ts @@ -0,0 +1,27 @@ +/** + * Reading the files a launch configuration points at, with a user-facing + * explanation when one is not readable. + * + * A raw `ENOENT: no such file or directory, open '…'` tells the user what the + * runtime saw, not what they got wrong; these wrappers say which configuration + * attribute the path came from and, where there is one, how to produce the file. + * + * Pure module apart from the read itself (no `vscode` imports). + */ + +import { promises as fs } from 'fs'; +import { unreadableFile } from './setup'; + +/** Read a file as bytes, explaining a failure in terms of the config. */ +export async function readFileOrExplain(path: string, what: string, hint?: string): Promise { + try { + return await fs.readFile(path); + } catch (e) { + throw unreadableFile({ what, path, error: e as NodeJS.ErrnoException, hint }); + } +} + +/** Read a file as UTF-8 text, explaining a failure in terms of the config. */ +export async function readTextOrExplain(path: string, what: string, hint?: string): Promise { + return (await readFileOrExplain(path, what, hint)).toString('utf8'); +} diff --git a/src/diagnostics/setup.ts b/src/diagnostics/setup.ts new file mode 100644 index 0000000..353641f --- /dev/null +++ b/src/diagnostics/setup.ts @@ -0,0 +1,390 @@ +/** + * The messages a user reads when one of the debugger's external dependencies is + * missing, unusable, or too old. + * + * Every failure of that kind is expressible as a `SetupError`, whose message is + * written for a person: it says what could not be done, why, what to run or set + * to fix it, and — always as the last line — where to read more. Nothing here + * knows about VSCode or DAP, so the same wording reaches the editor modal, the + * debug console, `stellar-trace` and `stellar-dap`. + * + * The four situations these cover, and where each is raised: + * - komet-node cannot be spawned, or dies before serving (komet/KometProcess) + * - komet-node never answers, or answers too old (backends/LiveBackend, + * pipeline/SequenceRunner, + * komet/trace) + * - the contract build fails for want of a toolchain (build/ContractBuilder) + * - an input file (trace, wasm) cannot be read (both backends) + * + * Pure module (no `vscode`, no I/O): the factories are string builders, unit + * tested directly in test/setupErrors.test.ts. + */ + +/** The README, which carries the requirements and the troubleshooting table. */ +export const README_URL = 'https://github.com/runtimeverification/stellar-debugger/blob/main/README.md'; + +/** Where every setup error sends the reader for the longer version. */ +export const TROUBLESHOOTING_URL = `${README_URL}#troubleshooting`; + +/** Where the Stellar CLI itself is documented. */ +const STELLAR_CLI_URL = 'https://developers.stellar.org/docs/tools/cli'; + +/** Where a Rust toolchain comes from. */ +const RUSTUP_URL = 'https://rustup.rs'; + +/** The wasm targets a Soroban contract builds to, newest first. */ +const WASM_TARGETS = ['wasm32v1-none', 'wasm32-unknown-unknown']; + +/** + * A dependency problem, phrased for the person who has to fix it. The message + * is assembled from paragraphs and always closes with the README link, so no + * caller can forget it. + */ +export class SetupError extends Error { + /** Marks a message meant for a user: printed as prose, without a stack. */ + readonly userFacing = true; + + constructor(...paragraphs: string[]) { + super(setupMessage(...paragraphs)); + this.name = 'SetupError'; + } +} + +/** Join paragraphs into a user-facing message and append the README link. */ +export function setupMessage(...paragraphs: string[]): string { + const body = paragraphs.filter((p) => p.length > 0); + return [...body, `See ${TROUBLESHOOTING_URL}.`].join('\n'); +} + +/** + * Whether an error carries a message written for the user. Checked by the flag + * rather than by class so that `StaleTraceError` — which must stay a + * `TraceParseError` for existing handlers — can opt in too. + */ +export function isUserFacing(e: unknown): boolean { + return typeof e === 'object' && e !== null && (e as { userFacing?: unknown }).userFacing === true; +} + +/** + * How an error should be logged. A setup error is already the explanation, so + * its stack is noise; anything else is a bug, whose stack is the whole point. + */ +export function formatErrorDetail(e: unknown): string { + if (isUserFacing(e)) { + return (e as Error).message; + } + if (e instanceof Error) { + return e.stack ?? e.message; + } + return String(e); +} + +// --- komet-node: cannot be started --------------------------------------- + +/** Where to say a komet-node path can be corrected. */ +const KOMET_PATH_HINT = + 'Set the `stellar.kometNode.path` setting (or `node.command` in your launch configuration) ' + + 'to its full path if it lives somewhere off your `PATH`.'; + +const KOMET_WHAT = + 'komet-node is the local Stellar network the debugger runs your contract on; ' + + 'it must bundle komet v0.1.87 or newer.'; + +const REPLAY_NEEDS_NOTHING = + 'Replaying an already-recorded trace (the `rawTrace` launch attribute) needs no komet-node at all.'; + +/** komet-node could not be spawned: not installed, not executable, or worse. */ +export function kometSpawnFailure(opts: { + command: string; + error: NodeJS.ErrnoException; +}): SetupError { + const { command, error } = opts; + const where = command.includes('/') ? `at \`${command}\`` : `named \`${command}\` on your \`PATH\``; + + if (error.code === 'ENOENT') { + return new SetupError( + `komet-node could not be started: there is no executable ${where}.`, + `${KOMET_WHAT} Install it with \`kup install komet-node\`. ${KOMET_PATH_HINT}`, + REPLAY_NEEDS_NOTHING, + ); + } + if (error.code === 'EACCES' || error.code === 'EPERM') { + return new SetupError( + `komet-node could not be started: \`${command}\` is not executable (permission denied).`, + `Make it executable with \`chmod +x ${command}\`, or point \`stellar.kometNode.path\` at the right file.`, + ); + } + return new SetupError( + `komet-node could not be started: ${error.message}`, + `The command was \`${command}\`. ${KOMET_PATH_HINT}`, + ); +} + +/** komet-node started and then exited before it was ready to serve. */ +export function kometExitedEarly(opts: { + command: string; + code: number | null; + signal: NodeJS.Signals | null; + output: readonly string[]; + port: number; +}): SetupError { + const { command, code, signal, output, port } = opts; + const how = signal ? `was killed by ${signal}` : `exited with code ${code ?? 'unknown'}`; + return new SetupError( + `komet-node ${how} before it was ready to serve requests.`, + outputParagraph('Its last output was', output), + `A common cause is port ${port} already being in use — another komet-node may still be running. ` + + 'Set `node.port` in your launch configuration to a free port, or stop the other process. ' + + `The command was \`${command}\`.`, + ); +} + +/** Nothing answered the health check within the deadline. */ +export function kometUnreachable(opts: { + url: string; + attach: boolean; + timeoutMs: number; + port: number; +}): SetupError { + const { url, attach, timeoutMs, port } = opts; + const waited = timeoutMs >= 1000 ? `${Math.round(timeoutMs / 1000)}s` : `${timeoutMs}ms`; + const host = hostOf(url); + + if (attach) { + return new SetupError( + `No komet-node answered at ${url} within ${waited}.`, + 'Your launch configuration sets `node.attach`, so the debugger did not start a node itself. ' + + `Start one with \`komet-node --host ${host} --port ${port}\` and launch again, ` + + 'or drop `node.attach` and let the debugger spawn it for you.', + ); + } + return new SetupError( + `komet-node did not become ready within ${waited}: it is running, but it never answered ` + + `the health check at ${url}.`, + 'Its own output is in the log above (the Debug Console, in the editor) and usually says why. ' + + 'A very large contract can simply need longer to boot — raise `node.healthTimeoutMs` in your ' + + `launch configuration. If something else is holding port ${port}, set \`node.port\` to a free one.`, + ); +} + +// --- komet-node: too old -------------------------------------------------- + +const KOMET_UPGRADE = 'Upgrade it with `kup install komet-node`, then run again.'; + +/** + * The message for a trace whose records predate komet v0.1.87. Exposed as a + * string (not an error) because `komet/trace.ts` must raise it as a + * `TraceParseError` subclass to stay compatible with existing handlers. + */ +export function staleKometTraceMessage(detail: string): string { + return setupMessage( + 'This execution trace was recorded by a komet-node that is too old for this version of the ' + + `debugger (${detail}; that field arrived in komet v0.1.87).`, + `${KOMET_UPGRADE} If you are replaying a saved trace file, re-record it with the upgraded node — ` + + 'the debugger refuses to replay the old shape rather than show you a session with every state ' + + 'view mysteriously empty.', + ); +} + +/** komet-node does not implement an RPC method the debugger needs. */ +export function staleKometRpc(method: string): SetupError { + return new SetupError( + `komet-node does not support the \`${method}\` request, which the debugger needs to record an ` + + 'execution.', + `The installed node is older than komet v0.1.87 (or is not komet-node at all). ${KOMET_UPGRADE}`, + ); +} + +// --- the contract build -------------------------------------------------- + +const BUILD_NEEDS = + 'Building a contract needs a Rust toolchain with a WebAssembly target ' + + `(\`${WASM_TARGETS[0]}\`) and the Stellar CLI.`; + +/** The build command could not be launched at all (no shell, and the like). */ +export function buildSpawnFailure(opts: { command: string; error: NodeJS.ErrnoException }): SetupError { + return new SetupError( + `The contract build could not be started: ${opts.error.message}`, + `The build command was \`${opts.command}\`. ${BUILD_NEEDS}`, + ); +} + +/** + * The build ran and failed. The output is classified — a missing program, a + * missing wasm target, a command that is not the Stellar CLI — so the message + * names the fix instead of only the exit code. + */ +export function buildFailure(opts: { + command: string; + cwd: string; + code: number | null; + signal?: NodeJS.Signals | null; + output: readonly string[]; +}): SetupError { + const { command, cwd, code, signal, output } = opts; + const text = output.join('\n'); + + // 1. A program the build wanted is not installed. The shell says so on + // stderr; exit 127 says so on its own when the output was swallowed. + const missing = missingProgram(text) ?? (code === 127 ? firstWord(command) : undefined); + if (missing !== undefined) { + return missingProgramError(missing, command); + } + + // 2. The toolchain is there, but not the target the contract compiles to. + if (/target may not be installed|can't find crate for `core`|no such target/i.test(text)) { + return new SetupError( + 'The contract build failed: the Rust WebAssembly target is missing.', + `Install it with \`rustup target add ${WASM_TARGETS[0]}\` ` + + `(toolchains older than Rust 1.84 use \`${WASM_TARGETS[1]}\` instead), then build again.`, + outputParagraph('The build said', output), + ); + } + + // 3. Something answered, but it is not the Stellar CLI. + if (/unrecognized subcommand|no such subcommand|no such command|unknown command/i.test(text)) { + return new SetupError( + `The contract build failed: \`${firstWord(command)}\` does not understand \`contract build\`, ` + + 'so it does not appear to be the Stellar CLI.', + `Install the Stellar CLI (${STELLAR_CLI_URL}) and point the \`stellar.cliPath\` setting — or a ` + + "deploy step's `buildCommand` — at it.", + outputParagraph('The command said', output), + ); + } + + // 4. An ordinary build failure. The output is the answer; we add what the + // build needs, because a toolchain problem often surfaces this way. + const how = signal ? `was killed by ${signal}` : `exited with code ${code ?? 'unknown'}`; + return new SetupError( + `The contract build failed: \`${command}\` ${how} in ${cwd}.`, + outputParagraph('Its last output was', output), + `The full build log is above. ${BUILD_NEEDS}`, + ); +} + +/** The build produced no wasm, so there is nothing to deploy. */ +export function noWasmProduced(opts: { contractDir: string; command: string }): SetupError { + return new SetupError( + 'The contract build reported success but produced no WebAssembly file.', + `Nothing was found under \`${opts.contractDir}/target/{${WASM_TARGETS.join(',')}}/release\`. ` + + `Check that this directory is a Soroban contract crate (a \`Cargo.toml\` with ` + + `\`crate-type = ["cdylib"]\`) and that \`${opts.command}\` really builds it.`, + ); +} + +/** Phrase a missing program as the dependency it belongs to. */ +function missingProgramError(program: string, command: string): SetupError { + const base = program.split('/').pop() ?? program; + + if (/^(cargo|rustc|rustup)(\.exe)?$/i.test(base)) { + return new SetupError( + `The contract build failed: \`${base}\` was not found, so there is no Rust toolchain to build with.`, + `Install one from ${RUSTUP_URL}, then add the WebAssembly target with ` + + `\`rustup target add ${WASM_TARGETS[0]}\`.`, + ); + } + // Only a name that reads as the Stellar CLI is diagnosed as one: telling + // someone their missing `foo` is a missing Stellar CLI would be a wrong + // answer stated confidently. + const isStellarCli = /^stellar(\b|[-_.])/i.test(base); + return new SetupError( + `The contract build failed: \`${program}\` was not found (the build command was \`${command}\`).`, + isStellarCli + ? `Install the Stellar CLI (${STELLAR_CLI_URL}), or point the \`stellar.cliPath\` setting — or a ` + + "deploy step's `buildCommand` — at the executable you want to build with." + : `Install it, or change the \`buildCommand\` of that deploy step. ${BUILD_NEEDS}`, + ); +} + +/** Shells name themselves when they report a missing program; skip those. */ +const SHELL_NAMES = /^(sh|bash|zsh|dash|ksh|fish|cmd|powershell)$/i; + +/** + * The program name a shell reports as missing. Covers the three phrasings in + * the wild: `sh: 1: foo: not found`, `bash: foo: command not found`, and + * `zsh: command not found: foo`. The trailing-name form is tried first, since + * its prefix also matches the leading-name form (with the shell as the name). + */ +function missingProgram(output: string): string | undefined { + const name = + /command not found: ([^\s:]+)/m.exec(output)?.[1] ?? + /(?:^|[\s:])([^\s:]+): (?:command )?not found/m.exec(output)?.[1]; + return name !== undefined && SHELL_NAMES.test(name) ? undefined : name; +} + +// --- unreadable inputs --------------------------------------------------- + +/** A file the launch configuration points at cannot be read. */ +export function unreadableFile(opts: { + what: string; + path: string; + error: NodeJS.ErrnoException; + hint?: string; +}): SetupError { + return new SetupError( + `Cannot read ${opts.what} at \`${opts.path}\`: ${fsReason(opts.error)}.`, + opts.hint ?? '', + ); +} + +/** A filesystem error code as a phrase, falling back to the raw message. */ +function fsReason(error: NodeJS.ErrnoException): string { + switch (error.code) { + case 'ENOENT': + return 'no such file or directory'; + case 'EACCES': + case 'EPERM': + return 'permission denied'; + case 'EISDIR': + return 'that path is a directory, not a file'; + case 'ENOTDIR': + return 'a component of that path is not a directory'; + default: + return error.message; + } +} + +// --- shared helpers ------------------------------------------------------ + +/** How many trailing output lines a message quotes. */ +const TAIL_LINES = 8; +/** How much of one quoted line survives. */ +const TAIL_LINE_CHARS = 160; +/** How much quoted output a message carries in total. */ +const TAIL_CHARS = 700; + +/** + * The tail of a process's output, indented under a lead-in. Bounded on both + * axes: a message has to stay readable in a modal dialog, and the full log is + * in the debug console (or on stderr) anyway. + */ +function outputParagraph(lead: string, output: readonly string[]): string { + const lines = output + .flatMap((chunk) => chunk.split('\n')) + .map((line) => line.trimEnd()) + .filter((line) => line.length > 0) + .slice(-TAIL_LINES) + .map((line) => (line.length > TAIL_LINE_CHARS ? `${line.slice(0, TAIL_LINE_CHARS)}…` : line)); + + while (lines.length > 1 && lines.join('\n').length > TAIL_CHARS) { + lines.shift(); + } + if (lines.length === 0) { + return ''; + } + return [`${lead}:`, ...lines.map((line) => ` ${line}`)].join('\n'); +} + +/** The program a shell command runs, for naming it in a message. */ +function firstWord(command: string): string { + return command.trim().split(/\s+/)[0].replace(/^["']|["']$/g, ''); +} + +/** The host part of a `http://host:port` URL. */ +function hostOf(url: string): string { + try { + return new URL(url).hostname; + } catch { + return 'localhost'; + } +} diff --git a/src/extension.ts b/src/extension.ts index 74c5f34..6b9c14b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -13,6 +13,7 @@ import * as vscode from 'vscode'; import { SorobanDebugSession } from './debugAdapter/SorobanDebugSession'; import { backendFor } from './debugAdapter/backendFor'; import { SorobanLaunchArgs } from './debugAdapter/types'; +import { TROUBLESHOOTING_URL } from './diagnostics/setup'; export function activate(context: vscode.ExtensionContext): void { const provider = new SorobanConfigurationProvider(); @@ -55,7 +56,10 @@ class SorobanConfigurationProvider implements vscode.DebugConfigurationProvider applyBinaryPaths(config, folder); if (!config.rawTrace && !Array.isArray(config.transactions)) { return vscode.window - .showErrorMessage('Stellar debug: a `transactions` array (or a `rawTrace` file) is required in the launch configuration.') + .showErrorMessage( + 'Stellar debug: a `transactions` array (or a `rawTrace` file) is required in the launch ' + + `configuration. See ${TROUBLESHOOTING_URL}.`, + ) .then(() => undefined); } return config; diff --git a/src/komet/KometClient.ts b/src/komet/KometClient.ts index 45432c9..03f52f8 100644 --- a/src/komet/KometClient.ts +++ b/src/komet/KometClient.ts @@ -146,11 +146,20 @@ export class KometClient { return records; } - /** Poll getHealth until healthy or the deadline passes. */ - async waitForHealthy(deadlineMs: number, intervalMs = 500): Promise { + /** + * Poll getHealth until healthy or the deadline passes. + * + * `giveUp` lets a caller that has already learned the node is doomed (see + * `KometProcess.whenFailed`) end the wait at once, instead of leaving a poll + * loop hammering a dead port for the rest of the deadline. + */ + async waitForHealthy(deadlineMs: number, intervalMs = 500, giveUp?: () => boolean): Promise { const start = Date.now(); let lastErr: unknown; while (Date.now() - start < deadlineMs) { + if (giveUp?.()) { + throw new KometRpcError(`gave up waiting for komet-node at ${this.url}`); + } try { const h = await this.getHealth(); if (h.status === 'healthy') { diff --git a/src/komet/KometProcess.ts b/src/komet/KometProcess.ts index da3fd3d..c36b853 100644 --- a/src/komet/KometProcess.ts +++ b/src/komet/KometProcess.ts @@ -7,11 +7,18 @@ * `getHealth` method (see KometClient.waitForHealthy) before the pipeline * proceeds. * + * Failures are surfaced through `whenFailed()`, which LiveBackend races the + * health check against: a node that cannot be spawned (not installed, not + * executable) or that dies during boot is known to be a lost cause the moment it + * happens, and waiting out the health-check deadline would only replace a + * precise diagnosis with a timeout. + * * Pure module (uses child_process, no `vscode` imports). */ import { ChildProcess, spawn } from 'child_process'; import { ProgressReporter } from '../debugAdapter/types'; +import { SetupError, kometExitedEarly, kometSpawnFailure } from '../diagnostics/setup'; export interface KometProcessOptions { /** Base command, e.g. "komet-node". */ @@ -24,11 +31,22 @@ export interface KometProcessOptions { cwd?: string; } +/** How many trailing output lines are kept to explain an early exit. */ +const OUTPUT_TAIL_LINES = 20; + export class KometProcess { private child?: ChildProcess; readonly host: string; readonly port: number; + /** The failure, once one is known; `whenFailed()` settles with it. */ + private failure?: SetupError; + private readonly failureWaiters: ((failure: SetupError) => void)[] = []; + /** Set by `stop()`, so a shutdown we asked for is not reported as a failure. */ + private stopping = false; + /** Ring buffer of the node's most recent output, for the failure message. */ + private readonly outputTail: string[] = []; + constructor(private readonly opts: KometProcessOptions) { this.host = opts.host ?? 'localhost'; this.port = opts.port ?? 8000; @@ -53,12 +71,56 @@ export class KometProcess { // the same reason — a shell wrapper is a separate process that swallows the // signal and orphans the real node. this.child = spawn(base, args, { cwd: this.opts.cwd, detached: true }); - this.child.stdout?.on('data', (d) => report(`[komet-node] ${d.toString().trimEnd()}`)); - this.child.stderr?.on('data', (d) => report(`[komet-node] ${d.toString().trimEnd()}`)); - this.child.on('error', (err) => report(`[komet-node] failed to spawn: ${err.message}`)); + this.child.stdout?.on('data', (d) => this.onOutput(d, report)); + this.child.stderr?.on('data', (d) => this.onOutput(d, report)); + this.child.on('error', (err) => { + const failure = kometSpawnFailure({ command: base, error: err }); + // Only the headline goes to the log: the full message — install hint, + // README link and all — is the thrown error, and printing both would + // duplicate the whole thing on a CLI, where both land on stderr. + report(`[komet-node] ${failure.message.split('\n')[0]}`); + this.fail(failure); + }); + // An exit before the health check passes is fatal — the pipeline has nothing + // to talk to — and the node's own output usually says why (a bound port, a + // missing K distribution). A deliberate stop() sets `stopping` first. + this.child.on('exit', (code, signal) => { + // A process that never spawned reports itself through 'error' above, with + // a far better message than "exited with code unknown". + if (this.child?.pid === undefined) { + return; + } + this.fail( + kometExitedEarly({ + command: base, + code, + signal, + output: this.outputTail, + port: this.port, + }), + ); + }); + } + + /** + * Settles with the reason the node will never serve. Stays pending while the + * node is alive and after a deliberate `stop()`, so it is safe to race against + * the health check and simply abandon when the node comes up. + */ + whenFailed(): Promise { + if (this.failure) { + return Promise.resolve(this.failure); + } + return new Promise((resolve) => this.failureWaiters.push(resolve)); + } + + /** The failure so far, if any: what a health-check timeout should defer to. */ + currentFailure(): SetupError | undefined { + return this.failure; } async stop(): Promise { + this.stopping = true; const child = this.child; this.child = undefined; if (!child || child.exitCode !== null || child.pid === undefined) { @@ -91,4 +153,25 @@ export class KometProcess { killGroup('SIGTERM'); }); } + + /** Mirror node output to the console, keeping the tail for diagnostics. */ + private onOutput(chunk: unknown, report: ProgressReporter): void { + const text = String(chunk).trimEnd(); + report(`[komet-node] ${text}`); + this.outputTail.push(text); + if (this.outputTail.length > OUTPUT_TAIL_LINES) { + this.outputTail.splice(0, this.outputTail.length - OUTPUT_TAIL_LINES); + } + } + + /** Record the first failure and release anyone waiting on it. */ + private fail(failure: SetupError): void { + if (this.stopping || this.failure) { + return; + } + this.failure = failure; + for (const resolve of this.failureWaiters.splice(0)) { + resolve(failure); + } + } } diff --git a/src/komet/trace.ts b/src/komet/trace.ts index 6083510..ca58eea 100644 --- a/src/komet/trace.ts +++ b/src/komet/trace.ts @@ -57,9 +57,27 @@ */ import { TraceParseError } from './traceError'; +import { staleKometTraceMessage } from '../diagnostics/setup'; import { isEvenLengthHex, parseTraceEvent, TraceEvent } from './traceEvents'; export { TraceParseError } from './traceError'; + +/** + * A trace recorded before komet v0.1.87, whose records carry no `kind`. It is a + * `TraceParseError` (existing handlers keep working) with a user-facing message + * (the cause is a stale komet-node, not a corrupt file), which is exactly the + * combination that stops this failure from reading as "the repo is broken" — + * a diagnosis that has cost real debugging time before. + */ +export class StaleTraceError extends TraceParseError { + readonly userFacing = true; + + constructor(detail: string) { + super(staleKometTraceMessage(detail)); + this.name = 'StaleTraceError'; + } +} + export type { TraceEvent, TraceAddress, @@ -148,6 +166,12 @@ export function toTraceRecord(value: unknown, lineNo: number): TraceRecord { const kind = obj.kind; if (typeof kind !== 'string' || kind === '') { + // A record that otherwise looks like a trace record, but has no `kind`, is + // the pre-v0.1.87 shape rather than a malformed line: say so, because the + // fix is `kup install komet-node`, not a bug report. + if ('instr' in obj || 'pos' in obj) { + throw new StaleTraceError(`record ${lineNo} has no \`kind\` field`); + } reject("'kind' must be a non-empty string"); } const isInstruction = kind === 'instr'; diff --git a/src/pipeline/SequenceRunner.ts b/src/pipeline/SequenceRunner.ts index aae9cf9..d4182cc 100644 --- a/src/pipeline/SequenceRunner.ts +++ b/src/pipeline/SequenceRunner.ts @@ -29,7 +29,7 @@ import { createHash } from 'crypto'; import { promises as fs } from 'fs'; import { Keypair } from '@stellar/stellar-sdk'; -import { KometClient } from '../komet/KometClient'; +import { KometClient, KometRpcError } from '../komet/KometClient'; import { ContractBuilder } from '../build/ContractBuilder'; import { SorobanTxBuilder } from '../soroban/SorobanTxBuilder'; import { stripDebugSections } from '../wasm/sections'; @@ -38,6 +38,8 @@ import { TraceModel } from '../debugAdapter/TraceModel'; import { buildDebugArtifacts } from '../debugAdapter/artifacts'; import { ProgressReporter, ResolvedTrace } from '../debugAdapter/types'; import { encodeInvokeArgs, substitute } from '../soroban/specEncode'; +import { staleKometRpc } from '../diagnostics/setup'; +import { readFileOrExplain } from '../diagnostics/files'; import { DeployStep, InvokeStep, NormalizedConfig } from './config'; /** Options controlling how the sequence is run. */ @@ -139,12 +141,28 @@ export class SequenceRunner { // reverting tx stays debuggable). const traced = submitted[config.trace]; report(`Fetching trace for transaction ${traced.hash} ...`); - const trace = await this.client.traceTransaction(traced.hash); + const trace = await this.fetchTrace(traced.hash); const model = new TraceModel(toTraceRecords(trace)); return { model, ...buildDebugArtifacts(traced.wasm, model, report) }; } + /** + * Fetch the traced transaction's records. A node that does not know the + * method is not a protocol error to relay verbatim — it is a komet-node too + * old to trace at all, which is worth saying in those words. + */ + private async fetchTrace(hash: string): Promise { + try { + return await this.client.traceTransaction(hash); + } catch (e) { + if (e instanceof KometRpcError && (e.code === -32601 || /method not found/i.test(e.message))) { + throw staleKometRpc('traceTransaction'); + } + throw e; + } + } + /** Upload + create a contract, registering its handle. */ private async deploy(step: DeployStep, ctx: RunContext): Promise { const { txBuilder, source, submit, report } = ctx; @@ -191,7 +209,7 @@ export class SequenceRunner { /** Load a deploy's wasm: a prebuilt `wasm` path, or build a `contract` dir. */ private async loadWasm(step: DeployStep, report: ProgressReporter): Promise { if (step.wasm) { - return fs.readFile(step.wasm); + return readFileOrExplain(step.wasm, `the prebuilt wasm for deploy step "${step.id}" (\`wasm\`)`); } const builder = new ContractBuilder(); const wasmPath = await builder.build( @@ -205,3 +223,4 @@ export class SequenceRunner { return fs.readFile(wasmPath); } } + diff --git a/test/contractBuilder.test.ts b/test/contractBuilder.test.ts index b816a5a..8dd6ead 100644 --- a/test/contractBuilder.test.ts +++ b/test/contractBuilder.test.ts @@ -3,6 +3,7 @@ import { promises as fs } from 'fs'; import * as os from 'os'; import * as path from 'path'; import { ContractBuilder } from '../src/build/ContractBuilder'; +import { TROUBLESHOOTING_URL, isUserFacing } from '../src/diagnostics/setup'; import { WASM_HEADER, customSection, wasmModule } from './support/wasmBytes'; const DEPS_REL = path.join('target', 'wasm32v1-none', 'release', 'deps'); @@ -219,3 +220,61 @@ describe('ContractBuilder (unit, temp dirs)', () => { }); }); }); + +/** + * What the user sees when the build cannot run: a missing Stellar CLI, a + * missing Rust toolchain or wasm target, and an ordinary compile failure. The + * wording lives in src/diagnostics/setup.ts (setupErrors.test.ts asserts it); + * these check that a real failed build reaches it, output tail included. + */ +describe('ContractBuilder failure diagnostics', () => { + const tempDirs: string[] = []; + + afterEach(async () => { + await Promise.all(tempDirs.splice(0).map((d) => fs.rm(d, { recursive: true, force: true }))); + }); + + async function contractDir(): Promise { + const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'contract-builder-fail-')); + tempDirs.push(dir); + return dir; + } + + async function buildError(buildCommand: string): Promise { + const dir = await contractDir(); + try { + await new ContractBuilder().build({ contractDir: dir, buildCommand }, () => undefined); + } catch (e) { + const err = e as Error; + assert.ok(isUserFacing(err), `expected a user-facing error, got ${err.name}: ${err.message}`); + assert.ok(err.message.includes(TROUBLESHOOTING_URL), `expected the README link in: ${err.message}`); + return err; + } + return assert.fail('expected the build to fail'); + } + + it('reports a missing `stellar` binary as a missing Stellar CLI', async () => { + const err = await buildError('stellar-cli-does-not-exist-4f2a contract build'); + assert.match(err.message, /stellar-cli-does-not-exist-4f2a/); + assert.match(err.message, /stellar\.cliPath|Stellar CLI/i); + }); + + it('reports a missing wasm target as a `rustup target add`', async () => { + const err = await buildError( + 'printf "error[E0463]: can\'t find crate for \\`core\\`\\nnote: the \\`wasm32v1-none\\` target may not be installed\\n" >&2; exit 101', + ); + assert.match(err.message, /rustup target add wasm32v1-none/); + }); + + it('reports an ordinary compile failure with its exit code and output tail', async () => { + const err = await buildError('printf "error: could not compile \\`token\\`\\n" >&2; exit 101'); + assert.match(err.message, /code 101/); + assert.match(err.message, /could not compile/); + }); + + it('reports a build that produced no wasm', async () => { + const err = await buildError('true'); + assert.match(err.message, /wasm/); + assert.match(err.message, /wasm32v1-none/); + }); +}); diff --git a/test/kometClient.test.ts b/test/kometClient.test.ts index 6dbed4f..4e0261a 100644 --- a/test/kometClient.test.ts +++ b/test/kometClient.test.ts @@ -200,3 +200,17 @@ describe('KometClient', () => { await assert.rejects(() => client.waitForHealthy(30, 5), /did not become healthy/); }); }); + +describe('waitForHealthy: giving up early', () => { + it('stops polling as soon as the caller says the node is doomed', async () => { + // Nothing is listening on this port, so only `giveUp` can end the wait — + // well inside the 60s deadline it is given. + const client = new KometClient({ host: '127.0.0.1', port: 1, timeoutMs: 100 }); + const started = Date.now(); + let doomed = false; + setTimeout(() => (doomed = true), 50); + + await assert.rejects(() => client.waitForHealthy(60_000, 20, () => doomed)); + assert.ok(Date.now() - started < 5000, 'the wait ran on past the give-up signal'); + }); +}); diff --git a/test/kometProcess.test.ts b/test/kometProcess.test.ts new file mode 100644 index 0000000..93daa61 --- /dev/null +++ b/test/kometProcess.test.ts @@ -0,0 +1,109 @@ +/** + * KometProcess failure detection: a node that cannot be spawned, or that dies + * before it serves, must be reported AT ONCE rather than left for the 60-second + * health-check timeout to notice. `whenFailed()` is what LiveBackend races the + * health check against. + */ + +import * as assert from 'assert'; +import { promises as fs } from 'fs'; +import * as os from 'os'; +import * as path from 'path'; +import { KometProcess } from '../src/komet/KometProcess'; +import { isUserFacing } from '../src/diagnostics/setup'; + +/** A command name no PATH can resolve. */ +const MISSING = 'komet-node-does-not-exist-4f2a'; + +/** Resolve to `'pending'` if `p` has not settled within `ms`. */ +function within(p: Promise, ms: number): Promise { + return Promise.race([p, new Promise<'pending'>((r) => setTimeout(() => r('pending'), ms))]); +} + +describe('KometProcess failure detection', () => { + const tempDirs: string[] = []; + + afterEach(async () => { + await Promise.all(tempDirs.splice(0).map((d) => fs.rm(d, { recursive: true, force: true }))); + }); + + /** + * An executable stand-in for komet-node: it ignores the --host/--port + * arguments the real node takes, so `body` decides how the "node" behaves. + */ + async function fakeNode(body: string): Promise { + const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'komet-process-test-')); + tempDirs.push(dir); + const script = path.join(dir, 'komet-node'); + await fs.writeFile(script, `#!/bin/sh\n${body}\n`, { mode: 0o755 }); + return script; + } + + it('reports a missing binary immediately, as a user-facing setup error', async () => { + const proc = new KometProcess({ command: MISSING, port: 8123 }); + const messages: string[] = []; + const started = Date.now(); + proc.start((m) => messages.push(m)); + + const failure = await within(proc.whenFailed(), 5000); + assert.notStrictEqual(failure, 'pending', 'the spawn failure was not reported'); + const err = failure as Error; + assert.ok(isUserFacing(err), `expected a user-facing error, got ${err.name}`); + assert.match(err.message, /komet-node/); + assert.match(err.message, /kup install komet-node/); + assert.match(err.message, new RegExp(MISSING)); + assert.ok(Date.now() - started < 5000, 'reporting a missing binary should not wait on a timeout'); + // The console still gets a line, so the log tells the same story. + assert.ok(messages.some((m) => /komet-node/.test(m)), messages.join('\n')); + await proc.stop(); + }); + + it('reports a node that exits before serving, with its exit code', async () => { + const proc = new KometProcess({ command: await fakeNode('exit 1'), port: 8123 }); + proc.start(() => undefined); + + const failure = await within(proc.whenFailed(), 5000); + assert.notStrictEqual(failure, 'pending', 'the early exit was not reported'); + const err = failure as Error; + assert.ok(isUserFacing(err)); + assert.match(err.message, /exited/); + assert.match(err.message, /code 1/); + await proc.stop(); + }); + + it('keeps the node output that explains an early exit', async () => { + const proc = new KometProcess({ + command: await fakeNode('echo "Address already in use" >&2; exit 2'), + port: 8123, + }); + proc.start(() => undefined); + + const failure = await within(proc.whenFailed(), 5000); + assert.notStrictEqual(failure, 'pending'); + assert.match((failure as Error).message, /Address already in use/); + await proc.stop(); + }); + + it('never reports a failure for a node we shut down ourselves', async () => { + const proc = new KometProcess({ command: await fakeNode('sleep 30'), port: 8123 }); + proc.start(() => undefined); + await proc.stop(); + + assert.strictEqual(await within(proc.whenFailed(), 300), 'pending'); + }); + + it('survives stop() after a failed spawn', async () => { + const proc = new KometProcess({ command: MISSING, port: 8123 }); + proc.start(() => undefined); + await within(proc.whenFailed(), 5000); + await assert.doesNotReject(() => proc.stop()); + }); + + it('does not report a failure while the node is still running', async () => { + const proc = new KometProcess({ command: await fakeNode('sleep 30'), port: 8123 }); + proc.start(() => undefined); + + assert.strictEqual(await within(proc.whenFailed(), 300), 'pending'); + await proc.stop(); + }); +}); diff --git a/test/setupBackends.test.ts b/test/setupBackends.test.ts new file mode 100644 index 0000000..77a87c7 --- /dev/null +++ b/test/setupBackends.test.ts @@ -0,0 +1,187 @@ +/** + * End-to-end behavior of the setup diagnostics through the backends: what a + * user actually sees when komet-node, the toolchain, or an input file is not + * there. The messages themselves are asserted in setupErrors.test.ts; here we + * check that each failure path REACHES them, and reaches them fast. + */ + +import * as assert from 'assert'; +import { promises as fs } from 'fs'; +import * as os from 'os'; +import * as path from 'path'; +import { LiveBackend } from '../src/debugAdapter/backends/LiveBackend'; +import { RawTraceBackend } from '../src/debugAdapter/backends/RawTraceBackend'; +import { SorobanLaunchArgs } from '../src/debugAdapter/types'; +import { TROUBLESHOOTING_URL, isUserFacing } from '../src/diagnostics/setup'; +import { MockKometNode } from './support/mockKometNode'; + +const FIXTURES = path.join(__dirname, '..', '..', 'test', 'fixtures'); +const WASM = path.join(FIXTURES, 'sample_contract.wasm'); +const TRACE = path.join(FIXTURES, 'add.trace.jsonl'); + +const MISSING_BINARY = 'komet-node-does-not-exist-4f2a'; + +/** A closed port: bind one, note it, release it. */ +async function freePort(): Promise { + const net = await import('net'); + const server = net.createServer(); + await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)); + const port = (server.address() as import('net').AddressInfo).port; + await new Promise((resolve) => server.close(() => resolve())); + return port; +} + +function launch(node: Record, wasm = WASM): SorobanLaunchArgs { + return { + transactions: [ + { kind: 'deploy', id: 'c', wasm }, + { kind: 'invoke', contract: 'c', function: 'add', args: { a: 1, b: 2 } }, + ], + node, + } as unknown as SorobanLaunchArgs; +} + +/** Reject the launch and hand back the error, asserting it is user-facing. */ +async function failedLaunch(backend: LiveBackend | RawTraceBackend, args: SorobanLaunchArgs): Promise { + try { + await backend.resolve(args, () => undefined); + } catch (e) { + const err = e as Error; + assert.ok(isUserFacing(err), `expected a user-facing error, got ${err.name}: ${err.message}`); + assert.ok(err.message.includes(TROUBLESHOOTING_URL), `expected the README link in: ${err.message}`); + return err; + } + return assert.fail('expected the launch to fail'); +} + +describe('a launch with komet-node missing', () => { + it('fails at once with an install hint, instead of waiting out the health check', async function () { + this.timeout(20_000); + const backend = new LiveBackend(); + const started = Date.now(); + // healthTimeoutMs is left at its 60s default on purpose: the point is that + // the spawn failure short-circuits it. + const err = await failedLaunch(backend, launch({ command: MISSING_BINARY, port: await freePort() })); + const elapsed = Date.now() - started; + + assert.match(err.message, /kup install komet-node/); + assert.match(err.message, /stellar\.kometNode\.path/); + assert.ok(elapsed < 10_000, `took ${elapsed}ms — the health-check timeout was not short-circuited`); + await backend.dispose(); + }); +}); + +describe('a launch against a node that is not there', () => { + it('explains an attach-mode failure as nothing listening, not as a missing install', async () => { + const backend = new LiveBackend(); + const err = await failedLaunch( + backend, + launch({ attach: true, host: '127.0.0.1', port: await freePort(), healthTimeoutMs: 300 }), + ); + + assert.match(err.message, /attach/); + assert.doesNotMatch(err.message, /kup install/); + await backend.dispose(); + }); + + it('explains a spawned node that never became healthy', async function () { + this.timeout(20_000); + const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'setup-backends-')); + const script = path.join(dir, 'komet-node'); + // Runs, serves nothing, and stays up: the health check must time out. + await fs.writeFile(script, '#!/bin/sh\nsleep 30\n', { mode: 0o755 }); + const backend = new LiveBackend(); + try { + const err = await failedLaunch( + backend, + launch({ command: script, port: await freePort(), healthTimeoutMs: 500 }), + ); + assert.match(err.message, /healthTimeoutMs/); + assert.match(err.message, /did not become (ready|healthy)|no response/i); + } finally { + await backend.dispose(); + await fs.rm(dir, { recursive: true, force: true }); + } + }); +}); + +describe('a launch against a komet-node that is too old', () => { + let mock: MockKometNode; + + afterEach(async () => { + if (mock) { + await mock.stop(); + } + }); + + it('explains a node with no traceTransaction method as a version problem', async () => { + mock = new MockKometNode({ + trace: await fs.readFile(TRACE, 'utf8'), + errorFor: { method: 'traceTransaction', code: -32601, message: 'Method not found' }, + }); + const port = await mock.start(); + + const backend = new LiveBackend(); + const err = await failedLaunch(backend, launch({ attach: true, host: '127.0.0.1', port })); + assert.match(err.message, /traceTransaction/); + assert.match(err.message, /kup install komet-node/); + await backend.dispose(); + }); + + it('explains a pre-v0.1.87 trace shape as a version problem', async () => { + // The old shape: no `kind` field on the records (see the release notes). + mock = new MockKometNode({ + trace: '{"pos":null,"instr":["callContract"],"stack":[],"locals":{}}', + }); + const port = await mock.start(); + + const backend = new LiveBackend(); + const err = await failedLaunch(backend, launch({ attach: true, host: '127.0.0.1', port })); + assert.match(err.message, /komet v0\.1\.87/); + assert.match(err.message, /kup install komet-node/); + await backend.dispose(); + }); +}); + +describe('a launch whose inputs cannot be read', () => { + let mock: MockKometNode; + + afterEach(async () => { + if (mock) { + await mock.stop(); + } + }); + + it('explains a missing rawTrace file, and how to record one', async () => { + const backend = new RawTraceBackend(); + const err = await failedLaunch(backend, { rawTrace: '/nope/missing.jsonl' } as SorobanLaunchArgs); + assert.match(err.message, /\/nope\/missing\.jsonl/); + assert.match(err.message, /rawTrace/); + assert.match(err.message, /no such file/i); + assert.match(err.message, /stellar-trace/); + }); + + it('explains a missing wasmPath alongside a good rawTrace', async () => { + const backend = new RawTraceBackend(); + const err = await failedLaunch(backend, { + rawTrace: TRACE, + wasmPath: '/nope/missing.wasm', + } as SorobanLaunchArgs); + assert.match(err.message, /\/nope\/missing\.wasm/); + assert.match(err.message, /wasmPath/); + }); + + it('explains a deploy step whose prebuilt wasm is missing, naming the step', async () => { + mock = new MockKometNode({ trace: await fs.readFile(TRACE, 'utf8') }); + const port = await mock.start(); + + const backend = new LiveBackend(); + const err = await failedLaunch( + backend, + launch({ attach: true, host: '127.0.0.1', port }, '/nope/missing.wasm'), + ); + assert.match(err.message, /\/nope\/missing\.wasm/); + assert.match(err.message, /"c"/); + await backend.dispose(); + }); +}); diff --git a/test/setupErrors.test.ts b/test/setupErrors.test.ts new file mode 100644 index 0000000..7fcd838 --- /dev/null +++ b/test/setupErrors.test.ts @@ -0,0 +1,354 @@ +/** + * The user-facing setup diagnostics: every message a missing or stale + * dependency produces must name the thing that is missing, say how to get it, + * and link to the README. These are pure string builders, so they are asserted + * directly here and reused by the backends (see setupBackends.test.ts). + */ + +import * as assert from 'assert'; +import { + README_URL, + SetupError, + TROUBLESHOOTING_URL, + buildFailure, + buildSpawnFailure, + formatErrorDetail, + isUserFacing, + kometExitedEarly, + kometSpawnFailure, + kometUnreachable, + staleKometRpc, + staleKometTraceMessage, + unreadableFile, +} from '../src/diagnostics/setup'; + +/** A Node spawn/fs error, as the runtime raises it. */ +function errno(code: string, message = `${code}: something went wrong`): NodeJS.ErrnoException { + const err: NodeJS.ErrnoException = new Error(message); + err.code = code; + return err; +} + +const ALL_ERRORS: (() => SetupError)[] = [ + () => kometSpawnFailure({ command: 'komet-node', error: errno('ENOENT') }), + () => kometSpawnFailure({ command: '/opt/komet-node', error: errno('EACCES') }), + () => kometSpawnFailure({ command: 'komet-node', error: errno('EMFILE') }), + () => kometExitedEarly({ command: 'komet-node', code: 1, signal: null, output: ['boom'], port: 8000 }), + () => kometUnreachable({ url: 'http://localhost:8000', attach: false, timeoutMs: 60_000, port: 8000 }), + () => kometUnreachable({ url: 'http://localhost:8000', attach: true, timeoutMs: 60_000, port: 8000 }), + () => buildFailure({ command: 'stellar contract build', cwd: '/w', code: 127, output: ['sh: 1: stellar: not found'] }), + () => buildFailure({ command: 'stellar contract build', cwd: '/w', code: 101, output: ['boom'] }), + () => buildSpawnFailure({ command: 'stellar contract build', error: errno('ENOENT') }), + () => staleKometRpc('traceTransaction'), + () => unreadableFile({ what: 'the recorded trace', path: '/x.jsonl', error: errno('ENOENT') }), +]; + +describe('setup diagnostics: the README link', () => { + it('points at the README on GitHub', () => { + assert.match(README_URL, /^https:\/\/github\.com\/runtimeverification\/stellar-debugger\b/); + assert.match(README_URL, /README\.md$/); + assert.ok(TROUBLESHOOTING_URL.startsWith(README_URL)); + }); + + it('closes every setup error, and the stale-trace message, with the link', () => { + for (const make of ALL_ERRORS) { + const message = make().message; + assert.ok( + message.trimEnd().endsWith(TROUBLESHOOTING_URL + '.') || message.includes(TROUBLESHOOTING_URL), + `missing the README link: ${message}`, + ); + } + assert.ok(staleKometTraceMessage('record 1 has no `kind` field').includes(TROUBLESHOOTING_URL)); + }); + + it('writes messages as prose, not as error codes', () => { + for (const make of ALL_ERRORS) { + const first = make().message.split('\n')[0]; + // A leading `Error: ENOENT ...` style line is what we are replacing. + assert.doesNotMatch(first, /^[A-Z]{4,}:/, `raw errno leaked into the first line: ${first}`); + assert.ok(first.length > 20, `first line is not informative: ${first}`); + } + }); +}); + +describe('setup diagnostics: komet-node cannot be started', () => { + it('says the binary is not installed, how to install it, and how to point at it', () => { + const message = kometSpawnFailure({ command: 'komet-node', error: errno('ENOENT') }).message; + assert.match(message, /komet-node/); + assert.match(message, /not found|no executable/i); + assert.match(message, /kup install komet-node/); + assert.match(message, /stellar\.kometNode\.path/); + assert.match(message, /node\.command/); + }); + + it('mentions that replaying a recorded trace needs no komet-node at all', () => { + const message = kometSpawnFailure({ command: 'komet-node', error: errno('ENOENT') }).message; + assert.match(message, /rawTrace/); + }); + + it('names the configured path when one was configured', () => { + const message = kometSpawnFailure({ command: '/opt/bin/komet-node', error: errno('ENOENT') }).message; + assert.match(message, /\/opt\/bin\/komet-node/); + }); + + it('distinguishes a non-executable file from a missing one', () => { + const message = kometSpawnFailure({ command: '/opt/bin/komet-node', error: errno('EACCES') }).message; + assert.match(message, /not executable|permission/i); + assert.match(message, /chmod \+x/); + assert.doesNotMatch(message, /kup install/); + }); + + it('falls back to the underlying reason for an unexpected spawn failure', () => { + const message = kometSpawnFailure({ + command: 'komet-node', + error: errno('EMFILE', 'EMFILE: too many open files'), + }).message; + assert.match(message, /too many open files/); + assert.match(message, /komet-node/); + }); +}); + +describe('setup diagnostics: komet-node started but did not serve', () => { + it('reports an early exit with its code, its output, and the port hint', () => { + const message = kometExitedEarly({ + command: 'komet-node', + code: 1, + signal: null, + output: ['Address already in use', 'giving up'], + port: 8000, + }).message; + assert.match(message, /exited/); + assert.match(message, /code 1/); + assert.match(message, /giving up/); + assert.match(message, /port/); + assert.match(message, /node\.port/); + }); + + it('reports a killing signal instead of an exit code when there is one', () => { + const message = kometExitedEarly({ + command: 'komet-node', + code: null, + signal: 'SIGKILL', + output: [], + port: 8000, + }).message; + assert.match(message, /SIGKILL/); + }); + + it('explains a health-check timeout in spawn mode, with the knob to raise it', () => { + const message = kometUnreachable({ + url: 'http://localhost:8000', + attach: false, + timeoutMs: 60_000, + port: 8000, + }).message; + assert.match(message, /http:\/\/localhost:8000/); + assert.match(message, /60/); // the timeout, in seconds or ms + assert.match(message, /healthTimeoutMs/); + assert.match(message, /node\.port/); + }); + + it('explains an attach-mode timeout as nothing listening, not as a missing install', () => { + const message = kometUnreachable({ + url: 'http://127.0.0.1:9999', + attach: true, + timeoutMs: 500, + port: 9999, + }).message; + assert.match(message, /http:\/\/127\.0\.0\.1:9999/); + assert.match(message, /attach/); + assert.match(message, /komet-node --host 127\.0\.0\.1 --port 9999|start .*komet-node/); + assert.doesNotMatch(message, /kup install/); + }); +}); + +describe('setup diagnostics: the contract build', () => { + const cwd = '/work/contract'; + + it('names the missing Stellar CLI and the setting that points at it', () => { + const message = buildFailure({ + command: 'stellar contract build', + cwd, + code: 127, + output: ['sh: 1: stellar: not found'], + }).message; + assert.match(message, /stellar/); + assert.match(message, /Stellar CLI/i); + assert.match(message, /stellar\.cliPath/); + assert.match(message, /buildCommand/); + assert.match(message, /developers\.stellar\.org/); + }); + + it('recognizes the `bash: X: command not found` phrasing too', () => { + const message = buildFailure({ + command: 'stellar contract build', + cwd, + code: 127, + output: ['bash: stellar: command not found'], + }).message; + assert.match(message, /Stellar CLI/i); + }); + + it('recognizes the `zsh: command not found: X` phrasing too', () => { + const message = buildFailure({ + command: 'cargo build', + cwd, + code: 127, + output: ['zsh: command not found: cargo'], + }).message; + assert.match(message, /Rust/i); + assert.match(message, /rustup/); + }); + + it('points at rustup when the Rust toolchain itself is missing', () => { + const message = buildFailure({ + command: 'stellar contract build', + cwd, + code: 127, + output: ['sh: 1: cargo: not found'], + }).message; + assert.match(message, /Rust/i); + assert.match(message, /rustup/); + assert.doesNotMatch(message, /stellar\.cliPath/); + }); + + it('points at `rustup target add` when the wasm target is missing', () => { + const message = buildFailure({ + command: 'stellar contract build', + cwd, + code: 101, + output: [ + "error[E0463]: can't find crate for `core`", + 'note: the `wasm32v1-none` target may not be installed', + ], + }).message; + assert.match(message, /rustup target add wasm32v1-none/); + assert.match(message, /wasm32-unknown-unknown/); + }); + + it('says the command is not the Stellar CLI when it rejects `contract build`', () => { + const message = buildFailure({ + command: 'stellar contract build', + cwd, + code: 2, + output: ["error: unrecognized subcommand 'contract'"], + }).message; + assert.match(message, /Stellar CLI/i); + assert.match(message, /stellar\.cliPath/); + }); + + it('reports an unrecognized failure with the command, the directory, and the output tail', () => { + const message = buildFailure({ + command: 'stellar contract build', + cwd, + code: 101, + output: ['warning: unused import', 'error: could not compile `token`'], + }).message; + assert.match(message, /stellar contract build/); + assert.match(message, /\/work\/contract/); + assert.match(message, /code 101/); + assert.match(message, /could not compile `token`/); + // Still tells the reader what the build needs, since a toolchain problem + // often surfaces as an ordinary compile failure. + assert.match(message, /wasm32v1-none|Rust/); + }); + + it('keeps the output tail bounded', () => { + const output = Array.from({ length: 200 }, (_, i) => `line ${i}`); + const message = buildFailure({ command: 'x', cwd, code: 1, output }).message; + assert.match(message, /line 199/); + assert.doesNotMatch(message, /line 100\b/); + assert.ok(message.length < 2000, `message is ${message.length} chars`); + }); + + it('handles a build command that could not be launched at all', () => { + const message = buildSpawnFailure({ + command: 'stellar contract build', + error: errno('ENOENT', 'spawn /bin/sh ENOENT'), + }).message; + assert.match(message, /stellar contract build/); + assert.match(message, /could not|failed/i); + }); +}); + +describe('setup diagnostics: a stale komet-node', () => { + it('explains the old trace shape as a version problem, with the fix', () => { + const message = staleKometTraceMessage('record 1 has no `kind` field'); + assert.match(message, /record 1 has no `kind` field/); + assert.match(message, /komet v0\.1\.87/); + assert.match(message, /kup install komet-node/); + assert.match(message, /re-?record/i); + }); + + it('explains a missing traceTransaction method as a version problem', () => { + const message = staleKometRpc('traceTransaction').message; + assert.match(message, /traceTransaction/); + assert.match(message, /too old|older/i); + assert.match(message, /kup install komet-node/); + }); +}); + +describe('setup diagnostics: unreadable inputs', () => { + it('explains a missing file in words, with what it was for', () => { + const message = unreadableFile({ + what: 'the recorded trace (`rawTrace`)', + path: '/traces/add.jsonl', + error: errno('ENOENT', "ENOENT: no such file or directory, open '/traces/add.jsonl'"), + hint: 'Record one with `stellar-trace --out add.jsonl`.', + }).message; + assert.match(message, /the recorded trace \(`rawTrace`\)/); + assert.match(message, /\/traces\/add\.jsonl/); + assert.match(message, /no such file/i); + assert.match(message, /stellar-trace --out add\.jsonl/); + }); + + it('distinguishes a permission problem and a directory from a missing file', () => { + const denied = unreadableFile({ what: 'the contract wasm', path: '/w/a.wasm', error: errno('EACCES') }).message; + assert.match(denied, /permission/i); + const isDir = unreadableFile({ what: 'the contract wasm', path: '/w', error: errno('EISDIR') }).message; + assert.match(isDir, /directory/i); + }); +}); + +describe('setup diagnostics: how errors are printed', () => { + it('marks setup errors as user-facing and plain errors as not', () => { + assert.ok(isUserFacing(new SetupError('nope'))); + assert.ok(isUserFacing(kometSpawnFailure({ command: 'komet-node', error: errno('ENOENT') }))); + assert.ok(!isUserFacing(new Error('boom'))); + assert.ok(!isUserFacing('boom')); + assert.ok(!isUserFacing(undefined)); + }); + + it('prints a user-facing error as its message alone, with no stack trace', () => { + const detail = formatErrorDetail(kometSpawnFailure({ command: 'komet-node', error: errno('ENOENT') })); + assert.match(detail, /kup install komet-node/); + assert.doesNotMatch(detail, /\n\s+at /); + assert.doesNotMatch(detail, /SetupError/); + }); + + it('prints an unexpected error with its stack, so a bug stays diagnosable', () => { + const detail = formatErrorDetail(new Error('boom')); + assert.match(detail, /boom/); + assert.match(detail, /\n\s+at /); + }); + + it('prints a non-error as itself', () => { + assert.strictEqual(formatErrorDetail('just a string'), 'just a string'); + }); +}); + +describe('setup diagnostics: a missing program we cannot classify', () => { + it('names it without claiming to know which dependency it is', () => { + const message = buildFailure({ + command: 'my-wrapper build', + cwd: '/w', + code: 127, + output: ['sh: 1: my-wrapper: not found'], + }).message; + assert.match(message, /my-wrapper/); + assert.match(message, /buildCommand/); + // Guessing "install the Stellar CLI" here would be a confident wrong answer. + assert.doesNotMatch(message, /Install the Stellar CLI/); + assert.doesNotMatch(message, /rustup/); + }); +}); diff --git a/test/support/mockKometNode.ts b/test/support/mockKometNode.ts index 41da532..5f8e203 100644 --- a/test/support/mockKometNode.ts +++ b/test/support/mockKometNode.ts @@ -23,6 +23,12 @@ export interface MockOptions { delayMs?: number; /** If set, delay ONLY responses for this method; if unset, delay all. */ delayMethod?: string; + /** + * Answer one method with a JSON-RPC error instead of a result — e.g. the + * `-32601 Method not found` an older komet-node returns for + * `traceTransaction`. + */ + errorFor?: { method: string; code: number; message: string }; } export class MockKometNode { @@ -68,6 +74,15 @@ export class MockKometNode { const msg = JSON.parse(body); id = msg.id; this.received.push({ method: msg.method, params: msg.params ?? {} }); + const failure = this.opts.errorFor; + if (failure && failure.method === msg.method) { + this.send(res, { + jsonrpc: '2.0', + id, + error: { code: failure.code, message: failure.message }, + }); + return; + } const result = this.dispatch(msg.method); const res_ = { jsonrpc: '2.0', id, result }; if ( diff --git a/test/trace.test.ts b/test/trace.test.ts index e5a3e6c..984277d 100644 --- a/test/trace.test.ts +++ b/test/trace.test.ts @@ -68,3 +68,37 @@ describe('trace parsing', () => { ); }); }); + +describe('trace parsing: a pre-v0.1.87 komet-node', () => { + it('explains the old record shape as a stale komet-node, not as a parse error', () => { + // The old shape carried no `kind` field (see the 0.1.0 release notes). + assert.throws( + () => toTraceRecord({ pos: null, instr: ['callContract'], stack: [], locals: {} }, 1), + (e: unknown) => { + assert.ok(e instanceof TraceParseError, 'must stay a TraceParseError for existing handlers'); + assert.match((e as Error).message, /komet v0\.1\.87/); + assert.match((e as Error).message, /kup install komet-node/); + assert.match((e as Error).message, /README\.md/); + return true; + }, + ); + }); + + it('reports the record number so a partially-old trace is locatable', () => { + assert.throws( + () => toTraceRecords([ + { kind: 'instr', pos: 1, instr: ['nop'] }, + { pos: 2, instr: ['nop'] }, + ]), + /record 2|line 2/, + ); + }); + + it('still reports a plainly malformed record as a malformed record', () => { + assert.throws(() => toTraceRecord({ foo: 1 }, 1), /'kind'/); + assert.throws(() => toTraceRecord({ foo: 1 }, 1), (e: unknown) => { + assert.doesNotMatch((e as Error).message, /komet v0\.1\.87/); + return true; + }); + }); +}); From 9dd085dabed403f93ec04faa44bea6951c30485c Mon Sep 17 00:00:00 2001 From: Raoul Date: Fri, 21 Aug 2026 12:24:23 +0000 Subject: [PATCH 07/13] docs: say how to install kup and komet-node MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Requirements section named komet-node and linked its repository, but the repository's own README does not say how to install it either — the reader was left to discover that it comes from `kup`, and that `kup` comes from Nix. The three commands are the ones `.devcontainer/Dockerfile` already runs, so the README and the container cannot drift apart. The `nix.conf` stanza the Dockerfile writes is deliberately left out: it exists only because the image build has stdin closed, where kup's prompt to register the substituters dies on EOFError. A human running this interactively just answers the prompt. --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 1f55ea8..ab69c58 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,17 @@ Replaying an already-recorded trace needs none of the above — no toolchain, no The repository ships a [devcontainer](.devcontainer/Dockerfile) with all of it preinstalled if you'd rather not set it up by hand. If something is missing, the debugger says which tool it is and how to get it, and links back to [Troubleshooting](#troubleshooting) below. +### Installing komet-node + +komet-node is distributed with [`kup`](https://github.com/runtimeverification/kup), Runtime Verification's package manager, which builds on Nix: + +```bash +curl -L https://kframework.org/install | bash # installs kup +kup install komet-node # kup update komet-node, if already installed +``` + +The node and its K semantics are published to Runtime Verification's binary cache, so this downloads prebuilt binaries rather than compiling them; `kup` offers to register the caches that make that work the first time it needs them. `kup list komet-node` reports the installed version and whether a newer one exists. + ## Install Install **Stellar Debugger** from the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=runtimeverification.stellar-debugger), or from the command line: From ccbf2788094234ffea74a7cdd4e8730e09496dc9 Mon Sep 17 00:00:00 2001 From: Raoul Date: Fri, 21 Aug 2026 13:16:56 +0000 Subject: [PATCH 08/13] docs: drop the unreleased section Everything it listed ships in 0.1.0, and it described how setup problems are detected rather than what a user can do. --- CHANGELOG.md | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb11905..85bc424 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,23 +2,6 @@ All notable changes to this extension are documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] - -### Changed - -- When a dependency is missing, the debugger now says which one, how to install it, and where to set its path, and links to the README's new Troubleshooting section. This replaces messages like `build command exited with code 127` and `trace line 1: 'kind' must be a non-empty string`, which named a symptom rather than a cause. -- A komet-node that cannot be started — not installed, or not executable — fails the launch immediately instead of after the 60-second health-check timeout. -- A komet-node that exits during startup is reported with its exit code and its own last output, rather than as a health-check timeout. -- A komet-node older than komet v0.1.87 is now diagnosed as out of date, both when it rejects the `traceTransaction` request and when it returns the pre-v0.1.87 trace shape. -- An attach-mode launch (`node.attach`) that finds nothing listening says so, instead of suggesting an install you already have. -- A failed contract build is classified from its output: a missing Stellar CLI, a missing Rust toolchain, a missing WebAssembly target, and an ordinary compile failure each get their own message and fix. -- An unreadable `rawTrace` or `wasmPath` names the attribute it came from and why the file could not be read, instead of surfacing a raw `ENOENT`. -- `stellar-trace` and `stellar-dap` print these messages on their own, without a stack trace in front of them. - -### Added - -- `node.healthTimeoutMs` sets how long to wait for komet-node to start answering requests (default 60 s). - ## [0.1.0] — 2026-08-21 This is the first public release. The extension debugs Stellar smart contracts written in Rust, in VSCode or from the command line, and it steps backward as readily as forward. @@ -42,5 +25,4 @@ This is the first public release. The extension debugs Stellar smart contracts w - Debugging a contract requires [komet-node](https://github.com/runtimeverification/komet-node), the local Stellar network that runs it. It must be built with komet v0.1.87 or newer; an older build produces recordings this version cannot open, and says so rather than opening an empty session. - Building and deploying a contract also requires a Rust toolchain with a WebAssembly target and the Stellar CLI. Replaying a recording requires neither. -[Unreleased]: https://github.com/runtimeverification/stellar-debugger/compare/v0.1.0...HEAD [0.1.0]: https://github.com/runtimeverification/stellar-debugger/releases/tag/v0.1.0 From 395e97f1f20d5f6ec98bb5d99cd560fec23bf15f Mon Sep 17 00:00:00 2001 From: Raoul Date: Fri, 21 Aug 2026 13:16:57 +0000 Subject: [PATCH 09/13] chore: drop the release checklist from the repo It was a working doc for the 0.1.0 release and is kept outside the tree, under the now-ignored .notes/. --- .gitignore | 1 + RELEASE-CHECKLIST.md | 40 ---------------------------------------- 2 files changed, 1 insertion(+), 40 deletions(-) delete mode 100644 RELEASE-CHECKLIST.md diff --git a/.gitignore b/.gitignore index 62fb920..7741ea0 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,4 @@ test/fixtures/*/target/ examples/*/target/ # Fixture crates are built by hand only, to regenerate the committed .wasm. test/fixtures/*/Cargo.lock +.notes/ diff --git a/RELEASE-CHECKLIST.md b/RELEASE-CHECKLIST.md deleted file mode 100644 index ddf21cb..0000000 --- a/RELEASE-CHECKLIST.md +++ /dev/null @@ -1,40 +0,0 @@ -# First public release — polishing checklist - -Working doc for the v0.1.0 public release of the Stellar Debugger. Delete this file once the release is out. - -Decisions taken: full rename to `stellar` (debug type, settings, command, CLI binaries), version **0.1.0**, `examples/` stays repo-only rather than shipping in the `.vsix`, and the CLIs stay repo-built (no npm publish this release). - -## Done - -- [x] **Package identity.** `name` → `stellar-debugger`, `displayName` → `Stellar Debugger`, `version` → `0.1.0`, description rewritten; `.devcontainer/devcontainer.json` renamed too, and `package-lock.json` resynced. -- [x] **Full `soroban` → `stellar` rename of everything users type or see**: debug type `"type": "stellar"`, settings `stellar.kometNode.path` and `stellar.cliPath` (was the awkward `soroban.stellar.path`), command `stellar.debug`, binaries `stellar-dap` / `stellar-trace`, the thread label `stellar-vm [n/m]`, and every launch-config name, snippet, error message, doc and example. Internal identifiers (`SorobanDebugSession`, `SorobanLaunchArgs`, `src/soroban/**`) deliberately keep the name: they refer to the Soroban protocol layer, not to the product, and renaming them would churn the whole tree for no user-visible gain. -- [x] **Marketplace metadata.** `icon` (128×128, `images/icon.png`, generated from `images/icon.svg`), `galleryBanner`, ten `keywords`, `categories: [Debuggers, Testing]`, and `preview: true` for the first release. -- [x] **`.vscodeignore` rewritten as an allowlist.** `vsce ls` now reports exactly 8 files and `npm run package` produces a 905 KB `.vsix` — previously it would have swept in the ~5.8 GB of `examples/*/target` and `test/fixtures/*/target` that git ignores but `vsce` does not. -- [x] **Release plumbing.** `@vscode/vsce` and `ovsx` added as devDependencies with `package` / `publish:vscode` / `publish:openvsx` scripts, plus `.github/workflows/release.yml`: tag-triggered, refuses a tag that disagrees with `package.json`, runs the suite with the e2e opt-out (CI already ran it against the real node on that commit), then publishes to the VS Code Marketplace and Open VSX and attaches the `.vsix` to a GitHub release. -- [x] **CHANGELOG.** `[Unreleased]` folded into `[0.1.0] — 2026-08-21`, rewritten as a first-public-release feature list rather than a diff against a version nobody had; the fictional `[0.1.0]`-predecessor entry and its dead tag link are gone, and the komet-node floor is stated under Requirements. -- [x] **README.** New **Install** section (marketplace, `code --install-extension`, Open VSX for Cursor/Windsurf/VSCodium); komet-node **≥ v0.1.87** stated in Requirements with the note that replay needs no toolchain at all; a **Known limitations** section covering partial traces, the opt-level-0 requirement, and one-traced-transaction-per-session; the Roadmap no longer contradicts the Features (the Variables view ships — *inline* values are what's still future); `examples/` described as a repo clone rather than "bundled"; and the CLIs marked as repo-built, not installed by the extension. -- [x] **CLI docs** (`docs/trace-cli.md`, `docs/dap-cli.md`) say plainly that a marketplace install does not put `stellar-trace` / `stellar-dap` on `PATH`. -- [x] **`SECURITY.md`** (private reporting, scope, and the explicit non-vulnerability of a `launch.json` naming its own build command) and **`CODE_OF_CONDUCT.md`** (Contributor Covenant 2.1). -- [x] **Repo hygiene.** `.gitignore` covers `.env`, `.env.*` and `.deps/`; the personal `/home/node/work/...` entries are out of `.vscode/launch.json`; the stray `state.kore` is deleted. -- [x] **Personal paths out of the test data.** `test/justMyCode.test.ts` classified paths under `/home/node/work/rs-lending-xlm/...`, naming an internal project in a repo about to go public; the ground-truth paths are now neutral (`/home/dev/work/lending-pool/...`), which the classifier treats identically since it keys off `.rustup` / `.cargo/registry` / `/rustc/` markers. -- [x] **Lint covers the tests too** (`eslint src test`), and it passes. -- [x] **Activation narrowed.** `activationEvents` was the blanket `onDebug`, which woke this extension for *any* debug session and left the palette command relying on implicit activation; it is now `onDebugResolve:stellar` plus an explicit `onCommand:stellar.debug`. -- [x] **`engines.vscode: ^1.85.0` verified.** `src/extension.ts` is the only module that imports `vscode`, and every API it touches (`registerDebugConfigurationProvider`, `registerDebugAdapterDescriptorFactory`, `DebugAdapterInlineImplementation`, `getConfiguration`, `showInputBox`, `startDebugging`) long predates 1.85; the disassembly, memory and step-back features are negotiated DAP capabilities, supported well before it. The floor is truthful and conservative. -- [x] **CONTRIBUTING** documents the release process, the allowlist `.vscodeignore` invariant, and the deliberate decision to defer the ESLint 9 migration until after the release (dev-only dependency, never reaches the `.vsix`). - -## Needs a human - -- [ ] **Pin, or at least verify, the `komet-node` version CI and the devcontainer install.** Both run a bare `kup install komet-node`, so they ride whatever is newest at build time — and the trace format is a hard contract this extension rejects on mismatch, which means CI can turn red with no change in this repo. This is not hypothetical: the devcontainer in use here has komet-node `7b2c71b`, about fourteen commits stale and predating the komet v0.1.88 bump, so **all six real-node e2e tests fail locally** with `trace line 1: 'kind' must be a non-empty string`. A raw dump confirms that node still serves the old shape (`{"pos":null,"instr":["callContract"],…}`, no `kind`). Nothing in this repo is at fault, and no polishing change caused it, but the release tag has to sit on a commit whose e2e suite really passed — so rebuild the devcontainer (or `kup install komet-node --version `) and confirm green before tagging. - -- [ ] **Record a screenshot or a short GIF for the README.** This is the one real gap left: the marketplace page is the README, and a time-travel debugger sells on motion — stepping backwards, the Ledger view scrubbing with the cursor. Nothing else on this list can substitute for it. -- [ ] **Confirm the marketplace publisher and add the secrets.** `publisher: runtimeverification` must exist and be verified, with `VSCE_PAT` and `OVSX_PAT` stored as repository secrets, plus an Open VSX namespace of the same name. -- [ ] **Enable GitHub private vulnerability reporting** (Settings → Security) so the link in `SECURITY.md` resolves, and confirm `security@runtimeverification.com` is a mailbox someone actually watches — replace it if not. -- [ ] **Consider a designed icon.** `images/icon.png` is a hand-rolled rewind glyph on navy: legible at tile and tree size, but a real designer would do better. Regeneration instructions are in `images/README.md`. -- [ ] **Install the packaged `.vsix` in a clean VSCode** (no repo, no dev dependencies) and run one replay config and one live build-deploy-debug config. The replay path must work with no toolchain at all — that is the front page's claim. -- [ ] **Tag the release** on a commit that is green on CI: `git tag v0.1.0 && git push origin v0.1.0`. Then check that the marketplace and Open VSX links in the README resolve. -- [ ] **Verify the README's relative links** on the rendered marketplace page (`vsce` rewrites them against the `repository` field; the `docs/` and `examples/` links do not ship inside the `.vsix`). - -## After the release - -- [ ] Migrate to ESLint 9's flat config. -- [ ] Revisit `preview: true` once the first users have reported back. From 0ea3c95d2d8ec39c0c5766788c59002e945cab91 Mon Sep 17 00:00:00 2001 From: Raoul Date: Fri, 21 Aug 2026 14:01:41 +0000 Subject: [PATCH 10/13] chore(deps): patch the npm advisories axios and form-data were the only two reaching users, bundled into dist/ through @stellar/stellar-sdk; the rest are dev-only. Every mocha up to 12.0.0-beta-2 pins vulnerable serialize-javascript, qs and diff majors, so those go through overrides rather than the downgrade of the test runner that npm audit suggests. --- package-lock.json | 879 ++++++++++++++++++++++++++++------------------ package.json | 9 +- 2 files changed, 536 insertions(+), 352 deletions(-) diff --git a/package-lock.json b/package-lock.json index f0e2f82..c38a181 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,10 +29,10 @@ "@vscode/debugadapter-testsupport": "^1.68.0", "@vscode/vsce": "^3.6.0", "c8": "^11.0.0", - "esbuild": "^0.23.0", + "esbuild": "^0.28.2", "eslint": "^8.57.0", "fast-check": "^4.9.0", - "mocha": "^10.7.0", + "mocha": "^11.8.0", "ovsx": "^0.10.1", "typescript": "^5.5.0" }, @@ -789,9 +789,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", - "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", "cpu": [ "ppc64" ], @@ -806,9 +806,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", - "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", "cpu": [ "arm" ], @@ -823,9 +823,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", - "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", "cpu": [ "arm64" ], @@ -840,9 +840,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", - "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", "cpu": [ "x64" ], @@ -857,9 +857,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", - "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", "cpu": [ "arm64" ], @@ -874,9 +874,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", - "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", "cpu": [ "x64" ], @@ -891,9 +891,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", - "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", "cpu": [ "arm64" ], @@ -908,9 +908,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", - "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", "cpu": [ "x64" ], @@ -925,9 +925,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", - "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", "cpu": [ "arm" ], @@ -942,9 +942,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", - "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", "cpu": [ "arm64" ], @@ -959,9 +959,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", - "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", "cpu": [ "ia32" ], @@ -976,9 +976,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", - "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", "cpu": [ "loong64" ], @@ -993,9 +993,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", - "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", "cpu": [ "mips64el" ], @@ -1010,9 +1010,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", - "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", "cpu": [ "ppc64" ], @@ -1027,9 +1027,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", - "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", "cpu": [ "riscv64" ], @@ -1044,9 +1044,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", - "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", "cpu": [ "s390x" ], @@ -1061,9 +1061,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", - "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", "cpu": [ "x64" ], @@ -1077,10 +1077,27 @@ "node": ">=18" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", - "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", "cpu": [ "x64" ], @@ -1095,9 +1112,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", - "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", "cpu": [ "arm64" ], @@ -1112,9 +1129,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", - "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", "cpu": [ "x64" ], @@ -1128,10 +1145,27 @@ "node": ">=18" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", - "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", "cpu": [ "x64" ], @@ -1146,9 +1180,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", - "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", "cpu": [ "arm64" ], @@ -1163,9 +1197,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", - "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", "cpu": [ "ia32" ], @@ -1180,9 +1214,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", - "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", "cpu": [ "x64" ], @@ -1257,9 +1291,9 @@ "license": "MIT" }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", "dev": true, "license": "MIT", "dependencies": { @@ -1324,9 +1358,9 @@ "license": "MIT" }, "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", "dev": true, "license": "MIT", "dependencies": { @@ -1713,6 +1747,78 @@ } } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/@istanbuljs/schema": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", @@ -2088,6 +2194,17 @@ "node": ">= 8" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@sec-ant/readable-stream": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", @@ -3258,16 +3375,6 @@ "node": ">= 14" } }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-escapes": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", @@ -3310,20 +3417,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -3363,13 +3456,13 @@ } }, "node_modules/axios": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.17.0.tgz", - "integrity": "sha512-J8SwNxprqqpbfenehxWYXE7CW+wM1BB4w3+N+g+/Wx40xM4rsLrfPmHHxSWIxJLYDgSY/HqlFPIYb2/S3rxafw==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.19.0.tgz", + "integrity": "sha512-ht/iuYZXEjFxLH/Hkezgd7m6JKlHHXEUSneaDz8uZe1Gj5QZtCnpyDsckvAiEnT89OEbCLmnte4R4sn7P0EKFw==", "license": "MIT", "dependencies": { "follow-redirects": "^1.16.0", - "form-data": "^4.0.5", + "form-data": "^4.0.6", "https-proxy-agent": "^5.0.1", "proxy-from-env": "^2.1.0" } @@ -3458,19 +3551,6 @@ "node": "*" } }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/binaryextensions": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-6.11.0.tgz", @@ -3541,16 +3621,16 @@ "license": "BSD-2-Clause" }, "node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", + "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" }, "engines": { - "node": "18 || 20 || >=22" + "node": "20 || >=22" } }, "node_modules/braces": { @@ -3698,50 +3778,6 @@ } } }, - "node_modules/c8/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/c8/node_modules/yargs": { - "version": "17.7.3", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", - "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/c8/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, "node_modules/call-bind": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", @@ -3902,41 +3938,19 @@ } }, "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "dev": true, "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^4.0.1" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 14.16.0" }, "funding": { "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" } }, "node_modules/chownr": { @@ -3965,15 +3979,36 @@ } }, "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "license": "ISC", "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/cockatiel": { @@ -4261,9 +4296,9 @@ } }, "node_modules/diff": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.2.tgz", - "integrity": "sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A==", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -4363,6 +4398,13 @@ "node": ">= 0.4" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -4514,9 +4556,9 @@ } }, "node_modules/esbuild": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", - "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -4527,30 +4569,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.23.1", - "@esbuild/android-arm": "0.23.1", - "@esbuild/android-arm64": "0.23.1", - "@esbuild/android-x64": "0.23.1", - "@esbuild/darwin-arm64": "0.23.1", - "@esbuild/darwin-x64": "0.23.1", - "@esbuild/freebsd-arm64": "0.23.1", - "@esbuild/freebsd-x64": "0.23.1", - "@esbuild/linux-arm": "0.23.1", - "@esbuild/linux-arm64": "0.23.1", - "@esbuild/linux-ia32": "0.23.1", - "@esbuild/linux-loong64": "0.23.1", - "@esbuild/linux-mips64el": "0.23.1", - "@esbuild/linux-ppc64": "0.23.1", - "@esbuild/linux-riscv64": "0.23.1", - "@esbuild/linux-s390x": "0.23.1", - "@esbuild/linux-x64": "0.23.1", - "@esbuild/netbsd-x64": "0.23.1", - "@esbuild/openbsd-arm64": "0.23.1", - "@esbuild/openbsd-x64": "0.23.1", - "@esbuild/sunos-x64": "0.23.1", - "@esbuild/win32-arm64": "0.23.1", - "@esbuild/win32-ia32": "0.23.1", - "@esbuild/win32-x64": "0.23.1" + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" } }, "node_modules/escalade": { @@ -4671,9 +4715,9 @@ "license": "MIT" }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", "dev": true, "license": "MIT", "dependencies": { @@ -4920,9 +4964,9 @@ } }, "node_modules/fast-uri": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.3.tgz", - "integrity": "sha512-i70LwGWUduXqzicKXWshooq+sWL1K3WUU5rKZNG/0i3a1OSoX3HqhH5WbWwTmqWfor4urUakGPiRQcleRZTwOg==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", "dev": true, "funding": [ { @@ -5122,16 +5166,16 @@ } }, "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" + "hasown": "^2.0.4", + "mime-types": "^2.1.35" }, "engines": { "node": ">= 6" @@ -5167,21 +5211,6 @@ "dev": true, "license": "ISC" }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -5274,21 +5303,22 @@ "optional": true }, "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, - "engines": { - "node": ">=12" + "bin": { + "glob": "dist/esm/bin.mjs" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -5315,26 +5345,53 @@ "license": "MIT" }, "node_modules/glob/node_modules/brace-expansion": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", - "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, + "node_modules/glob/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, "node_modules/glob/node_modules/minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/globals": { @@ -5734,19 +5791,6 @@ "license": "ISC", "optional": true }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -6022,6 +6066,22 @@ "url": "https://bevry.me/fund" } }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/js-md4": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz", @@ -6551,31 +6611,32 @@ "optional": true }, "node_modules/mocha": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", - "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", + "version": "11.8.0", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.8.0.tgz", + "integrity": "sha512-VyCeUdGN3A9lmCTTgG4yuvY9ixxaDk+xt2R/7/+1AP6EqNG+G9OKkzBwhVtVYoNX8YsxNSgAl8mOv3IAeOpFbw==", "dev": true, "license": "MIT", "dependencies": { - "ansi-colors": "^4.1.3", "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", + "chokidar": "^4.0.1", "debug": "^4.3.5", - "diff": "^5.2.0", + "diff": "^7.0.0", "escape-string-regexp": "^4.0.0", "find-up": "^5.0.0", - "glob": "^8.1.0", + "glob": "^10.4.5", "he": "^1.2.0", + "is-path-inside": "^3.0.3", "js-yaml": "^4.1.0", "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", + "minimatch": "^9.0.5", "ms": "^2.1.3", + "picocolors": "^1.1.1", "serialize-javascript": "^6.0.2", "strip-json-comments": "^3.1.1", "supports-color": "^8.1.1", - "workerpool": "^6.5.1", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9", + "workerpool": "^9.2.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", "yargs-unparser": "^2.0.0" }, "bin": { @@ -6583,7 +6644,7 @@ "mocha": "bin/mocha.js" }, "engines": { - "node": ">= 14.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/mocha/node_modules/balanced-match": { @@ -6594,9 +6655,9 @@ "license": "MIT" }, "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", - "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", "dev": true, "license": "MIT", "dependencies": { @@ -6604,16 +6665,19 @@ } }, "node_modules/mocha/node_modules/minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/mocha/node_modules/supports-color": { @@ -6781,16 +6845,6 @@ "dev": true, "license": "ISC" }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/npm-run-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", @@ -6982,6 +7036,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -7342,13 +7403,14 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.15.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", - "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", + "version": "6.15.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.1.0" + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" }, "engines": { "node": ">=0.6" @@ -7511,16 +7573,17 @@ } }, "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, "engines": { - "node": ">=8.10.0" + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/require-directory": { @@ -7589,9 +7652,9 @@ "license": "MIT" }, "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "version": "1.1.18", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.18.tgz", + "integrity": "sha512-Edep/X9fGqVNmzKBVsDYIOtD+z1tuezV70LBjdCst9Tqu76lsnvRiZ6oTic1n+/BIwX6QDGAO94PN4N2SADvtw==", "dev": true, "license": "MIT", "dependencies": { @@ -7754,13 +7817,13 @@ } }, "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.1.0.tgz", + "integrity": "sha512-RNEqWOyhhUQYN9V1GfHwu9AR/g+NTciH6Z5u3/no6X3/w+04J2lVDL+svFQVXgXrEGBMG2puMVN3gq2SNGuTGw==", "dev": true, "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" + "engines": { + "node": ">=20.0.0" } }, "node_modules/set-function-length": { @@ -8074,6 +8137,22 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -8087,6 +8166,20 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-final-newline": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", @@ -8799,13 +8892,32 @@ } }, "node_modules/workerpool": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", - "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "version": "9.3.4", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz", + "integrity": "sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg==", "dev": true, "license": "Apache-2.0" }, "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", @@ -8823,6 +8935,73 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -8888,32 +9067,32 @@ "license": "ISC" }, "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.7.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz", + "integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==", "dev": true, "license": "MIT", "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.1.1" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, "license": "ISC", "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-unparser": { diff --git a/package.json b/package.json index 5e322b9..d22050c 100644 --- a/package.json +++ b/package.json @@ -290,11 +290,16 @@ "@vscode/debugadapter-testsupport": "^1.68.0", "@vscode/vsce": "^3.6.0", "c8": "^11.0.0", - "esbuild": "^0.23.0", + "esbuild": "^0.28.2", "eslint": "^8.57.0", "fast-check": "^4.9.0", - "mocha": "^10.7.0", + "mocha": "^11.8.0", "ovsx": "^0.10.1", "typescript": "^5.5.0" + }, + "overrides": { + "serialize-javascript": "^7.1.0", + "qs": "^6.15.3", + "diff": "^8.0.3" } } From b23fca92fb79d8b30d63172b149d9a9e840b9737 Mon Sep 17 00:00:00 2001 From: Raoul Date: Fri, 21 Aug 2026 14:01:46 +0000 Subject: [PATCH 11/13] chore(deps): build the examples against soroban-sdk 27 stellar-xdr and soroban-env-host had no patched version reachable from soroban-sdk 22. SDK 27 requires the wasm32v1-none target, which ContractBuilder already auto-detects, so neither code nor docs needed changing. Verified by tracing increment against a real komet-node: 1551 records, three source stops, variables resolving. --- examples/adder/Cargo.lock | 349 +++++++++++++++++-------- examples/adder/Cargo.toml | 2 +- examples/control/Cargo.lock | 473 +++++++++++++++++++++++----------- examples/control/Cargo.toml | 2 +- examples/greeter/Cargo.lock | 349 +++++++++++++++++-------- examples/greeter/Cargo.toml | 2 +- examples/increment/Cargo.lock | 349 +++++++++++++++++-------- examples/increment/Cargo.toml | 2 +- examples/stepper/Cargo.lock | 473 +++++++++++++++++++++++----------- examples/stepper/Cargo.toml | 2 +- 10 files changed, 1369 insertions(+), 634 deletions(-) diff --git a/examples/adder/Cargo.lock b/examples/adder/Cargo.lock index 6239382..c18efb0 100644 --- a/examples/adder/Cargo.lock +++ b/examples/adder/Cargo.lock @@ -21,6 +21,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -32,9 +38,9 @@ dependencies = [ [[package]] name = "ark-bls12-381" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +checksum = "3df4dcc01ff89867cd86b0da835f23c3f02738353aaee7dde7495af71363b8d5" dependencies = [ "ark-ec", "ark-ff", @@ -42,112 +48,136 @@ dependencies = [ "ark-std", ] +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + [[package]] name = "ark-ec" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" dependencies = [ + "ahash", "ark-ff", "ark-poly", "ark-serialize", "ark-std", - "derivative", - "hashbrown 0.13.2", + "educe", + "fnv", + "hashbrown 0.15.5", "itertools", + "num-bigint", + "num-integer", "num-traits", "zeroize", ] [[package]] name = "ark-ff" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" dependencies = [ "ark-ff-asm", "ark-ff-macros", "ark-serialize", "ark-std", - "derivative", + "arrayvec", "digest", + "educe", "itertools", "num-bigint", "num-traits", "paste", - "rustc_version", "zeroize", ] [[package]] name = "ark-ff-asm" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 1.0.109", + "syn 2.0.118", ] [[package]] name = "ark-ff-macros" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" dependencies = [ "num-bigint", "num-traits", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.118", ] [[package]] name = "ark-poly" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" dependencies = [ + "ahash", "ark-ff", "ark-serialize", "ark-std", - "derivative", - "hashbrown 0.13.2", + "educe", + "fnv", + "hashbrown 0.15.5", ] [[package]] name = "ark-serialize" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" dependencies = [ "ark-serialize-derive", "ark-std", + "arrayvec", "digest", "num-bigint", ] [[package]] name = "ark-serialize-derive" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.118", ] [[package]] name = "ark-std" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" dependencies = [ "num-traits", "rand", ] +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + [[package]] name = "autocfg" version = "1.5.1" @@ -160,12 +190,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.22.1" @@ -202,11 +226,17 @@ version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes-lit" -version = "0.0.5" +version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0adabf37211a5276e46335feabcbb1530c95eb3fdf85f324c7db942770aa025d" +checksum = "9b04f2b1d34cb428043f14aa4c853d14294532e8bbde3b6a3bc2faaaae31a1dd" dependencies = [ "num-bigint", "proc-macro2", @@ -230,6 +260,17 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_eval" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "chrono" version = "0.4.45" @@ -274,6 +315,17 @@ dependencies = [ "serde_json", ] +[[package]] +name = "crate-git-revision" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54851b5b3f24621804b1cded2820975623c205e3055d2d44031cdb1237339ac8" +dependencies = [ + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -417,17 +469,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "digest" version = "0.10.7" @@ -490,6 +531,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "either" version = "1.16.0" @@ -514,6 +567,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "enum-ordinalize" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89dd01549b09589510cf0647475075d12071456586d70f5c75c98ae2a5537677" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65863d15a4ce2888bd2f0f543cc963d3879c3a022c8ee43f6141d479a3ac815" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -619,6 +692,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -627,11 +709,11 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "ahash", + "allocator-api2", ] [[package]] @@ -640,6 +722,22 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hex" version = "0.4.3" @@ -725,9 +823,9 @@ checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" [[package]] name = "itertools" -version = "0.10.5" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] @@ -788,6 +886,17 @@ version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" +[[package]] +name = "macro-string" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "memchr" version = "2.8.2" @@ -1006,6 +1115,17 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "serde", + "serde_json", +] + [[package]] name = "schemars" version = "0.9.0" @@ -1098,12 +1218,13 @@ version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" dependencies = [ - "base64 0.22.1", + "base64", "bs58", "chrono", "hex", "indexmap 1.9.3", "indexmap 2.14.0", + "schemars 0.8.22", "schemars 0.9.0", "schemars 1.2.1", "serde_core", @@ -1175,9 +1296,9 @@ checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] name = "soroban-builtin-sdk-macros" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2e42bf80fcdefb3aae6ff3c7101a62cf942e95320ed5b518a1705bc11c6b2f" +checksum = "b77bc93d930032c487cb1506b6ed166b2af49db76d52678ec4887ac621ecce01" dependencies = [ "itertools", "proc-macro2", @@ -1187,15 +1308,14 @@ dependencies = [ [[package]] name = "soroban-env-common" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "027cd856171bfd6ad2c0ffb3b7dfe55ad7080fb3050c36ad20970f80da634472" +checksum = "6b22e9981cdd444f3aa6734bc58d76195bf7eca3ccf1dd432b875af5d02da068" dependencies = [ - "crate-git-revision", + "crate-git-revision 0.0.6", "ethnum", "num-derive", "num-traits", - "serde", "soroban-env-macros", "soroban-wasmi", "static_assertions", @@ -1205,9 +1325,9 @@ dependencies = [ [[package]] name = "soroban-env-guest" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a07dda1ae5220d975979b19ad4fd56bc86ec7ec1b4b25bc1c5d403f934e592e" +checksum = "2b6072f99ca6bf8e8d5b04e05d083dac785e5357d9c0f36a6658f819c2fd7d67" dependencies = [ "soroban-env-common", "static_assertions", @@ -1215,11 +1335,12 @@ dependencies = [ [[package]] name = "soroban-env-host" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66e8b03a4191d485eab03f066336112b2a50541a7553179553dc838b986b94dd" +checksum = "2c06afd7c75ce150ce53e4d77a77645b18e3fb61856a0ddc42bfcecdc39fa3b9" dependencies = [ "ark-bls12-381", + "ark-bn254", "ark-ec", "ark-ff", "ark-serialize", @@ -1245,15 +1366,15 @@ dependencies = [ "soroban-env-common", "soroban-wasmi", "static_assertions", - "stellar-strkey", + "stellar-strkey 0.0.13", "wasmparser", ] [[package]] name = "soroban-env-macros" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00eff744764ade3bc480e4909e3a581a240091f3d262acdce80b41f7069b2bd9" +checksum = "647811bdd28a3ec40296987f6635781e5e1141c8f5affbbd53ba12b6295b7bb6" dependencies = [ "itertools", "proc-macro2", @@ -1264,50 +1385,37 @@ dependencies = [ "syn 2.0.118", ] -[[package]] -name = "soroban-ledger-snapshot" -version = "22.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c30035cf1e8f02f65de3e594b6da113ecdaf1cd134d8480961d62568bb15adaf" -dependencies = [ - "serde", - "serde_json", - "serde_with", - "soroban-env-common", - "soroban-env-host", - "thiserror", -] - [[package]] name = "soroban-sdk" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff18e8d7ca6d5340a211605ca2c86383bd4dfacc4f8253d72a1573974ffffe69" +checksum = "6c3f21971c84fcfb08957e3e8f5a9a70f134cb07ad9ee053ac7e6d7a887a82af" dependencies = [ "bytes-lit", + "crate-git-revision 0.0.9", "rand", "rustc_version", "serde", "serde_json", "soroban-env-guest", "soroban-env-host", - "soroban-ledger-snapshot", "soroban-sdk-macros", - "stellar-strkey", + "stellar-strkey 0.0.16", + "visibility", ] [[package]] name = "soroban-sdk-macros" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42b205cd86b34d530db87667bd287fbb194166d79b368227fd842110a914fde8" +checksum = "3bd4a847273d749807fe2eb52e2b9c1917ee482cd6a39465cad5c389548996ad" dependencies = [ - "crate-git-revision", "darling 0.20.11", + "heck", "itertools", + "macro-string", "proc-macro2", "quote", - "rustc_version", "sha2", "soroban-env-common", "soroban-spec", @@ -1318,11 +1426,12 @@ dependencies = [ [[package]] name = "soroban-spec" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6a16f2de28852c759f4da5f28cda54ec0d8dfa4c0e6e8cb3495234a72b0cea" +checksum = "473404322827b285cbcd87517f365986bd63af7842c78b2a86ee061715fda61e" dependencies = [ - "base64 0.13.1", + "base64", + "sha2", "stellar-xdr", "thiserror", "wasmparser", @@ -1330,9 +1439,9 @@ dependencies = [ [[package]] name = "soroban-spec-rust" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6db5902ab21290dddf63fec4ee95703fe59891a947646e7b8607536f043fc" +checksum = "2f25698b6ce2125850a9ef075cf9ba1e8d25b4cfa0c46aca42dadd80cc29d881" dependencies = [ "prettyplease", "proc-macro2", @@ -1373,6 +1482,12 @@ dependencies = [ "der", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + [[package]] name = "static_assertions" version = "1.1.0" @@ -1381,28 +1496,41 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "stellar-strkey" -version = "0.0.9" +version = "0.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e3aa3ed00e70082cb43febc1c2afa5056b9bb3e348bbb43d0cd0aa88a611144" +checksum = "ee1832fb50c651ad10f734aaf5d31ca5acdfb197a6ecda64d93fcdb8885af913" dependencies = [ - "crate-git-revision", + "crate-git-revision 0.0.6", "data-encoding", - "thiserror", +] + +[[package]] +name = "stellar-strkey" +version = "0.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084afcb0d458c3d5d5baa2d294b18f881e62cc258ef539d8fdf68be7dbe45520" +dependencies = [ + "crate-git-revision 0.0.6", + "data-encoding", + "heapless", ] [[package]] name = "stellar-xdr" -version = "22.1.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ce69db907e64d1e70a3dce8d4824655d154749426a6132b25395c49136013e4" +checksum = "05ff843326969bdf1ef673dcdba94c08f4a3c8f1e58d6e6ef39b1bd4f749179a" dependencies = [ - "base64 0.13.1", - "crate-git-revision", + "base64", + "cfg_eval", + "crate-git-revision 0.0.6", "escape-bytes", + "ethnum", "hex", "serde", "serde_with", - "stellar-strkey", + "sha2", + "stellar-strkey 0.0.13", ] [[package]] @@ -1419,9 +1547,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "1.0.109" +version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" dependencies = [ "proc-macro2", "quote", @@ -1430,9 +1558,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.118" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" dependencies = [ "proc-macro2", "quote", @@ -1522,6 +1650,17 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "visibility" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" diff --git a/examples/adder/Cargo.toml b/examples/adder/Cargo.toml index 9d80e72..09f65f1 100644 --- a/examples/adder/Cargo.toml +++ b/examples/adder/Cargo.toml @@ -8,7 +8,7 @@ publish = false crate-type = ["cdylib"] [dependencies] -soroban-sdk = "22.0.0" +soroban-sdk = "27.0.6" [profile.release] opt-level = "z" diff --git a/examples/control/Cargo.lock b/examples/control/Cargo.lock index 6507c7b..a642b57 100644 --- a/examples/control/Cargo.lock +++ b/examples/control/Cargo.lock @@ -14,6 +14,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -25,9 +31,9 @@ dependencies = [ [[package]] name = "ark-bls12-381" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +checksum = "3df4dcc01ff89867cd86b0da835f23c3f02738353aaee7dde7495af71363b8d5" dependencies = [ "ark-ec", "ark-ff", @@ -35,112 +41,136 @@ dependencies = [ "ark-std", ] +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + [[package]] name = "ark-ec" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" dependencies = [ + "ahash", "ark-ff", "ark-poly", "ark-serialize", "ark-std", - "derivative", - "hashbrown 0.13.2", + "educe", + "fnv", + "hashbrown 0.15.5", "itertools", + "num-bigint", + "num-integer", "num-traits", "zeroize", ] [[package]] name = "ark-ff" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" dependencies = [ "ark-ff-asm", "ark-ff-macros", "ark-serialize", "ark-std", - "derivative", + "arrayvec", "digest 0.10.7", + "educe", "itertools", "num-bigint", "num-traits", "paste", - "rustc_version", "zeroize", ] [[package]] name = "ark-ff-asm" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 1.0.109", + "syn 2.0.118", ] [[package]] name = "ark-ff-macros" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" dependencies = [ "num-bigint", "num-traits", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.118", ] [[package]] name = "ark-poly" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" dependencies = [ + "ahash", "ark-ff", "ark-serialize", "ark-std", - "derivative", - "hashbrown 0.13.2", + "educe", + "fnv", + "hashbrown 0.15.5", ] [[package]] name = "ark-serialize" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" dependencies = [ "ark-serialize-derive", "ark-std", + "arrayvec", "digest 0.10.7", "num-bigint", ] [[package]] name = "ark-serialize-derive" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.118", ] [[package]] name = "ark-std" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" dependencies = [ "num-traits", "rand", ] +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + [[package]] name = "autocfg" version = "1.5.1" @@ -155,15 +185,15 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" -version = "0.13.1" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] -name = "base64" -version = "0.22.1" +name = "base64ct" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "block-buffer" @@ -198,11 +228,17 @@ version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes-lit" -version = "0.0.5" +version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0adabf37211a5276e46335feabcbb1530c95eb3fdf85f324c7db942770aa025d" +checksum = "9b04f2b1d34cb428043f14aa4c853d14294532e8bbde3b6a3bc2faaaae31a1dd" dependencies = [ "num-bigint", "proc-macro2", @@ -226,6 +262,17 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_eval" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "chrono" version = "0.4.45" @@ -286,6 +333,17 @@ dependencies = [ "serde_json", ] +[[package]] +name = "crate-git-revision" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54851b5b3f24621804b1cded2820975623c205e3055d2d44031cdb1237339ac8" +dependencies = [ + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -293,7 +351,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "subtle", "zeroize", ] @@ -315,7 +373,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" dependencies = [ "hybrid-array", - "rand_core 0.10.1", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto 0.2.9", + "rustc_version", + "subtle", + "zeroize", ] [[package]] @@ -328,11 +401,9 @@ dependencies = [ "cpufeatures 0.3.0", "curve25519-dalek-derive", "digest 0.11.3", - "fiat-crypto", - "rand_core 0.10.1", + "fiat-crypto 0.3.0", "rustc_version", "subtle", - "zeroize", ] [[package]] @@ -440,17 +511,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "digest" version = "0.10.7" @@ -495,33 +555,46 @@ dependencies = [ "digest 0.10.7", "elliptic-curve", "rfc6979", - "signature 2.2.0", + "signature", ] [[package]] name = "ed25519" -version = "3.0.0" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29fcf32e6c73d1079f83ab4d782de2d81620346a5f38c6237a86a22f8368980a" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ - "signature 3.0.0", + "pkcs8", + "signature", ] [[package]] name = "ed25519-dalek" -version = "3.0.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ebaa1a2bf1290ab3bfe5a7b771d050ebffab2711c19a81691c683a5144a25de" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 4.1.3", "ed25519", - "rand_core 0.10.1", - "sha2 0.11.0", - "signature 3.0.0", + "rand_core", + "serde", + "sha2", "subtle", "zeroize", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "either" version = "1.16.0" @@ -540,12 +613,32 @@ dependencies = [ "ff", "generic-array", "group", - "rand_core 0.6.4", + "rand_core", "sec1", "subtle", "zeroize", ] +[[package]] +name = "enum-ordinalize" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89dd01549b09589510cf0647475075d12071456586d70f5c75c98ae2a5537677" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65863d15a4ce2888bd2f0f543cc963d3879c3a022c8ee43f6141d479a3ac815" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -570,10 +663,16 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ - "rand_core 0.6.4", + "rand_core", "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "fiat-crypto" version = "0.3.0" @@ -647,10 +746,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core 0.6.4", + "rand_core", "subtle", ] +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -659,11 +767,11 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "ahash", + "allocator-api2", ] [[package]] @@ -672,6 +780,22 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hex" version = "0.4.3" @@ -766,9 +890,9 @@ checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" [[package]] name = "itertools" -version = "0.10.5" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] @@ -799,7 +923,7 @@ dependencies = [ "cfg-if", "ecdsa", "elliptic-curve", - "sha2 0.10.9", + "sha2", ] [[package]] @@ -829,6 +953,17 @@ version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" +[[package]] +name = "macro-string" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "memchr" version = "2.8.3" @@ -895,7 +1030,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2 0.10.9", + "sha2", ] [[package]] @@ -910,6 +1045,16 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -970,7 +1115,7 @@ checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", "rand_chacha", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -980,7 +1125,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -992,12 +1137,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_core" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" - [[package]] name = "ref-cast" version = "1.0.25" @@ -1043,6 +1182,17 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "serde", + "serde_json", +] + [[package]] name = "schemars" version = "0.9.0" @@ -1135,12 +1285,13 @@ version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" dependencies = [ - "base64 0.22.1", + "base64", "bs58", "chrono", "hex", "indexmap 1.9.3", "indexmap 2.14.0", + "schemars 0.8.22", "schemars 0.9.0", "schemars 1.2.1", "serde_core", @@ -1172,17 +1323,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "sha2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", - "digest 0.11.3", -] - [[package]] name = "sha3" version = "0.10.9" @@ -1206,16 +1346,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest 0.10.7", - "rand_core 0.6.4", -] - -[[package]] -name = "signature" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5" -dependencies = [ - "rand_core 0.10.1", + "rand_core", ] [[package]] @@ -1232,9 +1363,9 @@ checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] name = "soroban-builtin-sdk-macros" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2e42bf80fcdefb3aae6ff3c7101a62cf942e95320ed5b518a1705bc11c6b2f" +checksum = "b77bc93d930032c487cb1506b6ed166b2af49db76d52678ec4887ac621ecce01" dependencies = [ "itertools", "proc-macro2", @@ -1244,15 +1375,14 @@ dependencies = [ [[package]] name = "soroban-env-common" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "027cd856171bfd6ad2c0ffb3b7dfe55ad7080fb3050c36ad20970f80da634472" +checksum = "6b22e9981cdd444f3aa6734bc58d76195bf7eca3ccf1dd432b875af5d02da068" dependencies = [ - "crate-git-revision", + "crate-git-revision 0.0.6", "ethnum", "num-derive", "num-traits", - "serde", "soroban-env-macros", "soroban-wasmi", "static_assertions", @@ -1262,9 +1392,9 @@ dependencies = [ [[package]] name = "soroban-env-guest" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a07dda1ae5220d975979b19ad4fd56bc86ec7ec1b4b25bc1c5d403f934e592e" +checksum = "2b6072f99ca6bf8e8d5b04e05d083dac785e5357d9c0f36a6658f819c2fd7d67" dependencies = [ "soroban-env-common", "static_assertions", @@ -1272,15 +1402,16 @@ dependencies = [ [[package]] name = "soroban-env-host" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66e8b03a4191d485eab03f066336112b2a50541a7553179553dc838b986b94dd" +checksum = "2c06afd7c75ce150ce53e4d77a77645b18e3fb61856a0ddc42bfcecdc39fa3b9" dependencies = [ "ark-bls12-381", + "ark-bn254", "ark-ec", "ark-ff", "ark-serialize", - "curve25519-dalek", + "curve25519-dalek 5.0.0", "ecdsa", "ed25519-dalek", "elliptic-curve", @@ -1296,21 +1427,21 @@ dependencies = [ "rand", "rand_chacha", "sec1", - "sha2 0.10.9", + "sha2", "sha3", "soroban-builtin-sdk-macros", "soroban-env-common", "soroban-wasmi", "static_assertions", - "stellar-strkey", + "stellar-strkey 0.0.13", "wasmparser", ] [[package]] name = "soroban-env-macros" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00eff744764ade3bc480e4909e3a581a240091f3d262acdce80b41f7069b2bd9" +checksum = "647811bdd28a3ec40296987f6635781e5e1141c8f5affbbd53ba12b6295b7bb6" dependencies = [ "itertools", "proc-macro2", @@ -1321,51 +1452,38 @@ dependencies = [ "syn 2.0.118", ] -[[package]] -name = "soroban-ledger-snapshot" -version = "22.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c30035cf1e8f02f65de3e594b6da113ecdaf1cd134d8480961d62568bb15adaf" -dependencies = [ - "serde", - "serde_json", - "serde_with", - "soroban-env-common", - "soroban-env-host", - "thiserror", -] - [[package]] name = "soroban-sdk" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff18e8d7ca6d5340a211605ca2c86383bd4dfacc4f8253d72a1573974ffffe69" +checksum = "6c3f21971c84fcfb08957e3e8f5a9a70f134cb07ad9ee053ac7e6d7a887a82af" dependencies = [ "bytes-lit", + "crate-git-revision 0.0.9", "rand", "rustc_version", "serde", "serde_json", "soroban-env-guest", "soroban-env-host", - "soroban-ledger-snapshot", "soroban-sdk-macros", - "stellar-strkey", + "stellar-strkey 0.0.16", + "visibility", ] [[package]] name = "soroban-sdk-macros" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42b205cd86b34d530db87667bd287fbb194166d79b368227fd842110a914fde8" +checksum = "3bd4a847273d749807fe2eb52e2b9c1917ee482cd6a39465cad5c389548996ad" dependencies = [ - "crate-git-revision", "darling 0.20.11", + "heck", "itertools", + "macro-string", "proc-macro2", "quote", - "rustc_version", - "sha2 0.10.9", + "sha2", "soroban-env-common", "soroban-spec", "soroban-spec-rust", @@ -1375,11 +1493,12 @@ dependencies = [ [[package]] name = "soroban-spec" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6a16f2de28852c759f4da5f28cda54ec0d8dfa4c0e6e8cb3495234a72b0cea" +checksum = "473404322827b285cbcd87517f365986bd63af7842c78b2a86ee061715fda61e" dependencies = [ - "base64 0.13.1", + "base64", + "sha2", "stellar-xdr", "thiserror", "wasmparser", @@ -1387,14 +1506,14 @@ dependencies = [ [[package]] name = "soroban-spec-rust" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6db5902ab21290dddf63fec4ee95703fe59891a947646e7b8607536f043fc" +checksum = "2f25698b6ce2125850a9ef075cf9ba1e8d25b4cfa0c46aca42dadd80cc29d881" dependencies = [ "prettyplease", "proc-macro2", "quote", - "sha2 0.10.9", + "sha2", "soroban-spec", "stellar-xdr", "syn 2.0.118", @@ -1420,6 +1539,22 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + [[package]] name = "static_assertions" version = "1.1.0" @@ -1428,28 +1563,41 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "stellar-strkey" -version = "0.0.9" +version = "0.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e3aa3ed00e70082cb43febc1c2afa5056b9bb3e348bbb43d0cd0aa88a611144" +checksum = "ee1832fb50c651ad10f734aaf5d31ca5acdfb197a6ecda64d93fcdb8885af913" dependencies = [ - "crate-git-revision", + "crate-git-revision 0.0.6", "data-encoding", - "thiserror", +] + +[[package]] +name = "stellar-strkey" +version = "0.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084afcb0d458c3d5d5baa2d294b18f881e62cc258ef539d8fdf68be7dbe45520" +dependencies = [ + "crate-git-revision 0.0.6", + "data-encoding", + "heapless", ] [[package]] name = "stellar-xdr" -version = "22.1.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ce69db907e64d1e70a3dce8d4824655d154749426a6132b25395c49136013e4" +checksum = "05ff843326969bdf1ef673dcdba94c08f4a3c8f1e58d6e6ef39b1bd4f749179a" dependencies = [ - "base64 0.13.1", - "crate-git-revision", + "base64", + "cfg_eval", + "crate-git-revision 0.0.6", "escape-bytes", + "ethnum", "hex", "serde", "serde_with", - "stellar-strkey", + "sha2", + "stellar-strkey 0.0.13", ] [[package]] @@ -1466,9 +1614,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "1.0.109" +version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" dependencies = [ "proc-macro2", "quote", @@ -1477,9 +1625,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.118" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" dependencies = [ "proc-macro2", "quote", @@ -1569,6 +1717,17 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "visibility" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" diff --git a/examples/control/Cargo.toml b/examples/control/Cargo.toml index 5d3225c..7e59e35 100644 --- a/examples/control/Cargo.toml +++ b/examples/control/Cargo.toml @@ -8,7 +8,7 @@ publish = false crate-type = ["cdylib"] [dependencies] -soroban-sdk = "22.0.0" +soroban-sdk = "27.0.6" # Mirrors the other examples' production profile. The debugger builds this with # CARGO_PROFILE_RELEASE_OPT_LEVEL=0 injected (see ContractBuilder), which is what diff --git a/examples/greeter/Cargo.lock b/examples/greeter/Cargo.lock index 5a449f8..4282a12 100644 --- a/examples/greeter/Cargo.lock +++ b/examples/greeter/Cargo.lock @@ -14,6 +14,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -25,9 +31,9 @@ dependencies = [ [[package]] name = "ark-bls12-381" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +checksum = "3df4dcc01ff89867cd86b0da835f23c3f02738353aaee7dde7495af71363b8d5" dependencies = [ "ark-ec", "ark-ff", @@ -35,112 +41,136 @@ dependencies = [ "ark-std", ] +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + [[package]] name = "ark-ec" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" dependencies = [ + "ahash", "ark-ff", "ark-poly", "ark-serialize", "ark-std", - "derivative", - "hashbrown 0.13.2", + "educe", + "fnv", + "hashbrown 0.15.5", "itertools", + "num-bigint", + "num-integer", "num-traits", "zeroize", ] [[package]] name = "ark-ff" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" dependencies = [ "ark-ff-asm", "ark-ff-macros", "ark-serialize", "ark-std", - "derivative", + "arrayvec", "digest", + "educe", "itertools", "num-bigint", "num-traits", "paste", - "rustc_version", "zeroize", ] [[package]] name = "ark-ff-asm" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 1.0.109", + "syn 2.0.118", ] [[package]] name = "ark-ff-macros" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" dependencies = [ "num-bigint", "num-traits", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.118", ] [[package]] name = "ark-poly" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" dependencies = [ + "ahash", "ark-ff", "ark-serialize", "ark-std", - "derivative", - "hashbrown 0.13.2", + "educe", + "fnv", + "hashbrown 0.15.5", ] [[package]] name = "ark-serialize" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" dependencies = [ "ark-serialize-derive", "ark-std", + "arrayvec", "digest", "num-bigint", ] [[package]] name = "ark-serialize-derive" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.118", ] [[package]] name = "ark-std" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" dependencies = [ "num-traits", "rand", ] +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + [[package]] name = "autocfg" version = "1.5.1" @@ -153,12 +183,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.22.1" @@ -195,11 +219,17 @@ version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes-lit" -version = "0.0.5" +version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0adabf37211a5276e46335feabcbb1530c95eb3fdf85f324c7db942770aa025d" +checksum = "9b04f2b1d34cb428043f14aa4c853d14294532e8bbde3b6a3bc2faaaae31a1dd" dependencies = [ "num-bigint", "proc-macro2", @@ -223,6 +253,17 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_eval" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "chrono" version = "0.4.45" @@ -267,6 +308,17 @@ dependencies = [ "serde_json", ] +[[package]] +name = "crate-git-revision" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54851b5b3f24621804b1cded2820975623c205e3055d2d44031cdb1237339ac8" +dependencies = [ + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -410,17 +462,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "digest" version = "0.10.7" @@ -483,6 +524,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "either" version = "1.16.0" @@ -507,6 +560,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "enum-ordinalize" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89dd01549b09589510cf0647475075d12071456586d70f5c75c98ae2a5537677" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65863d15a4ce2888bd2f0f543cc963d3879c3a022c8ee43f6141d479a3ac815" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -619,6 +692,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -627,11 +709,11 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "ahash", + "allocator-api2", ] [[package]] @@ -640,6 +722,22 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hex" version = "0.4.3" @@ -725,9 +823,9 @@ checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" [[package]] name = "itertools" -version = "0.10.5" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] @@ -788,6 +886,17 @@ version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" +[[package]] +name = "macro-string" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "memchr" version = "2.8.2" @@ -1006,6 +1115,17 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "serde", + "serde_json", +] + [[package]] name = "schemars" version = "0.9.0" @@ -1098,12 +1218,13 @@ version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" dependencies = [ - "base64 0.22.1", + "base64", "bs58", "chrono", "hex", "indexmap 1.9.3", "indexmap 2.14.0", + "schemars 0.8.22", "schemars 0.9.0", "schemars 1.2.1", "serde_core", @@ -1175,9 +1296,9 @@ checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] name = "soroban-builtin-sdk-macros" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2e42bf80fcdefb3aae6ff3c7101a62cf942e95320ed5b518a1705bc11c6b2f" +checksum = "b77bc93d930032c487cb1506b6ed166b2af49db76d52678ec4887ac621ecce01" dependencies = [ "itertools", "proc-macro2", @@ -1187,15 +1308,14 @@ dependencies = [ [[package]] name = "soroban-env-common" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "027cd856171bfd6ad2c0ffb3b7dfe55ad7080fb3050c36ad20970f80da634472" +checksum = "6b22e9981cdd444f3aa6734bc58d76195bf7eca3ccf1dd432b875af5d02da068" dependencies = [ - "crate-git-revision", + "crate-git-revision 0.0.6", "ethnum", "num-derive", "num-traits", - "serde", "soroban-env-macros", "soroban-wasmi", "static_assertions", @@ -1205,9 +1325,9 @@ dependencies = [ [[package]] name = "soroban-env-guest" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a07dda1ae5220d975979b19ad4fd56bc86ec7ec1b4b25bc1c5d403f934e592e" +checksum = "2b6072f99ca6bf8e8d5b04e05d083dac785e5357d9c0f36a6658f819c2fd7d67" dependencies = [ "soroban-env-common", "static_assertions", @@ -1215,11 +1335,12 @@ dependencies = [ [[package]] name = "soroban-env-host" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66e8b03a4191d485eab03f066336112b2a50541a7553179553dc838b986b94dd" +checksum = "2c06afd7c75ce150ce53e4d77a77645b18e3fb61856a0ddc42bfcecdc39fa3b9" dependencies = [ "ark-bls12-381", + "ark-bn254", "ark-ec", "ark-ff", "ark-serialize", @@ -1245,15 +1366,15 @@ dependencies = [ "soroban-env-common", "soroban-wasmi", "static_assertions", - "stellar-strkey", + "stellar-strkey 0.0.13", "wasmparser", ] [[package]] name = "soroban-env-macros" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00eff744764ade3bc480e4909e3a581a240091f3d262acdce80b41f7069b2bd9" +checksum = "647811bdd28a3ec40296987f6635781e5e1141c8f5affbbd53ba12b6295b7bb6" dependencies = [ "itertools", "proc-macro2", @@ -1264,50 +1385,37 @@ dependencies = [ "syn 2.0.118", ] -[[package]] -name = "soroban-ledger-snapshot" -version = "22.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c30035cf1e8f02f65de3e594b6da113ecdaf1cd134d8480961d62568bb15adaf" -dependencies = [ - "serde", - "serde_json", - "serde_with", - "soroban-env-common", - "soroban-env-host", - "thiserror", -] - [[package]] name = "soroban-sdk" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff18e8d7ca6d5340a211605ca2c86383bd4dfacc4f8253d72a1573974ffffe69" +checksum = "6c3f21971c84fcfb08957e3e8f5a9a70f134cb07ad9ee053ac7e6d7a887a82af" dependencies = [ "bytes-lit", + "crate-git-revision 0.0.9", "rand", "rustc_version", "serde", "serde_json", "soroban-env-guest", "soroban-env-host", - "soroban-ledger-snapshot", "soroban-sdk-macros", - "stellar-strkey", + "stellar-strkey 0.0.16", + "visibility", ] [[package]] name = "soroban-sdk-macros" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42b205cd86b34d530db87667bd287fbb194166d79b368227fd842110a914fde8" +checksum = "3bd4a847273d749807fe2eb52e2b9c1917ee482cd6a39465cad5c389548996ad" dependencies = [ - "crate-git-revision", "darling 0.20.11", + "heck", "itertools", + "macro-string", "proc-macro2", "quote", - "rustc_version", "sha2", "soroban-env-common", "soroban-spec", @@ -1318,11 +1426,12 @@ dependencies = [ [[package]] name = "soroban-spec" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6a16f2de28852c759f4da5f28cda54ec0d8dfa4c0e6e8cb3495234a72b0cea" +checksum = "473404322827b285cbcd87517f365986bd63af7842c78b2a86ee061715fda61e" dependencies = [ - "base64 0.13.1", + "base64", + "sha2", "stellar-xdr", "thiserror", "wasmparser", @@ -1330,9 +1439,9 @@ dependencies = [ [[package]] name = "soroban-spec-rust" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6db5902ab21290dddf63fec4ee95703fe59891a947646e7b8607536f043fc" +checksum = "2f25698b6ce2125850a9ef075cf9ba1e8d25b4cfa0c46aca42dadd80cc29d881" dependencies = [ "prettyplease", "proc-macro2", @@ -1373,6 +1482,12 @@ dependencies = [ "der", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + [[package]] name = "static_assertions" version = "1.1.0" @@ -1381,28 +1496,41 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "stellar-strkey" -version = "0.0.9" +version = "0.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e3aa3ed00e70082cb43febc1c2afa5056b9bb3e348bbb43d0cd0aa88a611144" +checksum = "ee1832fb50c651ad10f734aaf5d31ca5acdfb197a6ecda64d93fcdb8885af913" dependencies = [ - "crate-git-revision", + "crate-git-revision 0.0.6", "data-encoding", - "thiserror", +] + +[[package]] +name = "stellar-strkey" +version = "0.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084afcb0d458c3d5d5baa2d294b18f881e62cc258ef539d8fdf68be7dbe45520" +dependencies = [ + "crate-git-revision 0.0.6", + "data-encoding", + "heapless", ] [[package]] name = "stellar-xdr" -version = "22.1.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ce69db907e64d1e70a3dce8d4824655d154749426a6132b25395c49136013e4" +checksum = "05ff843326969bdf1ef673dcdba94c08f4a3c8f1e58d6e6ef39b1bd4f749179a" dependencies = [ - "base64 0.13.1", - "crate-git-revision", + "base64", + "cfg_eval", + "crate-git-revision 0.0.6", "escape-bytes", + "ethnum", "hex", "serde", "serde_with", - "stellar-strkey", + "sha2", + "stellar-strkey 0.0.13", ] [[package]] @@ -1419,9 +1547,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "1.0.109" +version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" dependencies = [ "proc-macro2", "quote", @@ -1430,9 +1558,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.118" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" dependencies = [ "proc-macro2", "quote", @@ -1522,6 +1650,17 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "visibility" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" diff --git a/examples/greeter/Cargo.toml b/examples/greeter/Cargo.toml index d6c9da6..4b8f4d2 100644 --- a/examples/greeter/Cargo.toml +++ b/examples/greeter/Cargo.toml @@ -8,7 +8,7 @@ publish = false crate-type = ["cdylib"] [dependencies] -soroban-sdk = "22.0.0" +soroban-sdk = "27.0.6" [profile.release] opt-level = "z" diff --git a/examples/increment/Cargo.lock b/examples/increment/Cargo.lock index 4863661..5bb8c24 100644 --- a/examples/increment/Cargo.lock +++ b/examples/increment/Cargo.lock @@ -14,6 +14,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -25,9 +31,9 @@ dependencies = [ [[package]] name = "ark-bls12-381" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +checksum = "3df4dcc01ff89867cd86b0da835f23c3f02738353aaee7dde7495af71363b8d5" dependencies = [ "ark-ec", "ark-ff", @@ -35,112 +41,136 @@ dependencies = [ "ark-std", ] +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + [[package]] name = "ark-ec" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" dependencies = [ + "ahash", "ark-ff", "ark-poly", "ark-serialize", "ark-std", - "derivative", - "hashbrown 0.13.2", + "educe", + "fnv", + "hashbrown 0.15.5", "itertools", + "num-bigint", + "num-integer", "num-traits", "zeroize", ] [[package]] name = "ark-ff" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" dependencies = [ "ark-ff-asm", "ark-ff-macros", "ark-serialize", "ark-std", - "derivative", + "arrayvec", "digest", + "educe", "itertools", "num-bigint", "num-traits", "paste", - "rustc_version", "zeroize", ] [[package]] name = "ark-ff-asm" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 1.0.109", + "syn 2.0.118", ] [[package]] name = "ark-ff-macros" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" dependencies = [ "num-bigint", "num-traits", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.118", ] [[package]] name = "ark-poly" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" dependencies = [ + "ahash", "ark-ff", "ark-serialize", "ark-std", - "derivative", - "hashbrown 0.13.2", + "educe", + "fnv", + "hashbrown 0.15.5", ] [[package]] name = "ark-serialize" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" dependencies = [ "ark-serialize-derive", "ark-std", + "arrayvec", "digest", "num-bigint", ] [[package]] name = "ark-serialize-derive" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.118", ] [[package]] name = "ark-std" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" dependencies = [ "num-traits", "rand", ] +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + [[package]] name = "autocfg" version = "1.5.1" @@ -153,12 +183,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.22.1" @@ -195,11 +219,17 @@ version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes-lit" -version = "0.0.5" +version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0adabf37211a5276e46335feabcbb1530c95eb3fdf85f324c7db942770aa025d" +checksum = "9b04f2b1d34cb428043f14aa4c853d14294532e8bbde3b6a3bc2faaaae31a1dd" dependencies = [ "num-bigint", "proc-macro2", @@ -223,6 +253,17 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_eval" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "chrono" version = "0.4.45" @@ -267,6 +308,17 @@ dependencies = [ "serde_json", ] +[[package]] +name = "crate-git-revision" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54851b5b3f24621804b1cded2820975623c205e3055d2d44031cdb1237339ac8" +dependencies = [ + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -410,17 +462,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "digest" version = "0.10.7" @@ -483,6 +524,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "either" version = "1.16.0" @@ -507,6 +560,26 @@ dependencies = [ "zeroize", ] +[[package]] +name = "enum-ordinalize" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89dd01549b09589510cf0647475075d12071456586d70f5c75c98ae2a5537677" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65863d15a4ce2888bd2f0f543cc963d3879c3a022c8ee43f6141d479a3ac815" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -612,6 +685,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -620,11 +702,11 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "ahash", + "allocator-api2", ] [[package]] @@ -633,6 +715,22 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hex" version = "0.4.3" @@ -725,9 +823,9 @@ checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" [[package]] name = "itertools" -version = "0.10.5" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] @@ -788,6 +886,17 @@ version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" +[[package]] +name = "macro-string" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "memchr" version = "2.8.2" @@ -1006,6 +1115,17 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "serde", + "serde_json", +] + [[package]] name = "schemars" version = "0.9.0" @@ -1098,12 +1218,13 @@ version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" dependencies = [ - "base64 0.22.1", + "base64", "bs58", "chrono", "hex", "indexmap 1.9.3", "indexmap 2.14.0", + "schemars 0.8.22", "schemars 0.9.0", "schemars 1.2.1", "serde_core", @@ -1175,9 +1296,9 @@ checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] name = "soroban-builtin-sdk-macros" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2e42bf80fcdefb3aae6ff3c7101a62cf942e95320ed5b518a1705bc11c6b2f" +checksum = "b77bc93d930032c487cb1506b6ed166b2af49db76d52678ec4887ac621ecce01" dependencies = [ "itertools", "proc-macro2", @@ -1187,15 +1308,14 @@ dependencies = [ [[package]] name = "soroban-env-common" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "027cd856171bfd6ad2c0ffb3b7dfe55ad7080fb3050c36ad20970f80da634472" +checksum = "6b22e9981cdd444f3aa6734bc58d76195bf7eca3ccf1dd432b875af5d02da068" dependencies = [ - "crate-git-revision", + "crate-git-revision 0.0.6", "ethnum", "num-derive", "num-traits", - "serde", "soroban-env-macros", "soroban-wasmi", "static_assertions", @@ -1205,9 +1325,9 @@ dependencies = [ [[package]] name = "soroban-env-guest" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a07dda1ae5220d975979b19ad4fd56bc86ec7ec1b4b25bc1c5d403f934e592e" +checksum = "2b6072f99ca6bf8e8d5b04e05d083dac785e5357d9c0f36a6658f819c2fd7d67" dependencies = [ "soroban-env-common", "static_assertions", @@ -1215,11 +1335,12 @@ dependencies = [ [[package]] name = "soroban-env-host" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66e8b03a4191d485eab03f066336112b2a50541a7553179553dc838b986b94dd" +checksum = "2c06afd7c75ce150ce53e4d77a77645b18e3fb61856a0ddc42bfcecdc39fa3b9" dependencies = [ "ark-bls12-381", + "ark-bn254", "ark-ec", "ark-ff", "ark-serialize", @@ -1245,15 +1366,15 @@ dependencies = [ "soroban-env-common", "soroban-wasmi", "static_assertions", - "stellar-strkey", + "stellar-strkey 0.0.13", "wasmparser", ] [[package]] name = "soroban-env-macros" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00eff744764ade3bc480e4909e3a581a240091f3d262acdce80b41f7069b2bd9" +checksum = "647811bdd28a3ec40296987f6635781e5e1141c8f5affbbd53ba12b6295b7bb6" dependencies = [ "itertools", "proc-macro2", @@ -1264,50 +1385,37 @@ dependencies = [ "syn 2.0.118", ] -[[package]] -name = "soroban-ledger-snapshot" -version = "22.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c30035cf1e8f02f65de3e594b6da113ecdaf1cd134d8480961d62568bb15adaf" -dependencies = [ - "serde", - "serde_json", - "serde_with", - "soroban-env-common", - "soroban-env-host", - "thiserror", -] - [[package]] name = "soroban-sdk" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff18e8d7ca6d5340a211605ca2c86383bd4dfacc4f8253d72a1573974ffffe69" +checksum = "6c3f21971c84fcfb08957e3e8f5a9a70f134cb07ad9ee053ac7e6d7a887a82af" dependencies = [ "bytes-lit", + "crate-git-revision 0.0.9", "rand", "rustc_version", "serde", "serde_json", "soroban-env-guest", "soroban-env-host", - "soroban-ledger-snapshot", "soroban-sdk-macros", - "stellar-strkey", + "stellar-strkey 0.0.16", + "visibility", ] [[package]] name = "soroban-sdk-macros" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42b205cd86b34d530db87667bd287fbb194166d79b368227fd842110a914fde8" +checksum = "3bd4a847273d749807fe2eb52e2b9c1917ee482cd6a39465cad5c389548996ad" dependencies = [ - "crate-git-revision", "darling 0.20.11", + "heck", "itertools", + "macro-string", "proc-macro2", "quote", - "rustc_version", "sha2", "soroban-env-common", "soroban-spec", @@ -1318,11 +1426,12 @@ dependencies = [ [[package]] name = "soroban-spec" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6a16f2de28852c759f4da5f28cda54ec0d8dfa4c0e6e8cb3495234a72b0cea" +checksum = "473404322827b285cbcd87517f365986bd63af7842c78b2a86ee061715fda61e" dependencies = [ - "base64 0.13.1", + "base64", + "sha2", "stellar-xdr", "thiserror", "wasmparser", @@ -1330,9 +1439,9 @@ dependencies = [ [[package]] name = "soroban-spec-rust" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6db5902ab21290dddf63fec4ee95703fe59891a947646e7b8607536f043fc" +checksum = "2f25698b6ce2125850a9ef075cf9ba1e8d25b4cfa0c46aca42dadd80cc29d881" dependencies = [ "prettyplease", "proc-macro2", @@ -1373,6 +1482,12 @@ dependencies = [ "der", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + [[package]] name = "static_assertions" version = "1.1.0" @@ -1381,28 +1496,41 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "stellar-strkey" -version = "0.0.9" +version = "0.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e3aa3ed00e70082cb43febc1c2afa5056b9bb3e348bbb43d0cd0aa88a611144" +checksum = "ee1832fb50c651ad10f734aaf5d31ca5acdfb197a6ecda64d93fcdb8885af913" dependencies = [ - "crate-git-revision", + "crate-git-revision 0.0.6", "data-encoding", - "thiserror", +] + +[[package]] +name = "stellar-strkey" +version = "0.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084afcb0d458c3d5d5baa2d294b18f881e62cc258ef539d8fdf68be7dbe45520" +dependencies = [ + "crate-git-revision 0.0.6", + "data-encoding", + "heapless", ] [[package]] name = "stellar-xdr" -version = "22.1.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ce69db907e64d1e70a3dce8d4824655d154749426a6132b25395c49136013e4" +checksum = "05ff843326969bdf1ef673dcdba94c08f4a3c8f1e58d6e6ef39b1bd4f749179a" dependencies = [ - "base64 0.13.1", - "crate-git-revision", + "base64", + "cfg_eval", + "crate-git-revision 0.0.6", "escape-bytes", + "ethnum", "hex", "serde", "serde_with", - "stellar-strkey", + "sha2", + "stellar-strkey 0.0.13", ] [[package]] @@ -1419,9 +1547,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "1.0.109" +version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" dependencies = [ "proc-macro2", "quote", @@ -1430,9 +1558,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.118" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" dependencies = [ "proc-macro2", "quote", @@ -1522,6 +1650,17 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "visibility" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" diff --git a/examples/increment/Cargo.toml b/examples/increment/Cargo.toml index 44e544e..99fdc2b 100644 --- a/examples/increment/Cargo.toml +++ b/examples/increment/Cargo.toml @@ -8,7 +8,7 @@ publish = false crate-type = ["cdylib"] [dependencies] -soroban-sdk = "22.0.0" +soroban-sdk = "27.0.6" [profile.release] opt-level = "z" diff --git a/examples/stepper/Cargo.lock b/examples/stepper/Cargo.lock index 0cad8d3..dee2950 100644 --- a/examples/stepper/Cargo.lock +++ b/examples/stepper/Cargo.lock @@ -14,6 +14,12 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -25,9 +31,9 @@ dependencies = [ [[package]] name = "ark-bls12-381" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c775f0d12169cba7aae4caeb547bb6a50781c7449a8aa53793827c9ec4abf488" +checksum = "3df4dcc01ff89867cd86b0da835f23c3f02738353aaee7dde7495af71363b8d5" dependencies = [ "ark-ec", "ark-ff", @@ -35,112 +41,136 @@ dependencies = [ "ark-std", ] +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + [[package]] name = "ark-ec" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" dependencies = [ + "ahash", "ark-ff", "ark-poly", "ark-serialize", "ark-std", - "derivative", - "hashbrown 0.13.2", + "educe", + "fnv", + "hashbrown 0.15.5", "itertools", + "num-bigint", + "num-integer", "num-traits", "zeroize", ] [[package]] name = "ark-ff" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" dependencies = [ "ark-ff-asm", "ark-ff-macros", "ark-serialize", "ark-std", - "derivative", + "arrayvec", "digest 0.10.7", + "educe", "itertools", "num-bigint", "num-traits", "paste", - "rustc_version", "zeroize", ] [[package]] name = "ark-ff-asm" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 1.0.109", + "syn 2.0.118", ] [[package]] name = "ark-ff-macros" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" dependencies = [ "num-bigint", "num-traits", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.118", ] [[package]] name = "ark-poly" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" dependencies = [ + "ahash", "ark-ff", "ark-serialize", "ark-std", - "derivative", - "hashbrown 0.13.2", + "educe", + "fnv", + "hashbrown 0.15.5", ] [[package]] name = "ark-serialize" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" dependencies = [ "ark-serialize-derive", "ark-std", + "arrayvec", "digest 0.10.7", "num-bigint", ] [[package]] name = "ark-serialize-derive" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.118", ] [[package]] name = "ark-std" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" dependencies = [ "num-traits", "rand", ] +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + [[package]] name = "autocfg" version = "1.5.1" @@ -155,15 +185,15 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" -version = "0.13.1" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] -name = "base64" -version = "0.22.1" +name = "base64ct" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "block-buffer" @@ -198,11 +228,17 @@ version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "bytes-lit" -version = "0.0.5" +version = "0.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0adabf37211a5276e46335feabcbb1530c95eb3fdf85f324c7db942770aa025d" +checksum = "9b04f2b1d34cb428043f14aa4c853d14294532e8bbde3b6a3bc2faaaae31a1dd" dependencies = [ "num-bigint", "proc-macro2", @@ -226,6 +262,17 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "cfg_eval" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "chrono" version = "0.4.45" @@ -279,6 +326,17 @@ dependencies = [ "serde_json", ] +[[package]] +name = "crate-git-revision" +version = "0.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54851b5b3f24621804b1cded2820975623c205e3055d2d44031cdb1237339ac8" +dependencies = [ + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -286,7 +344,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core 0.6.4", + "rand_core", "subtle", "zeroize", ] @@ -308,7 +366,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" dependencies = [ "hybrid-array", - "rand_core 0.10.1", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto 0.2.9", + "rustc_version", + "subtle", + "zeroize", ] [[package]] @@ -321,11 +394,9 @@ dependencies = [ "cpufeatures 0.3.0", "curve25519-dalek-derive", "digest 0.11.3", - "fiat-crypto", - "rand_core 0.10.1", + "fiat-crypto 0.3.0", "rustc_version", "subtle", - "zeroize", ] [[package]] @@ -433,17 +504,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "digest" version = "0.10.7" @@ -488,33 +548,46 @@ dependencies = [ "digest 0.10.7", "elliptic-curve", "rfc6979", - "signature 2.2.0", + "signature", ] [[package]] name = "ed25519" -version = "3.0.0" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29fcf32e6c73d1079f83ab4d782de2d81620346a5f38c6237a86a22f8368980a" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ - "signature 3.0.0", + "pkcs8", + "signature", ] [[package]] name = "ed25519-dalek" -version = "3.0.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ebaa1a2bf1290ab3bfe5a7b771d050ebffab2711c19a81691c683a5144a25de" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" dependencies = [ - "curve25519-dalek", + "curve25519-dalek 4.1.3", "ed25519", - "rand_core 0.10.1", - "sha2 0.11.0", - "signature 3.0.0", + "rand_core", + "serde", + "sha2", "subtle", "zeroize", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "either" version = "1.16.0" @@ -533,12 +606,32 @@ dependencies = [ "ff", "generic-array", "group", - "rand_core 0.6.4", + "rand_core", "sec1", "subtle", "zeroize", ] +[[package]] +name = "enum-ordinalize" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89dd01549b09589510cf0647475075d12071456586d70f5c75c98ae2a5537677" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a65863d15a4ce2888bd2f0f543cc963d3879c3a022c8ee43f6141d479a3ac815" +dependencies = [ + "proc-macro2", + "quote", + "syn 3.0.3", +] + [[package]] name = "equivalent" version = "1.0.2" @@ -563,10 +656,16 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" dependencies = [ - "rand_core 0.6.4", + "rand_core", "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "fiat-crypto" version = "0.3.0" @@ -640,10 +739,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core 0.6.4", + "rand_core", "subtle", ] +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.12.3" @@ -652,11 +760,11 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ - "ahash", + "allocator-api2", ] [[package]] @@ -665,6 +773,22 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hex" version = "0.4.3" @@ -759,9 +883,9 @@ checksum = "8e04e2fd2b8188ea827b32ef11de88377086d690286ab35747ef7f9bf3ccb590" [[package]] name = "itertools" -version = "0.10.5" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] @@ -792,7 +916,7 @@ dependencies = [ "cfg-if", "ecdsa", "elliptic-curve", - "sha2 0.10.9", + "sha2", ] [[package]] @@ -822,6 +946,17 @@ version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" +[[package]] +name = "macro-string" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "memchr" version = "2.8.2" @@ -888,7 +1023,7 @@ dependencies = [ "ecdsa", "elliptic-curve", "primeorder", - "sha2 0.10.9", + "sha2", ] [[package]] @@ -903,6 +1038,16 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -963,7 +1108,7 @@ checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" dependencies = [ "libc", "rand_chacha", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -973,7 +1118,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", + "rand_core", ] [[package]] @@ -985,12 +1130,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_core" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" - [[package]] name = "ref-cast" version = "1.0.25" @@ -1036,6 +1175,17 @@ version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" +[[package]] +name = "schemars" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615" +dependencies = [ + "dyn-clone", + "serde", + "serde_json", +] + [[package]] name = "schemars" version = "0.9.0" @@ -1128,12 +1278,13 @@ version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" dependencies = [ - "base64 0.22.1", + "base64", "bs58", "chrono", "hex", "indexmap 1.9.3", "indexmap 2.14.0", + "schemars 0.8.22", "schemars 0.9.0", "schemars 1.2.1", "serde_core", @@ -1165,17 +1316,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "sha2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" -dependencies = [ - "cfg-if", - "cpufeatures 0.3.0", - "digest 0.11.3", -] - [[package]] name = "sha3" version = "0.10.9" @@ -1199,16 +1339,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest 0.10.7", - "rand_core 0.6.4", -] - -[[package]] -name = "signature" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5" -dependencies = [ - "rand_core 0.10.1", + "rand_core", ] [[package]] @@ -1225,9 +1356,9 @@ checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" [[package]] name = "soroban-builtin-sdk-macros" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2e42bf80fcdefb3aae6ff3c7101a62cf942e95320ed5b518a1705bc11c6b2f" +checksum = "b77bc93d930032c487cb1506b6ed166b2af49db76d52678ec4887ac621ecce01" dependencies = [ "itertools", "proc-macro2", @@ -1237,15 +1368,14 @@ dependencies = [ [[package]] name = "soroban-env-common" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "027cd856171bfd6ad2c0ffb3b7dfe55ad7080fb3050c36ad20970f80da634472" +checksum = "6b22e9981cdd444f3aa6734bc58d76195bf7eca3ccf1dd432b875af5d02da068" dependencies = [ - "crate-git-revision", + "crate-git-revision 0.0.6", "ethnum", "num-derive", "num-traits", - "serde", "soroban-env-macros", "soroban-wasmi", "static_assertions", @@ -1255,9 +1385,9 @@ dependencies = [ [[package]] name = "soroban-env-guest" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a07dda1ae5220d975979b19ad4fd56bc86ec7ec1b4b25bc1c5d403f934e592e" +checksum = "2b6072f99ca6bf8e8d5b04e05d083dac785e5357d9c0f36a6658f819c2fd7d67" dependencies = [ "soroban-env-common", "static_assertions", @@ -1265,15 +1395,16 @@ dependencies = [ [[package]] name = "soroban-env-host" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66e8b03a4191d485eab03f066336112b2a50541a7553179553dc838b986b94dd" +checksum = "2c06afd7c75ce150ce53e4d77a77645b18e3fb61856a0ddc42bfcecdc39fa3b9" dependencies = [ "ark-bls12-381", + "ark-bn254", "ark-ec", "ark-ff", "ark-serialize", - "curve25519-dalek", + "curve25519-dalek 5.0.0", "ecdsa", "ed25519-dalek", "elliptic-curve", @@ -1289,21 +1420,21 @@ dependencies = [ "rand", "rand_chacha", "sec1", - "sha2 0.10.9", + "sha2", "sha3", "soroban-builtin-sdk-macros", "soroban-env-common", "soroban-wasmi", "static_assertions", - "stellar-strkey", + "stellar-strkey 0.0.13", "wasmparser", ] [[package]] name = "soroban-env-macros" -version = "22.1.3" +version = "27.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00eff744764ade3bc480e4909e3a581a240091f3d262acdce80b41f7069b2bd9" +checksum = "647811bdd28a3ec40296987f6635781e5e1141c8f5affbbd53ba12b6295b7bb6" dependencies = [ "itertools", "proc-macro2", @@ -1314,51 +1445,38 @@ dependencies = [ "syn 2.0.118", ] -[[package]] -name = "soroban-ledger-snapshot" -version = "22.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c30035cf1e8f02f65de3e594b6da113ecdaf1cd134d8480961d62568bb15adaf" -dependencies = [ - "serde", - "serde_json", - "serde_with", - "soroban-env-common", - "soroban-env-host", - "thiserror", -] - [[package]] name = "soroban-sdk" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff18e8d7ca6d5340a211605ca2c86383bd4dfacc4f8253d72a1573974ffffe69" +checksum = "6c3f21971c84fcfb08957e3e8f5a9a70f134cb07ad9ee053ac7e6d7a887a82af" dependencies = [ "bytes-lit", + "crate-git-revision 0.0.9", "rand", "rustc_version", "serde", "serde_json", "soroban-env-guest", "soroban-env-host", - "soroban-ledger-snapshot", "soroban-sdk-macros", - "stellar-strkey", + "stellar-strkey 0.0.16", + "visibility", ] [[package]] name = "soroban-sdk-macros" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42b205cd86b34d530db87667bd287fbb194166d79b368227fd842110a914fde8" +checksum = "3bd4a847273d749807fe2eb52e2b9c1917ee482cd6a39465cad5c389548996ad" dependencies = [ - "crate-git-revision", "darling 0.20.11", + "heck", "itertools", + "macro-string", "proc-macro2", "quote", - "rustc_version", - "sha2 0.10.9", + "sha2", "soroban-env-common", "soroban-spec", "soroban-spec-rust", @@ -1368,11 +1486,12 @@ dependencies = [ [[package]] name = "soroban-spec" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6a16f2de28852c759f4da5f28cda54ec0d8dfa4c0e6e8cb3495234a72b0cea" +checksum = "473404322827b285cbcd87517f365986bd63af7842c78b2a86ee061715fda61e" dependencies = [ - "base64 0.13.1", + "base64", + "sha2", "stellar-xdr", "thiserror", "wasmparser", @@ -1380,14 +1499,14 @@ dependencies = [ [[package]] name = "soroban-spec-rust" -version = "22.0.11" +version = "27.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6db5902ab21290dddf63fec4ee95703fe59891a947646e7b8607536f043fc" +checksum = "2f25698b6ce2125850a9ef075cf9ba1e8d25b4cfa0c46aca42dadd80cc29d881" dependencies = [ "prettyplease", "proc-macro2", "quote", - "sha2 0.10.9", + "sha2", "soroban-spec", "stellar-xdr", "syn 2.0.118", @@ -1413,6 +1532,22 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + [[package]] name = "static_assertions" version = "1.1.0" @@ -1421,28 +1556,41 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "stellar-strkey" -version = "0.0.9" +version = "0.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e3aa3ed00e70082cb43febc1c2afa5056b9bb3e348bbb43d0cd0aa88a611144" +checksum = "ee1832fb50c651ad10f734aaf5d31ca5acdfb197a6ecda64d93fcdb8885af913" dependencies = [ - "crate-git-revision", + "crate-git-revision 0.0.6", "data-encoding", - "thiserror", +] + +[[package]] +name = "stellar-strkey" +version = "0.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "084afcb0d458c3d5d5baa2d294b18f881e62cc258ef539d8fdf68be7dbe45520" +dependencies = [ + "crate-git-revision 0.0.6", + "data-encoding", + "heapless", ] [[package]] name = "stellar-xdr" -version = "22.1.0" +version = "27.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ce69db907e64d1e70a3dce8d4824655d154749426a6132b25395c49136013e4" +checksum = "05ff843326969bdf1ef673dcdba94c08f4a3c8f1e58d6e6ef39b1bd4f749179a" dependencies = [ - "base64 0.13.1", - "crate-git-revision", + "base64", + "cfg_eval", + "crate-git-revision 0.0.6", "escape-bytes", + "ethnum", "hex", "serde", "serde_with", - "stellar-strkey", + "sha2", + "stellar-strkey 0.0.13", ] [[package]] @@ -1466,9 +1614,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "1.0.109" +version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" dependencies = [ "proc-macro2", "quote", @@ -1477,9 +1625,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.118" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" dependencies = [ "proc-macro2", "quote", @@ -1569,6 +1717,17 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "visibility" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "wasi" version = "0.11.1+wasi-snapshot-preview1" diff --git a/examples/stepper/Cargo.toml b/examples/stepper/Cargo.toml index ba32d47..20fcb90 100644 --- a/examples/stepper/Cargo.toml +++ b/examples/stepper/Cargo.toml @@ -8,7 +8,7 @@ publish = false crate-type = ["cdylib"] [dependencies] -soroban-sdk = "22.0.0" +soroban-sdk = "27.0.6" [profile.release] opt-level = "z" From 19d9e0fd888cd164aaedd6a09a8d12a19b0eb086 Mon Sep 17 00:00:00 2001 From: Raoul Date: Fri, 21 Aug 2026 14:11:27 +0000 Subject: [PATCH 12/13] fix: re-record the bundled example trace It was still in the pre-v0.1.87 shape, so the zero-dependency replay config that examples/README.md offers as a first step failed with the stale-node error. The test fixtures had all been re-recorded; nothing replays this copy, so the suite stayed green. It is the same 41-record run, identical once `kind` is stripped. --- examples/traces/add.trace.jsonl | 82 ++++++++++++++++----------------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/examples/traces/add.trace.jsonl b/examples/traces/add.trace.jsonl index 783e9a6..3c73ec3 100644 --- a/examples/traces/add.trace.jsonl +++ b/examples/traces/add.trace.jsonl @@ -1,41 +1,41 @@ -{"pos":3,"instr":["const","i32",1048576],"stack":[],"locals":{}} -{"pos":11,"instr":["const","i32",1048576],"stack":[],"locals":{}} -{"pos":19,"instr":["const","i32",1048576],"stack":[],"locals":{}} -{"pos":null,"instr":["const","i64",17179869188],"stack":[],"locals":{}} -{"pos":null,"instr":["const","i64",12884901892],"stack":[["i64",17179869188]],"locals":{}} -{"pos":null,"instr":["block"],"stack":[],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":5,"instr":["block"],"stack":[],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":7,"instr":["block"],"stack":[],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":9,"instr":["local.get",0],"stack":[],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":11,"instr":["const","i64",255],"stack":[["i64",17179869188]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":14,"instr":["and","i64"],"stack":[["i64",255],["i64",17179869188]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":15,"instr":["const","i64",4],"stack":[["i64",4]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":17,"instr":["ne","i64"],"stack":[["i64",4],["i64",4]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":18,"instr":["br_if",0],"stack":[["i32",0]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":20,"instr":["local.get",1],"stack":[],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":22,"instr":["const","i64",255],"stack":[["i64",12884901892]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":25,"instr":["and","i64"],"stack":[["i64",255],["i64",12884901892]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":26,"instr":["const","i64",4],"stack":[["i64",4]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":28,"instr":["ne","i64"],"stack":[["i64",4],["i64",4]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":29,"instr":["br_if",0],"stack":[["i32",0]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":31,"instr":["local.get",1],"stack":[],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":33,"instr":["const","i64",32],"stack":[["i64",12884901892]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":35,"instr":["shr_u","i64"],"stack":[["i64",32],["i64",12884901892]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":36,"instr":["wrap_i64","i32"],"stack":[["i64",3]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":37,"instr":["local.tee",2],"stack":[["i32",3]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} -{"pos":39,"instr":["local.get",0],"stack":[["i32",3]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",0]}} -{"pos":41,"instr":["const","i64",32],"stack":[["i64",17179869188],["i32",3]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",0]}} -{"pos":43,"instr":["shr_u","i64"],"stack":[["i64",32],["i64",17179869188],["i32",3]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",0]}} -{"pos":44,"instr":["wrap_i64","i32"],"stack":[["i64",4],["i32",3]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",0]}} -{"pos":45,"instr":["add","i32"],"stack":[["i32",4],["i32",3]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",0]}} -{"pos":46,"instr":["local.tee",3],"stack":[["i32",7]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",0]}} -{"pos":48,"instr":["local.get",2],"stack":[["i32",7]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} -{"pos":50,"instr":["lt_u","i32"],"stack":[["i32",3],["i32",7]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} -{"pos":51,"instr":["br_if",1],"stack":[["i32",0]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} -{"pos":53,"instr":["local.get",3],"stack":[],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} -{"pos":55,"instr":["extend_i32_u","i64"],"stack":[["i32",7]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} -{"pos":56,"instr":["const","i64",32],"stack":[["i64",7]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} -{"pos":58,"instr":["shl","i64"],"stack":[["i64",32],["i64",7]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} -{"pos":59,"instr":["const","i64",4],"stack":[["i64",30064771072]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} -{"pos":61,"instr":["or","i64"],"stack":[["i64",4],["i64",30064771072]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} -{"pos":62,"instr":["return"],"stack":[["i64",30064771076]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} +{"kind":"instr","pos":3,"instr":["const","i32",1048576],"stack":[],"locals":{}} +{"kind":"instr","pos":11,"instr":["const","i32",1048576],"stack":[],"locals":{}} +{"kind":"instr","pos":19,"instr":["const","i32",1048576],"stack":[],"locals":{}} +{"kind":"instr","pos":null,"instr":["const","i64",17179869188],"stack":[],"locals":{}} +{"kind":"instr","pos":null,"instr":["const","i64",12884901892],"stack":[["i64",17179869188]],"locals":{}} +{"kind":"instr","pos":null,"instr":["block"],"stack":[],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":5,"instr":["block"],"stack":[],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":7,"instr":["block"],"stack":[],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":9,"instr":["local.get",0],"stack":[],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":11,"instr":["const","i64",255],"stack":[["i64",17179869188]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":14,"instr":["and","i64"],"stack":[["i64",255],["i64",17179869188]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":15,"instr":["const","i64",4],"stack":[["i64",4]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":17,"instr":["ne","i64"],"stack":[["i64",4],["i64",4]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":18,"instr":["br_if",0],"stack":[["i32",0]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":20,"instr":["local.get",1],"stack":[],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":22,"instr":["const","i64",255],"stack":[["i64",12884901892]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":25,"instr":["and","i64"],"stack":[["i64",255],["i64",12884901892]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":26,"instr":["const","i64",4],"stack":[["i64",4]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":28,"instr":["ne","i64"],"stack":[["i64",4],["i64",4]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":29,"instr":["br_if",0],"stack":[["i32",0]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":31,"instr":["local.get",1],"stack":[],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":33,"instr":["const","i64",32],"stack":[["i64",12884901892]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":35,"instr":["shr_u","i64"],"stack":[["i64",32],["i64",12884901892]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":36,"instr":["wrap_i64","i32"],"stack":[["i64",3]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":37,"instr":["local.tee",2],"stack":[["i32",3]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",0],"3":["i32",0]}} +{"kind":"instr","pos":39,"instr":["local.get",0],"stack":[["i32",3]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",0]}} +{"kind":"instr","pos":41,"instr":["const","i64",32],"stack":[["i64",17179869188],["i32",3]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",0]}} +{"kind":"instr","pos":43,"instr":["shr_u","i64"],"stack":[["i64",32],["i64",17179869188],["i32",3]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",0]}} +{"kind":"instr","pos":44,"instr":["wrap_i64","i32"],"stack":[["i64",4],["i32",3]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",0]}} +{"kind":"instr","pos":45,"instr":["add","i32"],"stack":[["i32",4],["i32",3]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",0]}} +{"kind":"instr","pos":46,"instr":["local.tee",3],"stack":[["i32",7]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",0]}} +{"kind":"instr","pos":48,"instr":["local.get",2],"stack":[["i32",7]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} +{"kind":"instr","pos":50,"instr":["lt_u","i32"],"stack":[["i32",3],["i32",7]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} +{"kind":"instr","pos":51,"instr":["br_if",1],"stack":[["i32",0]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} +{"kind":"instr","pos":53,"instr":["local.get",3],"stack":[],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} +{"kind":"instr","pos":55,"instr":["extend_i32_u","i64"],"stack":[["i32",7]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} +{"kind":"instr","pos":56,"instr":["const","i64",32],"stack":[["i64",7]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} +{"kind":"instr","pos":58,"instr":["shl","i64"],"stack":[["i64",32],["i64",7]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} +{"kind":"instr","pos":59,"instr":["const","i64",4],"stack":[["i64",30064771072]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} +{"kind":"instr","pos":61,"instr":["or","i64"],"stack":[["i64",4],["i64",30064771072]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} +{"kind":"instr","pos":62,"instr":["return"],"stack":[["i64",30064771076]],"locals":{"0":["i64",17179869188],"1":["i64",12884901892],"2":["i32",3],"3":["i32",7]}} From 56290492e14badac165422159445d702161859ea Mon Sep 17 00:00:00 2001 From: Raoul Date: Fri, 21 Aug 2026 14:11:33 +0000 Subject: [PATCH 13/13] docs: say that a recording carries its build machine paths The README offers a recording as a bug report to hand to someone else, but the source paths come from the wasm debug info and are absolute, and nothing remaps them. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ab69c58..1320647 100644 --- a/README.md +++ b/README.md @@ -183,6 +183,7 @@ internally. - **A trace can stop short of the invocation's end.** komet-node's tracer halts at instructions it cannot decode (it reports them as `unknown`), so depending on codegen some contracts replay only partially. The session opens and steps normally; it just ends earlier than the call did. - **Source stepping wants an unoptimized build.** The live pipeline builds with debug info at opt-level 0 for exactly this reason — at higher optimization levels a whole function can collapse onto a single line. See [`docs/stepping.md`](docs/stepping.md). +- **A recording carries the source paths of the machine that built the contract.** They are absolute paths taken from the wasm's debug info, so a trace someone hands you opens its frames at paths that need not exist on your disk: the session still replays, steps and shows variables, but the editor cannot show the source itself unless the files sit where that build left them. - **One transaction per session.** A launch config can run a whole sequence of transactions, but exactly one of them (`trace`) is the one you step through. ## Roadmap