@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 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
+ };