@ontrails/vite 0.2.0
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 +109 -0
- package/README.md +24 -0
- package/package.json +34 -0
- package/src/index.ts +149 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# @ontrails/vite
|
|
2
|
+
|
|
3
|
+
## 0.2.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [`b3ddf91`](https://github.com/outfitter-dev/trails/commit/b3ddf918ada8211f44983512e2bbdfbc5b66d722): Prepare the first normal Trails release at `0.2.0` on `latest`, replacing the unpublished 1.0.0 source release. The target advances the original `0.1.0` source minor, which was never published under the current package names. Public packages remain in lockstep. Update consumer installation guidance and provide a temporary manifest bridge for old 1.0 beta sources. Published beta versions remain unchanged; minor 0.x releases may carry documented breaking changes.
|
|
8
|
+
|
|
9
|
+
The `1.0.0` section retained below records an unpublished preparation, not an npm release. Its accumulated changes are included in `0.2.0`; the section remains as source history alongside the published beta entries.
|
|
10
|
+
|
|
11
|
+
## 1.0.0
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- [`f5c6777`](https://github.com/outfitter-dev/trails/commit/f5c6777c39ea959d2123f17bb683151fe265386c): Move adapter package workspaces from `connectors/*` to `adapters/*` as part of
|
|
16
|
+
the package-boundary taxonomy cutover. Package names and public APIs are
|
|
17
|
+
unchanged.
|
|
18
|
+
- [`ed5926b`](https://github.com/outfitter-dev/trails/commit/ed5926bddebed7be19a902d69be58f2d5e8b4c51): Add missing TSDoc for public adapter and sink boundary types.
|
|
19
|
+
- [`b1fbe57`](https://github.com/outfitter-dev/trails/commit/b1fbe574e6f44d1fecb5e3a000270955c0a77b7b): Publish Bun-validated package tarballs through an npm trusted-publishing adapter
|
|
20
|
+
binding, add exact repository metadata for each public workspace package, and
|
|
21
|
+
correct the native Bun release descriptor to its pack-only runtime boundary.
|
|
22
|
+
|
|
23
|
+
## 1.0.0-beta.50
|
|
24
|
+
|
|
25
|
+
## 1.0.0-beta.49
|
|
26
|
+
|
|
27
|
+
## 1.0.0-beta.48
|
|
28
|
+
|
|
29
|
+
## 1.0.0-beta.47
|
|
30
|
+
|
|
31
|
+
## 1.0.0-beta.46
|
|
32
|
+
|
|
33
|
+
## 1.0.0-beta.45
|
|
34
|
+
|
|
35
|
+
## 1.0.0-beta.44
|
|
36
|
+
|
|
37
|
+
### Patch Changes
|
|
38
|
+
|
|
39
|
+
- [`b1fbe57`](https://github.com/outfitter-dev/trails/commit/b1fbe574e6f44d1fecb5e3a000270955c0a77b7b): Publish Bun-validated package tarballs through an npm trusted-publishing adapter
|
|
40
|
+
binding, add exact repository metadata for each public workspace package, and
|
|
41
|
+
correct the native Bun release descriptor to its pack-only runtime boundary.
|
|
42
|
+
|
|
43
|
+
## 1.0.0-beta.43
|
|
44
|
+
|
|
45
|
+
## 1.0.0-beta.42
|
|
46
|
+
|
|
47
|
+
## 1.0.0-beta.41
|
|
48
|
+
|
|
49
|
+
## 1.0.0-beta.40
|
|
50
|
+
|
|
51
|
+
## 1.0.0-beta.39
|
|
52
|
+
|
|
53
|
+
## 1.0.0-beta.38
|
|
54
|
+
|
|
55
|
+
## 1.0.0-beta.37
|
|
56
|
+
|
|
57
|
+
## 1.0.0-beta.36
|
|
58
|
+
|
|
59
|
+
## 1.0.0-beta.35
|
|
60
|
+
|
|
61
|
+
## 1.0.0-beta.34
|
|
62
|
+
|
|
63
|
+
## 1.0.0-beta.33
|
|
64
|
+
|
|
65
|
+
## 1.0.0-beta.32
|
|
66
|
+
|
|
67
|
+
## 1.0.0-beta.31
|
|
68
|
+
|
|
69
|
+
## 1.0.0-beta.30
|
|
70
|
+
|
|
71
|
+
## 1.0.0-beta.29
|
|
72
|
+
|
|
73
|
+
## 1.0.0-beta.28
|
|
74
|
+
|
|
75
|
+
## 1.0.0-beta.27
|
|
76
|
+
|
|
77
|
+
## 1.0.0-beta.26
|
|
78
|
+
|
|
79
|
+
## 1.0.0-beta.25
|
|
80
|
+
|
|
81
|
+
## 1.0.0-beta.24
|
|
82
|
+
|
|
83
|
+
## 1.0.0-beta.23
|
|
84
|
+
|
|
85
|
+
## 1.0.0-beta.22
|
|
86
|
+
|
|
87
|
+
## 1.0.0-beta.21
|
|
88
|
+
|
|
89
|
+
## 1.0.0-beta.20
|
|
90
|
+
|
|
91
|
+
## 1.0.0-beta.19
|
|
92
|
+
|
|
93
|
+
### Patch Changes
|
|
94
|
+
|
|
95
|
+
- ed5926b: Add missing TSDoc for public adapter and sink boundary types.
|
|
96
|
+
|
|
97
|
+
## 1.0.0-beta.18
|
|
98
|
+
|
|
99
|
+
## 1.0.0-beta.17
|
|
100
|
+
|
|
101
|
+
## 1.0.0-beta.16
|
|
102
|
+
|
|
103
|
+
### Patch Changes
|
|
104
|
+
|
|
105
|
+
- f5c6777: Move adapter package workspaces from `connectors/*` to `adapters/*` as part of
|
|
106
|
+
the package-boundary taxonomy cutover. Package names and public APIs are
|
|
107
|
+
unchanged.
|
|
108
|
+
|
|
109
|
+
## 1.0.0-beta.15
|
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# `@ontrails/vite`
|
|
2
|
+
|
|
3
|
+
Bridge a fetch-based Trails HTTP surface into Vite's dev-server middleware stack.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { createApp } from '@ontrails/hono';
|
|
7
|
+
import { vite } from '@ontrails/vite';
|
|
8
|
+
import { defineConfig } from 'vite';
|
|
9
|
+
|
|
10
|
+
import { graph } from './src/app';
|
|
11
|
+
|
|
12
|
+
export default defineConfig({
|
|
13
|
+
plugins: [
|
|
14
|
+
{
|
|
15
|
+
name: 'trails-surface',
|
|
16
|
+
configureServer(server) {
|
|
17
|
+
server.middlewares.use('/api', vite(createApp(graph)));
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Mount the middleware under the path segment you want Vite to delegate to Trails.
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ontrails/vite",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "git+https://github.com/outfitter-dev/trails.git",
|
|
7
|
+
"directory": "adapters/vite"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"src/**/*.ts",
|
|
11
|
+
"!src/**/__tests__/**",
|
|
12
|
+
"!src/**/*.test.ts",
|
|
13
|
+
"!src/**/*.test-d.ts",
|
|
14
|
+
"README.md",
|
|
15
|
+
"CHANGELOG.md"
|
|
16
|
+
],
|
|
17
|
+
"type": "module",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": "./src/index.ts",
|
|
20
|
+
"./package.json": "./package.json"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc -b",
|
|
24
|
+
"test": "bun test",
|
|
25
|
+
"typecheck": "tsc --noEmit",
|
|
26
|
+
"lint": "oxlint ./src",
|
|
27
|
+
"clean": "rm -rf dist *.tsbuildinfo"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@ontrails/core": "^0.2.0",
|
|
31
|
+
"@ontrails/hono": "^0.2.0",
|
|
32
|
+
"zod": "^4.3.5"
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
import { Readable } from 'node:stream';
|
|
3
|
+
import { pipeline } from 'node:stream/promises';
|
|
4
|
+
import type { ReadableStream as NodeReadableStream } from 'node:stream/web';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Fetch contract consumed by the Vite adapter when converting to middleware.
|
|
8
|
+
*/
|
|
9
|
+
export interface FetchSurface {
|
|
10
|
+
fetch(request: Request): Response | Promise<Response>;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Callback invoked when Connect middleware should continue execution. */
|
|
14
|
+
export type ViteMiddlewareNext = (error?: unknown) => void;
|
|
15
|
+
|
|
16
|
+
/** Connect-style middleware wrapper around a Trails fetch surface. */
|
|
17
|
+
export type ViteMiddleware = (
|
|
18
|
+
req: IncomingMessage,
|
|
19
|
+
res: ServerResponse,
|
|
20
|
+
next: ViteMiddlewareNext
|
|
21
|
+
) => void | Promise<void>;
|
|
22
|
+
|
|
23
|
+
type CookieReadableHeaders = Headers & {
|
|
24
|
+
readonly getAll?: (name: string) => string[];
|
|
25
|
+
readonly getSetCookie?: () => string[];
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const BODYLESS_METHODS = new Set(['GET', 'HEAD']);
|
|
29
|
+
|
|
30
|
+
const appendHeader = (
|
|
31
|
+
headers: Headers,
|
|
32
|
+
name: string,
|
|
33
|
+
value: string | readonly string[]
|
|
34
|
+
): void => {
|
|
35
|
+
if (typeof value === 'string') {
|
|
36
|
+
headers.append(name, value);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
for (const item of value) {
|
|
41
|
+
headers.append(name, item);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const toRequestHeaders = (req: IncomingMessage): Headers => {
|
|
46
|
+
const headers = new Headers();
|
|
47
|
+
|
|
48
|
+
for (const [name, value] of Object.entries(req.headers)) {
|
|
49
|
+
if (value === undefined) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
appendHeader(headers, name, value);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return headers;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const toRequestInit = (
|
|
60
|
+
req: IncomingMessage
|
|
61
|
+
): RequestInit & { duplex?: 'half' } => {
|
|
62
|
+
const method = req.method ?? 'GET';
|
|
63
|
+
const headers = toRequestHeaders(req);
|
|
64
|
+
|
|
65
|
+
if (BODYLESS_METHODS.has(method)) {
|
|
66
|
+
return { headers, method };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
body: Readable.toWeb(req) as unknown as BodyInit,
|
|
71
|
+
duplex: 'half',
|
|
72
|
+
headers,
|
|
73
|
+
method,
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const toRequest = (req: IncomingMessage): Request => {
|
|
78
|
+
const host = req.headers.host ?? 'localhost';
|
|
79
|
+
const url = new URL(req.url ?? '/', `http://${host}`);
|
|
80
|
+
return new Request(url, toRequestInit(req));
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const readSetCookieHeaders = (headers: Headers): readonly string[] => {
|
|
84
|
+
const cookieHeaders = headers as CookieReadableHeaders;
|
|
85
|
+
if (typeof cookieHeaders.getSetCookie === 'function') {
|
|
86
|
+
return cookieHeaders.getSetCookie();
|
|
87
|
+
}
|
|
88
|
+
if (typeof cookieHeaders.getAll === 'function') {
|
|
89
|
+
return cookieHeaders.getAll('set-cookie');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const value = headers.get('set-cookie');
|
|
93
|
+
return value === null ? [] : [value];
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const writeHeaders = (response: Response, res: ServerResponse): void => {
|
|
97
|
+
const setCookie = readSetCookieHeaders(response.headers);
|
|
98
|
+
if (setCookie.length > 0) {
|
|
99
|
+
res.setHeader('set-cookie', [...setCookie]);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
for (const [name, value] of response.headers) {
|
|
103
|
+
if (name.toLowerCase() === 'set-cookie') {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
res.setHeader(name, value);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const writeResponse = async (
|
|
111
|
+
req: IncomingMessage,
|
|
112
|
+
res: ServerResponse,
|
|
113
|
+
response: Response
|
|
114
|
+
): Promise<void> => {
|
|
115
|
+
res.statusCode = response.status;
|
|
116
|
+
if (response.statusText.length > 0) {
|
|
117
|
+
res.statusMessage = response.statusText;
|
|
118
|
+
}
|
|
119
|
+
writeHeaders(response, res);
|
|
120
|
+
|
|
121
|
+
if (req.method === 'HEAD' || response.body === null) {
|
|
122
|
+
res.end();
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const body = Readable.fromWeb(
|
|
127
|
+
response.body as unknown as NodeReadableStream<Uint8Array>
|
|
128
|
+
);
|
|
129
|
+
await pipeline(body, res);
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Convert a fetch-based HTTP surface into Vite/Connect middleware.
|
|
134
|
+
*
|
|
135
|
+
* Mount it under the path segment that should resolve through Trails:
|
|
136
|
+
*
|
|
137
|
+
* `server.middlewares.use('/api', vite(createApp(graph)))`
|
|
138
|
+
*/
|
|
139
|
+
export const vite =
|
|
140
|
+
(app: FetchSurface): ViteMiddleware =>
|
|
141
|
+
async (req, res, next) => {
|
|
142
|
+
try {
|
|
143
|
+
const response = await app.fetch(toRequest(req));
|
|
144
|
+
await writeResponse(req, res, response);
|
|
145
|
+
} catch (error: unknown) {
|
|
146
|
+
// oxlint-disable-next-line promise/prefer-await-to-callbacks -- Connect middleware reports errors through next(error)
|
|
147
|
+
next(error);
|
|
148
|
+
}
|
|
149
|
+
};
|