Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@
"source.fixAll.eslint": "explicit"
},

"typescript.tsdk": "node_modules/typescript/lib",
"js/ts.tsdk.path": "node_modules/typescript/lib",
}
2 changes: 1 addition & 1 deletion docs/en/v0/guide/features/formData.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ To send complex `FormData`, you just need to use the client.
<!--@include: @/examples/v0/guide/features/formData/client.ts-->
```

Use the `createFormData` function from `@duplojs/utils` to get a `TheFormData`, an extended `FormData` class that supports complex structures. When the client detects that the body is a `TheFormData`, it automatically adds a custom header to indicate it to the server (`content-type-options: advanced`). This also keeps it compatible with standard `FormData`.
Use the `createFormData` function from `@duplojs/utils` to get a `TheFormData`, an extended `FormData` class that supports complex structures. When the client detects that the body is a `TheFormData`, it automatically adds a custom header to indicate it to the server (`x-duplojs-body-options: advanced`). This also keeps it compatible with standard `FormData`.
2 changes: 1 addition & 1 deletion docs/fr/v0/guide/features/formData.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ Pour envoyer des `FormData` à structure complexe, il vous suffit d'utiliser le
<!--@include: @/examples/v0/guide/features/formData/client.ts-->
```

Il suffit d'utiliser la fonction `createFormData` de la librairie `@duplojs/utils` pour obtenir un `TheFormData` (une classe étendue de `FormData`) qui supporte les structures complexes. Lorsque le client détecte que le body est un `TheFormData`, il ajoute automatiquement un en-tête personnalisé pour l'indiquer au serveur (`content-type-options: advanced`). Cela permet également de rester compatible avec des `FormData` classiques.
Il suffit d'utiliser la fonction `createFormData` de la librairie `@duplojs/utils` pour obtenir un `TheFormData` (une classe étendue de `FormData`) qui supporte les structures complexes. Lorsque le client détecte que le body est un `TheFormData`, il ajoute automatiquement un en-tête personnalisé pour l'indiquer au serveur (`x-duplojs-body-options: advanced`). Cela permet également de rester compatible avec des `FormData` classiques.
2 changes: 1 addition & 1 deletion docs/libs/v0/client/promiseRequest.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ class PromiseRequest extends Promise {
body = body.toString();
}
else if (body instanceof utils.TheFormData) {
headers["content-type-options"] = "advanced";
headers["x-duplojs-body-options"] = "advanced";
}
else if ((body
&& typeof body === "object"
Expand Down
2 changes: 1 addition & 1 deletion docs/libs/v0/client/promiseRequest.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ class PromiseRequest extends Promise {
body = body.toString();
}
else if (body instanceof TheFormData) {
headers["content-type-options"] = "advanced";
headers["x-duplojs-body-options"] = "advanced";
}
else if ((body
&& typeof body === "object"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ function createFormDataBodyReaderImplementation(serverParams) {
}
return result;
}
if (request.headers["content-type-options"]?.includes("advanced")) {
if (request.headers["x-duplojs-body-options"]?.includes("advanced")) {
return utils.E.success(utils.TheFormData.fromEntries(result.entries(), params.maxIndexArray));
}
return utils.E.success(utils.O.fromEntries(result.entries()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ function createFormDataBodyReaderImplementation(serverParams) {
}
return result;
}
if (request.headers["content-type-options"]?.includes("advanced")) {
if (request.headers["x-duplojs-body-options"]?.includes("advanced")) {
return E.success(TheFormData.fromEntries(result.entries(), params.maxIndexArray));
}
return E.success(O.fromEntries(result.entries()));
Expand Down
4 changes: 2 additions & 2 deletions docs/libs/v0/plugins/openApiGenerator/routeToOpenApi.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,13 @@ function routeToOpenApi(route, params) {
schema: body,
});
const content = utils.pipe(body, utils.P.when(utils.DP.identifier(utils.DP.emptyKind), utils.justReturn(lastValue[code]?.content)), utils.P.otherwise((value) => {
if (utils.DP.identifier(value, utils.DP.stringKind) && lastValue[code]?.content?.["plain/text"]) {
if (utils.DP.identifier(value, utils.DP.stringKind) && lastValue[code]?.content?.["text/plain"]) {
return lastValue[code].content;
}
if (utils.DP.identifier(value, utils.DP.stringKind)) {
return {
...lastValue[code]?.content,
"plain/text": {
"text/plain": {
schema: schemaResponse,
},
};
Expand Down
4 changes: 2 additions & 2 deletions docs/libs/v0/plugins/openApiGenerator/routeToOpenApi.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -165,13 +165,13 @@ function routeToOpenApi(route, params) {
schema: body,
});
const content = pipe(body, P.when(DP.identifier(DP.emptyKind), justReturn(lastValue[code]?.content)), P.otherwise((value) => {
if (DP.identifier(value, DP.stringKind) && lastValue[code]?.content?.["plain/text"]) {
if (DP.identifier(value, DP.stringKind) && lastValue[code]?.content?.["text/plain"]) {
return lastValue[code].content;
}
if (DP.identifier(value, DP.stringKind)) {
return {
...lastValue[code]?.content,
"plain/text": {
"text/plain": {
schema: schemaResponse,
},
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export interface EndpointResponseContent {
"application/json"?: {
schema: JsonSchema;
};
"plain/text"?: {
"text/plain"?: {
schema: JsonSchema;
};
}
Expand Down
32 changes: 32 additions & 0 deletions integration/codeGenerator/__snapshots__/index.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,38 @@ export type Routes = {
information: "cookie.dropped";
body?: undefined;
};
} | {
method: "GET";
path: "/stream";
query: {
value: number;
};
responses: {
code: "422";
information: "extract-error";
body?: undefined;
} | {
code: "200";
information: "monSuperStream";
body?: undefined;
flux: Uint8Array<ArrayBuffer>;
};
} | {
method: "POST";
path: "/stream-text";
body: {
value: string;
};
responses: {
code: "422";
information: "extract-error";
body?: undefined;
} | {
code: "200";
information: "monSuperStream";
body?: undefined;
flux: string;
};
} | {
method: "GET";
path: "/static-file";
Expand Down
2 changes: 2 additions & 0 deletions integration/core/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ import "./users";
import "./document";
import "./serverSentEvent";
import "./cookie";
import "./stream";
import "./streamText";
38 changes: 38 additions & 0 deletions integration/core/routes/stream.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { ResponseContract, useRouteBuilder } from "@duplojs/http";
import { DPE, sleep } from "@duplojs/utils";

useRouteBuilder("GET", "/stream")
.extract({
query: {
value: DPE.coerce.number(),
},
})
.handler(
ResponseContract.stream("monSuperStream", DPE.number()),
({ value }, { streamResponse }) => streamResponse(
"monSuperStream",
async({ send }) => {
await send(1);

await sleep(200);

await send(2);

await sleep(200);

await send(3);

await sleep(200);

await send(4);

await sleep(200);

await send(5);

await sleep(200);

await send(value);
},
),
);
38 changes: 38 additions & 0 deletions integration/core/routes/streamText.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { ResponseContract, useRouteBuilder } from "@duplojs/http";
import { DPE, sleep } from "@duplojs/utils";

useRouteBuilder("POST", "/stream-text")
.extract({
body: {
value: DPE.string(),
},
})
.handler(
ResponseContract.streamText("monSuperStream"),
({ value }, { streamTextResponse }) => streamTextResponse(
"monSuperStream",
async({ send }) => {
await send("super");

await sleep(200);

await send("Value");

await sleep(200);

await send("De");

await sleep(200);

await send("La");

await sleep(200);

await send("Mort");

await sleep(200);

await send(` ${value}`);
},
),
);
2 changes: 1 addition & 1 deletion integration/node/file.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe("file", async() => {
fetch("http://localhost:8961/documents", {
method: "POST",
body: formData,
headers: { "content-type-options": "advanced" },
headers: { "x-duplojs-body-options": "advanced" },
})
.then((response) => ({
headers: [...response.headers.entries()],
Expand Down
85 changes: 85 additions & 0 deletions integration/node/stream.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { hub } from "@core";
import { createHttpServer } from "@duplojs/http/node";

describe("stream", async() => {
const server = await createHttpServer(hub, {
host: "0.0.0.0",
port: 8653,
});

afterAll(() => {
server.close();
});

it("simple stream", async() => {
await expect(
fetch("http://localhost:8653/stream?value=12", { method: "GET" })
.then(async(response) => ({
body: await response.text(),
headers: [...response.headers.entries()],
})),
).resolves.toStrictEqual({
headers: expect.arrayContaining([
[
"information",
"monSuperStream",
],
[
"transfer-encoding",
"chunked",
],
[
"content-type",
"application/octet-stream",
],
[
"x-duplojs-body-options",
"stream",
],
[
"predicted",
"1",
],
]),
body: "1234512",
});
});

it("stream text", async() => {
await expect(
fetch("http://localhost:8653/stream-text", {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify({ value: "<3" }),
})
.then(async(response) => ({
body: await response.text(),
headers: [...response.headers.entries()],
})),
).resolves.toStrictEqual({
headers: expect.arrayContaining([
[
"information",
"monSuperStream",
],
[
"transfer-encoding",
"chunked",
],
[
"content-type",
"text/plain; charset=utf-8",
],
[
"x-duplojs-body-options",
"stream",
],
[
"predicted",
"1",
],
]),
body: "superValueDeLaMort <3",
});
});
});
Loading
Loading