diff --git a/README.md b/README.md
index 494e28c..0df5b3a 100644
--- a/README.md
+++ b/README.md
@@ -134,6 +134,26 @@ and fallback to the network otherwise
```
+## `fetch`
+
+Optionally provide function to override default `fetch` logic.
+
+```marko
+
+```
+
## `timeout`
A timeout in `ms` (defaults to 30s) that will prematurely abort the request. This will trigger the `<@catch>` if provided.
diff --git a/src/components/micro-frame/component/node.marko b/src/components/micro-frame/component/node.marko
index 6d3149f..8bcae21 100644
--- a/src/components/micro-frame/component/node.marko
+++ b/src/components/micro-frame/component/node.marko
@@ -2,22 +2,9 @@ import path from "path";
import fetch from "make-fetch-happen";
static const cachePath = path.resolve("node_modules/.cache/fetch");
-static function createDeferredPromise() {
- let resolve;
- let reject;
- const promise = new Promise((_resolve, _reject) => {
- resolve = _resolve;
- reject = _reject;
- });
- promise.resolve = resolve;
- promise.reject = reject;
- return promise;
-}
+static const strictSSL = process.env.NODE_TLS_REJECT_UNAUTHORIZED !== "0";
-$ let buf = "";
-$ let hasMore = true;
-$ let sentData = false;
-$ let next = (async () => {
+static async function fetchStream(input, out) {
const incomingMessage = out.stream && (out.stream.req || out.stream.request);
if (!incomingMessage) {
@@ -25,36 +12,31 @@ $ let next = (async () => {
}
const url = new URL(input.src, `${incomingMessage.protocol}://${incomingMessage.headers.host}`);
- const res = await fetch(url, {
- cachePath,
- cache: input.cache,
- strictSSL: process.env.NODE_TLS_REJECT_UNAUTHORIZED !== "0",
- headers: {
- ...incomingMessage.headers,
- ...input.headers,
- accept: "text/html",
- }
- });
+ const { cache } = input;
+ const headers = {
+ ...incomingMessage.headers,
+ ...input.headers,
+ accept: "text/html",
+ };
+
+ const res = await (input.fetch
+ ? input.fetch(url, { cache, headers }, fetch)
+ : fetch(url, {
+ cache,
+ headers,
+ cachePath,
+ strictSSL,
+ })
+ );
if (!res.ok) throw new Error(res.statusText);
- next = createDeferredPromise();
- res.body
- .on("data", data => {
- buf += data.toString();
- if (next) next = next.resolve();
- })
- .on("error", err => {
- if (next) next = next.reject(err);
- else out.error(err);
- })
- .on("end", () => {
- hasMore = false;
- if (next) next = next.resolve();
- });
+ if (!res.body || !res.body[Symbol.asyncIterator]) {
+ throw new Error("Response body must be a stream.");
+ }
- return next;
-})();
+ return res.body[Symbol.asyncIterator]();
+}
@@ -63,32 +45,42 @@ $ let next = (async () => {
$!{``}
-
-
- <@then>
- $!{buf}
-
- $ buf = "";
- $ sentData = true;
- $ next = createDeferredPromise();
-
-
- @then>
-
-
-
$ out.bf("@_", component, true);
-
- $ out.ef();
+
+ <@then|iter|>
+
+
+ <@then|{ value, done }|>
+
+
+
+ $ out.script(`((e,t,d)=>{t=document.getElementById(e);do{t.removeChild(d=t.firstChild)}while(d.data!==e)})(${JSON.stringify(component.id)});`);
+
+
+
+ $!{value}
+
+
+ @then>
+ <@catch|err|>
+
+
+
+ <${input.catch}(err)/>
+
+
+ $ throw err;
+
+ @catch>
+
+
-
-
- $ out.script(`((e,t,d)=>{t=document.getElementById(e);do{t.removeChild(d=t.firstChild)}while(d.data!==e)})(${JSON.stringify(component.id)});`);
-
+
+ @then>
+
+ $ out.ef();
diff --git a/src/components/micro-frame/component/web.component.ts b/src/components/micro-frame/component/web.component.ts
index d2ab717..8cd5a19 100644
--- a/src/components/micro-frame/component/web.component.ts
+++ b/src/components/micro-frame/component/web.component.ts
@@ -7,6 +7,11 @@ interface Input {
loading?: unknown;
cache?: RequestCache;
headers?: Record;
+ fetch?: (
+ url: string,
+ options: RequestInit,
+ fetch: typeof window.fetch
+ ) => Promise;
}
interface State {
@@ -49,11 +54,15 @@ export = {
let err: Error | undefined;
try {
- const res = await fetch(this.src, {
+ const options: RequestInit = {
cache: this.input.cache,
signal: controller.signal,
headers: Object.assign({}, this.input.headers, { accept: "text/html" }),
- });
+ };
+
+ const res = await (this.input.fetch
+ ? this.input.fetch(this.src, options, fetch)
+ : fetch(this.src, options));
if (!res.ok) throw new Error(res.statusText);
const reader = res.body!.getReader();
const decoder = new TextDecoder();