@fragno-dev/node 0.0.5
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/.turbo/turbo-build.log +13 -0
- package/.turbo/turbo-types$colon$check.log +1 -0
- package/CHANGELOG.md +29 -0
- package/dist/fragno-node.d.ts +45 -0
- package/dist/fragno-node.d.ts.map +1 -0
- package/dist/fragno-node.js +47 -0
- package/dist/fragno-node.js.map +1 -0
- package/fragno-node-express.test.ts +77 -0
- package/fragno-node-http.test.ts +81 -0
- package/fragno-node.ts +43 -0
- package/node-stream.test.ts +94 -0
- package/package.json +39 -0
- package/tsconfig.json +10 -0
- package/tsdown.config.ts +6 -0
- package/vitest.config.ts +3 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
$ tsdown
|
|
2
|
+
[34mℹ[39m tsdown [2mv0.15.5[22m powered by rolldown [2mv1.0.0-beta.40[22m
|
|
3
|
+
[34mℹ[39m Using tsdown config: [4m/home/runner/work/fragno/fragno/packages/fragno-node/tsdown.config.ts[24m
|
|
4
|
+
[34mℹ[39m entry: [34mfragno-node.ts[39m
|
|
5
|
+
[34mℹ[39m target: [34mnode20.0.0[39m
|
|
6
|
+
[34mℹ[39m tsconfig: [34mtsconfig.json[39m
|
|
7
|
+
[34mℹ[39m Build start
|
|
8
|
+
[34mℹ[39m [2mdist/[22m[1mfragno-node.js[22m [2m1.37 kB[22m [2m│ gzip: 0.50 kB[22m
|
|
9
|
+
[34mℹ[39m [2mdist/[22mfragno-node.js.map [2m1.68 kB[22m [2m│ gzip: 0.60 kB[22m
|
|
10
|
+
[34mℹ[39m [2mdist/[22mfragno-node.d.ts.map [2m0.20 kB[22m [2m│ gzip: 0.14 kB[22m
|
|
11
|
+
[34mℹ[39m [2mdist/[22m[32m[1mfragno-node.d.ts[22m[39m [2m1.40 kB[22m [2m│ gzip: 0.50 kB[22m
|
|
12
|
+
[34mℹ[39m 4 files, total: 4.64 kB
|
|
13
|
+
[32m✔[39m Build complete in [32m10283ms[39m
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
$ tsc --noEmit
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# @fragno-dev/node
|
|
2
|
+
|
|
3
|
+
## 0.0.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [b9450b1]
|
|
8
|
+
- @fragno-dev/core@0.0.5
|
|
9
|
+
|
|
10
|
+
## 0.0.4
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Updated dependencies [1dae6f9]
|
|
15
|
+
- @fragno-dev/core@0.0.4
|
|
16
|
+
|
|
17
|
+
## 0.0.3
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- Updated dependencies [604caff]
|
|
22
|
+
- @fragno-dev/core@0.0.3
|
|
23
|
+
|
|
24
|
+
## 0.0.2
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- Updated dependencies [2052919]
|
|
29
|
+
- @fragno-dev/core@0.0.2
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { RequestListener } from "node:http";
|
|
2
|
+
|
|
3
|
+
//#region fragno-node.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a handler that can be used with `node:http` to serve backend requests based on a Fragno
|
|
7
|
+
* fragment (library).
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* import { createServer } from "node:http";
|
|
11
|
+
* import { toNodeHandler } from "@fragno-dev/node";
|
|
12
|
+
* import { createExampleFragment } from "@fragno-dev/example-fragment";
|
|
13
|
+
*
|
|
14
|
+
* const fragment = createExampleFragment();
|
|
15
|
+
*
|
|
16
|
+
* const server = createServer(toNodeHandler(fragment.handler));
|
|
17
|
+
* server.listen(8080);
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* import { createServer } from "node:http";
|
|
21
|
+
* import { toNodeHandler } from "@fragno-dev/node";
|
|
22
|
+
* import { createExampleFragment } from "@fragno-dev/example-fragment";
|
|
23
|
+
*
|
|
24
|
+
* const fragment = createExampleFragment();
|
|
25
|
+
*
|
|
26
|
+
* const server = createServer((req, res) => {
|
|
27
|
+
* if (req.url?.startsWith(fragment.mountRoute)) {
|
|
28
|
+
* const handler = toNodeHandler(fragment.handler);
|
|
29
|
+
* return handler(req, res);
|
|
30
|
+
* }
|
|
31
|
+
* // ... Your route handling
|
|
32
|
+
* });
|
|
33
|
+
* @example
|
|
34
|
+
* import express from "express";
|
|
35
|
+
* import { toNodeHandler } from "@fragno-dev/node";
|
|
36
|
+
*
|
|
37
|
+
* const app = express();
|
|
38
|
+
* app.all("/api/my-library/{*any}", toNodeHandler(fragment.handler));
|
|
39
|
+
*
|
|
40
|
+
* app.listen(8080);
|
|
41
|
+
*/
|
|
42
|
+
declare function toNodeHandler(handler: (req: Request) => Promise<Response>): RequestListener;
|
|
43
|
+
//#endregion
|
|
44
|
+
export { toNodeHandler };
|
|
45
|
+
//# sourceMappingURL=fragno-node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fragno-node.d.ts","names":[],"sources":["../fragno-node.ts"],"sourcesContent":[],"mappings":";;;;;;AAwCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAgB,aAAA,gBAA6B,YAAY,QAAQ,YAAY"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { createRequestListener } from "@remix-run/node-fetch-server";
|
|
2
|
+
|
|
3
|
+
//#region fragno-node.ts
|
|
4
|
+
/**
|
|
5
|
+
* Creates a handler that can be used with `node:http` to serve backend requests based on a Fragno
|
|
6
|
+
* fragment (library).
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* import { createServer } from "node:http";
|
|
10
|
+
* import { toNodeHandler } from "@fragno-dev/node";
|
|
11
|
+
* import { createExampleFragment } from "@fragno-dev/example-fragment";
|
|
12
|
+
*
|
|
13
|
+
* const fragment = createExampleFragment();
|
|
14
|
+
*
|
|
15
|
+
* const server = createServer(toNodeHandler(fragment.handler));
|
|
16
|
+
* server.listen(8080);
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* import { createServer } from "node:http";
|
|
20
|
+
* import { toNodeHandler } from "@fragno-dev/node";
|
|
21
|
+
* import { createExampleFragment } from "@fragno-dev/example-fragment";
|
|
22
|
+
*
|
|
23
|
+
* const fragment = createExampleFragment();
|
|
24
|
+
*
|
|
25
|
+
* const server = createServer((req, res) => {
|
|
26
|
+
* if (req.url?.startsWith(fragment.mountRoute)) {
|
|
27
|
+
* const handler = toNodeHandler(fragment.handler);
|
|
28
|
+
* return handler(req, res);
|
|
29
|
+
* }
|
|
30
|
+
* // ... Your route handling
|
|
31
|
+
* });
|
|
32
|
+
* @example
|
|
33
|
+
* import express from "express";
|
|
34
|
+
* import { toNodeHandler } from "@fragno-dev/node";
|
|
35
|
+
*
|
|
36
|
+
* const app = express();
|
|
37
|
+
* app.all("/api/my-library/{*any}", toNodeHandler(fragment.handler));
|
|
38
|
+
*
|
|
39
|
+
* app.listen(8080);
|
|
40
|
+
*/
|
|
41
|
+
function toNodeHandler(handler) {
|
|
42
|
+
return createRequestListener(handler);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
//#endregion
|
|
46
|
+
export { toNodeHandler };
|
|
47
|
+
//# sourceMappingURL=fragno-node.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fragno-node.js","names":[],"sources":["../fragno-node.ts"],"sourcesContent":["import type { RequestListener } from \"node:http\";\nimport { createRequestListener } from \"@remix-run/node-fetch-server\";\n\n/**\n * Creates a handler that can be used with `node:http` to serve backend requests based on a Fragno\n * fragment (library).\n *\n * @example\n * import { createServer } from \"node:http\";\n * import { toNodeHandler } from \"@fragno-dev/node\";\n * import { createExampleFragment } from \"@fragno-dev/example-fragment\";\n *\n * const fragment = createExampleFragment();\n *\n * const server = createServer(toNodeHandler(fragment.handler));\n * server.listen(8080);\n *\n * @example\n * import { createServer } from \"node:http\";\n * import { toNodeHandler } from \"@fragno-dev/node\";\n * import { createExampleFragment } from \"@fragno-dev/example-fragment\";\n *\n * const fragment = createExampleFragment();\n *\n * const server = createServer((req, res) => {\n * if (req.url?.startsWith(fragment.mountRoute)) {\n * const handler = toNodeHandler(fragment.handler);\n * return handler(req, res);\n * }\n * // ... Your route handling\n * });\n * @example\n * import express from \"express\";\n * import { toNodeHandler } from \"@fragno-dev/node\";\n *\n * const app = express();\n * app.all(\"/api/my-library/{*any}\", toNodeHandler(fragment.handler));\n *\n * app.listen(8080);\n */\nexport function toNodeHandler(handler: (req: Request) => Promise<Response>): RequestListener {\n return createRequestListener(handler);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCA,SAAgB,cAAc,SAA+D;AAC3F,QAAO,sBAAsB,QAAQ"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import express, { type Application } from "express";
|
|
2
|
+
import { test, expect, describe, beforeAll, afterAll } from "vitest";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import {
|
|
5
|
+
defineFragment,
|
|
6
|
+
defineRoute,
|
|
7
|
+
createFragment,
|
|
8
|
+
type FragnoInstantiatedFragment,
|
|
9
|
+
type FragnoPublicClientConfig,
|
|
10
|
+
} from "@fragno-dev/core";
|
|
11
|
+
import { toNodeHandler } from "./fragno-node";
|
|
12
|
+
|
|
13
|
+
describe("Fragno Express integration", () => {
|
|
14
|
+
const testFragmentDefinition = defineFragment("test-fragment");
|
|
15
|
+
|
|
16
|
+
const usersRoute = defineRoute({
|
|
17
|
+
method: "GET",
|
|
18
|
+
path: "/users",
|
|
19
|
+
outputSchema: z.array(z.object({ id: z.number(), name: z.string() })),
|
|
20
|
+
handler: async (_ctx, { json }) => json([{ id: 1, name: "John" }]),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const clientConfig: FragnoPublicClientConfig = {
|
|
24
|
+
baseUrl: "http://localhost",
|
|
25
|
+
};
|
|
26
|
+
let testFragment: FragnoInstantiatedFragment<[typeof usersRoute]>;
|
|
27
|
+
let app: Application;
|
|
28
|
+
let server: ReturnType<typeof app.listen>;
|
|
29
|
+
let port: number;
|
|
30
|
+
|
|
31
|
+
function createExpressServerForTest() {
|
|
32
|
+
testFragment = createFragment(testFragmentDefinition, {}, [usersRoute], clientConfig);
|
|
33
|
+
app = express();
|
|
34
|
+
|
|
35
|
+
app.all("/api/test-fragment/{*any}", toNodeHandler(testFragment.handler));
|
|
36
|
+
|
|
37
|
+
// Add JSON body parsing middleware
|
|
38
|
+
app.use(express.json());
|
|
39
|
+
app.get("/some-other-route", (_req, res) => {
|
|
40
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
41
|
+
res.end(JSON.stringify({ message: "Hello world" }));
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
server = app.listen(0);
|
|
45
|
+
|
|
46
|
+
const address = server.address();
|
|
47
|
+
if (!address || typeof address === "string") {
|
|
48
|
+
throw new Error("Address invalid");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
port = address.port;
|
|
52
|
+
clientConfig.baseUrl = `http://localhost:${port}`;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
beforeAll(() => {
|
|
56
|
+
createExpressServerForTest();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
afterAll(() => {
|
|
60
|
+
server.close();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("should fetch data from the GET /users route", async () => {
|
|
64
|
+
const response = await fetch(`${clientConfig.baseUrl}${testFragment.mountRoute}/users`);
|
|
65
|
+
|
|
66
|
+
expect(response.ok).toBe(true);
|
|
67
|
+
|
|
68
|
+
const data = await response.json();
|
|
69
|
+
expect(data).toEqual([{ id: 1, name: "John" }]);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test("should fall back to normal express routes for non-lib routes", async () => {
|
|
73
|
+
const response = await fetch(`${clientConfig.baseUrl}/some-other-route`);
|
|
74
|
+
const data = await response.json();
|
|
75
|
+
expect(data).toEqual({ message: "Hello world" });
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createServer, type RequestListener, type Server } from "node:http";
|
|
2
|
+
import { test, expect, describe } from "vitest";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import {
|
|
5
|
+
defineFragment,
|
|
6
|
+
defineRoute,
|
|
7
|
+
createFragment,
|
|
8
|
+
type FragnoInstantiatedFragment,
|
|
9
|
+
type FragnoPublicClientConfig,
|
|
10
|
+
} from "@fragno-dev/core";
|
|
11
|
+
import { toNodeHandler } from "./fragno-node";
|
|
12
|
+
|
|
13
|
+
describe("Fragno Node.js integration", () => {
|
|
14
|
+
const testFragmentDefinition = defineFragment("test-fragment");
|
|
15
|
+
|
|
16
|
+
const usersRoute = defineRoute({
|
|
17
|
+
method: "GET",
|
|
18
|
+
path: "/users",
|
|
19
|
+
outputSchema: z.array(z.object({ id: z.number(), name: z.string() })),
|
|
20
|
+
handler: async (_ctx, { json }) => json([{ id: 1, name: "John" }]),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const clientConfig: FragnoPublicClientConfig = {
|
|
24
|
+
baseUrl: "http://localhost",
|
|
25
|
+
};
|
|
26
|
+
let testFragment: FragnoInstantiatedFragment<[typeof usersRoute]>;
|
|
27
|
+
let server: Server;
|
|
28
|
+
let port: number;
|
|
29
|
+
|
|
30
|
+
function createServerForTest(
|
|
31
|
+
listenerFactory: (fragment: FragnoInstantiatedFragment<[typeof usersRoute]>) => RequestListener,
|
|
32
|
+
) {
|
|
33
|
+
testFragment = createFragment(testFragmentDefinition, {}, [usersRoute], clientConfig);
|
|
34
|
+
server = createServer(listenerFactory(testFragment));
|
|
35
|
+
server.listen(0);
|
|
36
|
+
|
|
37
|
+
const address = server.address();
|
|
38
|
+
if (!address || typeof address === "string") {
|
|
39
|
+
throw new Error("Address invalid");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
port = address.port;
|
|
43
|
+
clientConfig.baseUrl = `http://localhost:${port}`;
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
close: () => server.close(),
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
test("should fetch data from the GET /users route", async () => {
|
|
51
|
+
const { close } = createServerForTest((fragment) => toNodeHandler(fragment.handler));
|
|
52
|
+
|
|
53
|
+
const response = await fetch(`${clientConfig.baseUrl}${testFragment.mountRoute}/users`);
|
|
54
|
+
|
|
55
|
+
expect(response.ok).toBe(true);
|
|
56
|
+
|
|
57
|
+
const data = await response.json();
|
|
58
|
+
expect(data).toEqual([{ id: 1, name: "John" }]);
|
|
59
|
+
|
|
60
|
+
close();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("should fall back to normal server for non-lib routes", async () => {
|
|
64
|
+
const { close } = createServerForTest((fragment) => (req, res) => {
|
|
65
|
+
if (req.url?.startsWith(fragment.mountRoute)) {
|
|
66
|
+
const handler = toNodeHandler(fragment.handler);
|
|
67
|
+
return handler(req, res);
|
|
68
|
+
} else {
|
|
69
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
70
|
+
res.end(JSON.stringify({ message: "It's working." }));
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const response = await fetch(`${clientConfig.baseUrl}/`);
|
|
75
|
+
expect(response.ok).toBe(true);
|
|
76
|
+
const data = await response.json();
|
|
77
|
+
expect(data).toEqual({ message: "It's working." });
|
|
78
|
+
|
|
79
|
+
close();
|
|
80
|
+
});
|
|
81
|
+
});
|
package/fragno-node.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { RequestListener } from "node:http";
|
|
2
|
+
import { createRequestListener } from "@remix-run/node-fetch-server";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Creates a handler that can be used with `node:http` to serve backend requests based on a Fragno
|
|
6
|
+
* fragment (library).
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* import { createServer } from "node:http";
|
|
10
|
+
* import { toNodeHandler } from "@fragno-dev/node";
|
|
11
|
+
* import { createExampleFragment } from "@fragno-dev/example-fragment";
|
|
12
|
+
*
|
|
13
|
+
* const fragment = createExampleFragment();
|
|
14
|
+
*
|
|
15
|
+
* const server = createServer(toNodeHandler(fragment.handler));
|
|
16
|
+
* server.listen(8080);
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* import { createServer } from "node:http";
|
|
20
|
+
* import { toNodeHandler } from "@fragno-dev/node";
|
|
21
|
+
* import { createExampleFragment } from "@fragno-dev/example-fragment";
|
|
22
|
+
*
|
|
23
|
+
* const fragment = createExampleFragment();
|
|
24
|
+
*
|
|
25
|
+
* const server = createServer((req, res) => {
|
|
26
|
+
* if (req.url?.startsWith(fragment.mountRoute)) {
|
|
27
|
+
* const handler = toNodeHandler(fragment.handler);
|
|
28
|
+
* return handler(req, res);
|
|
29
|
+
* }
|
|
30
|
+
* // ... Your route handling
|
|
31
|
+
* });
|
|
32
|
+
* @example
|
|
33
|
+
* import express from "express";
|
|
34
|
+
* import { toNodeHandler } from "@fragno-dev/node";
|
|
35
|
+
*
|
|
36
|
+
* const app = express();
|
|
37
|
+
* app.all("/api/my-library/{*any}", toNodeHandler(fragment.handler));
|
|
38
|
+
*
|
|
39
|
+
* app.listen(8080);
|
|
40
|
+
*/
|
|
41
|
+
export function toNodeHandler(handler: (req: Request) => Promise<Response>): RequestListener {
|
|
42
|
+
return createRequestListener(handler);
|
|
43
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import express, { type Application } from "express";
|
|
2
|
+
import { test, expect, describe, beforeAll, afterAll, assert } from "vitest";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import {
|
|
5
|
+
defineFragment,
|
|
6
|
+
defineRoute,
|
|
7
|
+
createFragment,
|
|
8
|
+
type FragnoInstantiatedFragment,
|
|
9
|
+
type FragnoPublicClientConfig,
|
|
10
|
+
} from "@fragno-dev/core";
|
|
11
|
+
import { toNodeHandler } from "./fragno-node";
|
|
12
|
+
|
|
13
|
+
describe("Node.js Streaming", () => {
|
|
14
|
+
const testFragmentDefinition = defineFragment("test-fragment");
|
|
15
|
+
|
|
16
|
+
const streamRoute = defineRoute({
|
|
17
|
+
method: "GET",
|
|
18
|
+
path: "/stream",
|
|
19
|
+
outputSchema: z.array(z.object({ message: z.string() })),
|
|
20
|
+
handler: async (_ctx, { jsonStream }) => {
|
|
21
|
+
return jsonStream(async (stream) => {
|
|
22
|
+
await stream.write({ message: "Hello, " });
|
|
23
|
+
await stream.sleep(1);
|
|
24
|
+
await stream.write({ message: "World!" });
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const clientConfig: FragnoPublicClientConfig = {
|
|
30
|
+
baseUrl: "http://localhost",
|
|
31
|
+
};
|
|
32
|
+
let testFragment: FragnoInstantiatedFragment<[typeof streamRoute]>;
|
|
33
|
+
let app: Application;
|
|
34
|
+
let server: ReturnType<typeof app.listen>;
|
|
35
|
+
let port: number;
|
|
36
|
+
|
|
37
|
+
function createExpressServerForTest() {
|
|
38
|
+
testFragment = createFragment(testFragmentDefinition, {}, [streamRoute], clientConfig);
|
|
39
|
+
app = express();
|
|
40
|
+
|
|
41
|
+
app.all("/api/test-fragment/{*any}", toNodeHandler(testFragment.handler));
|
|
42
|
+
|
|
43
|
+
// Add JSON body parsing middleware
|
|
44
|
+
app.use(express.json());
|
|
45
|
+
app.get("/some-other-route", (_req, res) => {
|
|
46
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
47
|
+
res.end(JSON.stringify({ message: "Hello world" }));
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
server = app.listen(0);
|
|
51
|
+
|
|
52
|
+
const address = server.address();
|
|
53
|
+
if (!address || typeof address === "string") {
|
|
54
|
+
throw new Error("Address invalid");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
port = address.port;
|
|
58
|
+
clientConfig.baseUrl = `http://localhost:${port}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
beforeAll(() => {
|
|
62
|
+
createExpressServerForTest();
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
afterAll(() => {
|
|
66
|
+
server.close();
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("should fetch data from the GET /stream route", async () => {
|
|
70
|
+
const response = await fetch(`${clientConfig.baseUrl}${testFragment.mountRoute}/stream`);
|
|
71
|
+
|
|
72
|
+
assert(response.body, "Response body is missing");
|
|
73
|
+
|
|
74
|
+
expect(response.headers.get("content-type")).toBe("application/x-ndjson; charset=utf-8");
|
|
75
|
+
expect(response.headers.get("cache-control")).toBe("no-cache");
|
|
76
|
+
expect(response.headers.get("transfer-encoding")).toBe("chunked");
|
|
77
|
+
|
|
78
|
+
const decoder = new TextDecoder();
|
|
79
|
+
let result = "";
|
|
80
|
+
for await (const chunk of response.body) {
|
|
81
|
+
const string = decoder.decode(chunk, { stream: true });
|
|
82
|
+
const lines = string.split("\n");
|
|
83
|
+
for (const line of lines) {
|
|
84
|
+
if (!line) {
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const jsonObject = JSON.parse(line);
|
|
89
|
+
result += jsonObject.message;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
expect(result).toBe("Hello, World!");
|
|
93
|
+
});
|
|
94
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fragno-dev/node",
|
|
3
|
+
"version": "0.0.5",
|
|
4
|
+
"exports": {
|
|
5
|
+
".": {
|
|
6
|
+
"bun": "./fragno-node.ts",
|
|
7
|
+
"development": "./fragno-node.ts",
|
|
8
|
+
"types": "./dist/fragno-node.d.ts",
|
|
9
|
+
"default": "./dist/fragno-node.js"
|
|
10
|
+
},
|
|
11
|
+
"./package.json": "./package.json"
|
|
12
|
+
},
|
|
13
|
+
"type": "module",
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsdown",
|
|
16
|
+
"build:watch": "tsdown --watch",
|
|
17
|
+
"types:check": "tsc --noEmit"
|
|
18
|
+
},
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"@fragno-dev/core": "0.0.5"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": "^20.0.0 || >=22.0.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@fragno-dev/core": "0.0.5",
|
|
27
|
+
"@fragno-private/typescript-config": "0.0.1",
|
|
28
|
+
"@types/node": "^22",
|
|
29
|
+
"@types/express": "^5.0.3",
|
|
30
|
+
"express": "^5.1.0",
|
|
31
|
+
"zod": "^4.0.5"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@remix-run/node-fetch-server": "^0.8.0"
|
|
35
|
+
},
|
|
36
|
+
"main": "./dist/fragno-node.js",
|
|
37
|
+
"module": "./dist/fragno-node.js",
|
|
38
|
+
"types": "./dist/fragno-node.d.ts"
|
|
39
|
+
}
|
package/tsconfig.json
ADDED
package/tsdown.config.ts
ADDED
package/vitest.config.ts
ADDED