@mcp-b/do-runtime 0.2.2 → 0.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/dist/index.js +108 -3
- package/dist/index.js.map +1 -1
- package/dist/src/api/http.d.ts +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- e4b1be6: Close three input-lock laundering paths in HTTP bodies. `ReadableStream` async iteration, second-order `Blob` reads, and reader or stream lifecycle promises could previously resume outside the actor's input gate and make the next storage call throw "no input lock available in this context". They now route every surfaced continuation through the actor's gated I/O seam while preserving native stream cancellation and lock-release behavior.
|
|
8
|
+
|
|
3
9
|
## 0.2.2
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -3685,6 +3685,42 @@ var BODY_CONSUMERS = [
|
|
|
3685
3685
|
"json",
|
|
3686
3686
|
"text"
|
|
3687
3687
|
];
|
|
3688
|
+
/** A consumed Blob is a second-order body: every read it produces needs the same gate. */
|
|
3689
|
+
function gateBlob(ctx, blob) {
|
|
3690
|
+
const arrayBuffer = blob.arrayBuffer.bind(blob);
|
|
3691
|
+
const bytes = blob.bytes.bind(blob);
|
|
3692
|
+
const slice = blob.slice.bind(blob);
|
|
3693
|
+
const stream = blob.stream.bind(blob);
|
|
3694
|
+
const text = blob.text.bind(blob);
|
|
3695
|
+
Object.defineProperties(blob, {
|
|
3696
|
+
arrayBuffer: {
|
|
3697
|
+
configurable: true,
|
|
3698
|
+
writable: true,
|
|
3699
|
+
value: () => ctx.awaitIo(arrayBuffer())
|
|
3700
|
+
},
|
|
3701
|
+
bytes: {
|
|
3702
|
+
configurable: true,
|
|
3703
|
+
writable: true,
|
|
3704
|
+
value: () => ctx.awaitIo(bytes())
|
|
3705
|
+
},
|
|
3706
|
+
slice: {
|
|
3707
|
+
configurable: true,
|
|
3708
|
+
writable: true,
|
|
3709
|
+
value: (start, end, contentType) => gateBlob(ctx, slice(start, end, contentType))
|
|
3710
|
+
},
|
|
3711
|
+
stream: {
|
|
3712
|
+
configurable: true,
|
|
3713
|
+
writable: true,
|
|
3714
|
+
value: () => gateReadableStream(ctx, stream())
|
|
3715
|
+
},
|
|
3716
|
+
text: {
|
|
3717
|
+
configurable: true,
|
|
3718
|
+
writable: true,
|
|
3719
|
+
value: () => ctx.awaitIo(text())
|
|
3720
|
+
}
|
|
3721
|
+
});
|
|
3722
|
+
return blob;
|
|
3723
|
+
}
|
|
3688
3724
|
/**
|
|
3689
3725
|
* Wrap a `Request` or `Response` so every asynchronous step of reading it
|
|
3690
3726
|
* resumes inside a gated slice.
|
|
@@ -3718,7 +3754,10 @@ function gateBody(ctx, value) {
|
|
|
3718
3754
|
return clone;
|
|
3719
3755
|
}
|
|
3720
3756
|
if (BODY_CONSUMERS.includes(property)) {
|
|
3721
|
-
const consume = (...args) =>
|
|
3757
|
+
const consume = (...args) => {
|
|
3758
|
+
const result = subject[property].apply(subject, args);
|
|
3759
|
+
return ctx.awaitIo(result, (value) => property === "blob" ? gateBlob(ctx, value) : value);
|
|
3760
|
+
};
|
|
3722
3761
|
bound.set(property, consume);
|
|
3723
3762
|
return consume;
|
|
3724
3763
|
}
|
|
@@ -3748,11 +3787,45 @@ function gateResponseBody(ctx, response) {
|
|
|
3748
3787
|
*/
|
|
3749
3788
|
var BYOB_READER_UNGATABLE_MESSAGE = "getReader({ mode: 'byob' }): a BYOB reader cannot be gated by this runtime, because `ReadableStream.getReader` is the only seam it has and a byte stream's `read(view)` returns the caller's own buffer. Read the body through `arrayBuffer()` or a default reader.";
|
|
3750
3789
|
function gateReadableStream(ctx, stream) {
|
|
3790
|
+
const cancel = stream.cancel.bind(stream);
|
|
3751
3791
|
const getReader = stream.getReader.bind(stream);
|
|
3752
3792
|
const tee = stream.tee.bind(stream);
|
|
3753
3793
|
const pipeThrough = stream.pipeThrough.bind(stream);
|
|
3754
3794
|
const pipeTo = stream.pipeTo.bind(stream);
|
|
3795
|
+
const values = async function* (options) {
|
|
3796
|
+
const reader = gateReader(ctx, getReader());
|
|
3797
|
+
let finished = false;
|
|
3798
|
+
try {
|
|
3799
|
+
for (;;) {
|
|
3800
|
+
let result;
|
|
3801
|
+
try {
|
|
3802
|
+
result = await reader.read();
|
|
3803
|
+
} catch (exception) {
|
|
3804
|
+
finished = true;
|
|
3805
|
+
throw exception;
|
|
3806
|
+
}
|
|
3807
|
+
if (result.done) {
|
|
3808
|
+
finished = true;
|
|
3809
|
+
return;
|
|
3810
|
+
}
|
|
3811
|
+
yield result.value;
|
|
3812
|
+
}
|
|
3813
|
+
} finally {
|
|
3814
|
+
try {
|
|
3815
|
+
if (!finished && options?.preventCancel !== true) await reader.cancel();
|
|
3816
|
+
} finally {
|
|
3817
|
+
reader.releaseLock();
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3820
|
+
};
|
|
3755
3821
|
Object.defineProperties(stream, {
|
|
3822
|
+
cancel: {
|
|
3823
|
+
configurable: true,
|
|
3824
|
+
writable: true,
|
|
3825
|
+
value(reason) {
|
|
3826
|
+
return ctx.awaitIo(cancel(reason));
|
|
3827
|
+
}
|
|
3828
|
+
},
|
|
3756
3829
|
getReader: {
|
|
3757
3830
|
configurable: true,
|
|
3758
3831
|
writable: true,
|
|
@@ -3782,15 +3855,47 @@ function gateReadableStream(ctx, stream) {
|
|
|
3782
3855
|
value(destination, options) {
|
|
3783
3856
|
return ctx.awaitIo(pipeTo(destination, options));
|
|
3784
3857
|
}
|
|
3858
|
+
},
|
|
3859
|
+
values: {
|
|
3860
|
+
configurable: true,
|
|
3861
|
+
writable: true,
|
|
3862
|
+
value: values
|
|
3863
|
+
},
|
|
3864
|
+
[Symbol.asyncIterator]: {
|
|
3865
|
+
configurable: true,
|
|
3866
|
+
writable: true,
|
|
3867
|
+
value: values
|
|
3785
3868
|
}
|
|
3786
3869
|
});
|
|
3787
3870
|
return stream;
|
|
3788
3871
|
}
|
|
3789
3872
|
function gateReader(ctx, reader) {
|
|
3873
|
+
const bound = /* @__PURE__ */ new Map();
|
|
3790
3874
|
return new Proxy(reader, { get(subject, property) {
|
|
3791
|
-
|
|
3875
|
+
const cached = bound.get(property);
|
|
3876
|
+
if (cached !== void 0) return cached;
|
|
3877
|
+
if (property === "closed") {
|
|
3878
|
+
const closed = ctx.awaitIo(subject.closed);
|
|
3879
|
+
bound.set(property, closed);
|
|
3880
|
+
return closed;
|
|
3881
|
+
}
|
|
3882
|
+
if (property === "read") {
|
|
3883
|
+
const read = () => ctx.awaitIo(subject.read());
|
|
3884
|
+
bound.set(property, read);
|
|
3885
|
+
return read;
|
|
3886
|
+
}
|
|
3887
|
+
if (property === "cancel") {
|
|
3888
|
+
const cancel = (reason) => ctx.awaitIo(subject.cancel(reason));
|
|
3889
|
+
bound.set(property, cancel);
|
|
3890
|
+
return cancel;
|
|
3891
|
+
}
|
|
3792
3892
|
const value = Reflect.get(subject, property, subject);
|
|
3793
|
-
|
|
3893
|
+
if (typeof value === "function") {
|
|
3894
|
+
const method = value.bind(subject);
|
|
3895
|
+
bound.set(property, method);
|
|
3896
|
+
return method;
|
|
3897
|
+
}
|
|
3898
|
+
return value;
|
|
3794
3899
|
} });
|
|
3795
3900
|
}
|
|
3796
3901
|
//#endregion
|