-
Notifications
You must be signed in to change notification settings - Fork 39
Description
The last changes allowed me to remove a lot of hacks, here is how the dax wrapper look now https://github.com/sigmaSd/Chef/blob/f11117c0db46e6eb3e3551ac141d0b0a0268f13e/src/dax_wrapper.ts
I asked gemini if there are other features that could be useful , if these don't sound interesting I can just close the issue, here is the answer:
Context
I currently have to rely on Proxy wrappers and reimplementations of internal logic (like pipeToPath) to integrate dax with my application's state (signals, progress bars, status listeners).
I would like to propose two API additions that would allow wrappers to integrate cleanly with dax without "hacks".
1. Structured Progress Callbacks
Problem: dax's pipeToPath and download progress are tightly coupled to the console/stderr output. To get raw progress numbers (loaded/total bytes) for a GUI progress bar, I currently have to reimplement pipeToPath completely, manually fetching the response and reading the stream.
Proposal: Add an .onProgress() method to RequestBuilder.
await $.request("https://example.com/file.zip")
.onProgress((loaded: number, total: number | undefined) => {
// Allows integrating with external UI systems
myGui.updateProgress(loaded, total);
})
.pipeToPath("file.zip");This would allow users to leverage dax's optimized streaming file writing while still observing the data flow.
2. Global "Middleware" or Lifecycle Hooks
Problem: My application has a dynamic AbortSignal (e.g., a "Cancel" button that resets for each task) and a global status listener (to show "Running..." or "Idle").
Currently, I have to wrap $ in a Proxy to intercept every command and request creation to:
- Inject the current signal dynamically (
.signal(context.getSignal())). - Notify the listener when execution starts and ends.
Proposal: Add support for lifecycle hooks or dynamic configuration in build$.
const $ = dax.build$({
hooks: {
// Called before execution, allowing modification of the builder
beforeCommand: (builder) => {
// Dynamic signal injection
builder.signal(myContext.getSignal());
// Status notification
myContext.notify("running", builder.getText());
},
beforeRequest: (builder) => {
builder.signal(myContext.getSignal());
myContext.notify("running", builder.getUrl());
},
// Called after completion (success or failure)
afterCommand: (result) => {
myContext.notify("idle");
},
afterRequest: (result) => {
myContext.notify("idle");
}
}
});Alternatively, allowing the signal option in build$ to accept a getter function (provider) would solve the specific signal injection issue:
const $ = dax.build$({
// dax calls this provider for every new command/request
signal: () => myContext.currentSignal
});Benefit
These changes would allow developers to build rich CLIs, TUIs, and GUIs on top of dax using its native, robust implementations instead of having to maintain complex wrappers and custom stream handling logic.