Skip to content

Commit

Permalink
support GET server functions
Browse files Browse the repository at this point in the history
  • Loading branch information
ryansolid committed Jan 24, 2024
1 parent 7b62a2d commit b5573d9
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 54 deletions.
1 change: 1 addition & 0 deletions packages/start/config/server-fns-runtime.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export function createServerReference(fn, id, name) {
if (prop === "url") {
return `${baseURL}/_server?id=${encodeURIComponent(id)}&name=${encodeURIComponent(name)}`;
}
if (prop === "GET") return receiver;
},
apply(target, thisArg, args) {
const ogEvt = getRequestEvent();
Expand Down
58 changes: 29 additions & 29 deletions packages/start/config/server-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,13 @@ import { sharedConfig } from "solid-js";
/* @ts-ignore */
import { provideRequestEvent } from "solid-js/web/storage";
import invariant from "vinxi/lib/invariant";
import {
eventHandler,
setHeader
} from "vinxi/server";
import { eventHandler, setHeader } from "vinxi/server";
import { getFetchEvent } from "../server/middleware";

function createChunk(data) {
const bytes = data.length;
const baseHex = bytes.toString(16);
const totalHex = '00000000'.substring(0, 8 - baseHex.length) + baseHex; // 32-bit
const totalHex = "00000000".substring(0, 8 - baseHex.length) + baseHex; // 32-bit
return new TextEncoder().encode(`;0x${totalHex};${data}`);
}

Expand All @@ -47,7 +44,9 @@ function serializeToStream(id, value) {
URLPlugin
],
onSerialize(data, initial) {
controller.enqueue(createChunk(initial ? `(${getCrossReferenceHeader(id)},${data})` : data));
controller.enqueue(
createChunk(initial ? `(${getCrossReferenceHeader(id)},${data})` : data)
);
},
onDone() {
controller.close();
Expand All @@ -61,7 +60,6 @@ function serializeToStream(id, value) {
}

async function handleServerFunction(h3Event) {
invariant(h3Event.method === "POST", `Invalid method ${h3Event.method}. Expected POST.`);
const event = getFetchEvent(h3Event);
const request = event.request;

Expand All @@ -84,31 +82,33 @@ async function handleServerFunction(h3Event) {
let parsed = [];

// grab bound arguments from url when no JS
if (!instance) {
if (!instance || h3Event.method === "GET") {
const args = url.searchParams.get("args");
if (args) JSON.parse(args).forEach(arg => parsed.push(arg));
}
const contentType = request.headers.get("content-type");
if (
contentType.startsWith("multipart/form-data") ||
contentType.startsWith("application/x-www-form-urlencoded")
) {
parsed.push(await request.formData());
} else {
parsed = fromJSON(await request.json(), {
plugins: [
CustomEventPlugin,
DOMExceptionPlugin,
EventPlugin,
FormDataPlugin,
HeadersPlugin,
ReadableStreamPlugin,
RequestPlugin,
ResponsePlugin,
URLSearchParamsPlugin,
URLPlugin
]
});
if (h3Event.method === "POST") {
const contentType = request.headers.get("content-type");
if (
contentType.startsWith("multipart/form-data") ||
contentType.startsWith("application/x-www-form-urlencoded")
) {
parsed.push(await request.formData());
} else {
parsed = fromJSON(await request.json(), {
plugins: [
CustomEventPlugin,
DOMExceptionPlugin,
EventPlugin,
FormDataPlugin,
HeadersPlugin,
ReadableStreamPlugin,
RequestPlugin,
ResponsePlugin,
URLSearchParamsPlugin,
URLPlugin
]
});
}
}
try {
const result = await provideRequestEvent(event, () => {
Expand Down
70 changes: 45 additions & 25 deletions packages/start/config/server-runtime.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import {
RequestPlugin,
ResponsePlugin,
URLPlugin,
URLSearchParamsPlugin,
} from 'seroval-plugins/web';
URLSearchParamsPlugin
} from "seroval-plugins/web";
import { createIslandReference } from "../server/islands";

class SerovalChunkReader {
constructor(stream) {
this.reader = stream.getReader();
this.buffer = '';
this.buffer = "";
this.done = false;
}

Expand All @@ -33,12 +33,12 @@ class SerovalChunkReader {

async next() {
// Check if the buffer is empty
if (this.buffer === '') {
if (this.buffer === "") {
// if we are already done...
if (this.done) {
return {
done: true,
value: undefined,
value: undefined
};
}
// Otherwise, read a new chunk
Expand All @@ -55,7 +55,7 @@ class SerovalChunkReader {
// If it's not enough, and the reader is done
// then the chunk is invalid.
if (this.done) {
throw new Error('Malformed server function stream.')
throw new Error("Malformed server function stream.");
}
// Otherwise, we read more chunks
await this.readChunk();
Expand All @@ -67,7 +67,7 @@ class SerovalChunkReader {
// Deserialize the chunk
return {
done: false,
value: deserialize(partial),
value: deserialize(partial)
};
}

Expand Down Expand Up @@ -117,31 +117,48 @@ function createRequest(base, id, instance, body, contentType) {
});
}

async function fetchServerFunction(base, id, args) {
async function fetchServerFunction(base, id, method, args) {
const instance = `server-fn:${INSTANCE++}`;
const response = await (args.length === 1 && args[0] instanceof FormData
const response = await (method === "GET"
? fetch(base + `/?args=${JSON.stringify(args)}`, {
headers: {
"x-server-id": id,
"x-server-instance": instance
}
})
: args.length === 1 && args[0] instanceof FormData
? createRequest(base, id, instance, args[0])
: createRequest(base, id, instance, JSON.stringify(await Promise.resolve(toJSONAsync(args, {
plugins: [
CustomEventPlugin,
DOMExceptionPlugin,
EventPlugin,
FormDataPlugin,
HeadersPlugin,
ReadableStreamPlugin,
RequestPlugin,
ResponsePlugin,
URLSearchParamsPlugin,
URLPlugin,
],
}))), "application/json"));
: createRequest(
base,
id,
instance,
JSON.stringify(
await Promise.resolve(
toJSONAsync(args, {
plugins: [
CustomEventPlugin,
DOMExceptionPlugin,
EventPlugin,
FormDataPlugin,
HeadersPlugin,
ReadableStreamPlugin,
RequestPlugin,
ResponsePlugin,
URLSearchParamsPlugin,
URLPlugin
]
})
)
),
"application/json"
));

if (response.headers.get("Location")) throw response;
if (response.headers.get("X-Revalidate")) {
/* ts-ignore-next-line */
response.customBody = () => {
return deserializeStream(instance, response);
}
};
throw response;
}
const contentType = response.headers.get("Content-Type");
Expand All @@ -166,9 +183,12 @@ export function createServerReference(fn, id, name) {
if (prop === "url") {
return `${baseURL}/_server?id=${encodeURIComponent(id)}&name=${encodeURIComponent(name)}`;
}
if (prop === "GET") {
return (...args) => fetchServerFunction(`${baseURL}/_server`, `${id}#${name}`, "GET", args);
}
},
apply(target, thisArg, args) {
return fetchServerFunction(`${baseURL}/_server`, `${id}#${name}`, args);
return fetchServerFunction(`${baseURL}/_server`, `${id}#${name}`, "POST", args);
}
});
}
Expand Down

0 comments on commit b5573d9

Please sign in to comment.