@foldkit/node 0.0.0-stage → 0.0.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/LICENSE +21 -0
- package/README.md +45 -2
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1 -0
- package/dist/node.d.ts +37 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +204 -0
- package/package.json +57 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Devin Jameson
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,46 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @foldkit/node
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`@foldkit/node` starts a built Foldkit server-rendered application on Node.
|
|
4
|
+
It reads `foldkit.build.json` to find the client output and Fetch handler.
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install @foldkit/node @effect/platform-node
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Serve a build
|
|
13
|
+
|
|
14
|
+
Build the application with `vite build`, then run a Node entry point such as:
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { Config, Option, String } from 'effect'
|
|
18
|
+
|
|
19
|
+
import { NodeRuntime } from '@effect/platform-node'
|
|
20
|
+
import * as Node from '@foldkit/node'
|
|
21
|
+
|
|
22
|
+
const port = Config.withDefault(Config.Port('PORT'), 3000)
|
|
23
|
+
const origin = Config.option(Config.String('ORIGIN')).pipe(
|
|
24
|
+
Config.map(Option.filter(String.isNonEmpty)),
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
NodeRuntime.runMain(Node.serve({ port, origin }))
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
`origin` is the public URL of the deployment. When it is `None`, the adapter
|
|
31
|
+
uses `http://localhost:<port>`. Set it behind a proxy or TLS terminator so the
|
|
32
|
+
server entry receives the public `Request.url`.
|
|
33
|
+
|
|
34
|
+
The adapter serves matching client files only for `GET` and `HEAD`. It sends
|
|
35
|
+
the Vite-base `index.html` path, such as `/app/index.html` for `/app/`, and
|
|
36
|
+
every request that does not match a static file to the Fetch handler. It does
|
|
37
|
+
not choose a `Cache-Control` policy or replace application 404 responses.
|
|
38
|
+
|
|
39
|
+
Pass `manifestPath` to `serve` when the manifest is not at
|
|
40
|
+
`dist/server/foldkit.build.json` relative to the process working directory.
|
|
41
|
+
When the server output is outside the Vite root, also pass `rootDirectory` so
|
|
42
|
+
the adapter can locate the client output recorded by the manifest.
|
|
43
|
+
|
|
44
|
+
For a Vite application built with a root-relative `base` such as `/app/`, pass
|
|
45
|
+
the same value as `basePath`. The adapter serves client files only under that
|
|
46
|
+
path and preserves it in URLs passed to the Fetch handler.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,WAAW,CAAA;AAEjC,YAAY,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { serve } from './node.js';
|
package/dist/node.d.ts
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Config, Effect, Option, PlatformError, Schema } from 'effect';
|
|
2
|
+
import { HttpServerError } from 'effect/http';
|
|
3
|
+
/** Configuration for a Node server that hosts a built Foldkit application. */
|
|
4
|
+
export type ServeOptions = Readonly<{
|
|
5
|
+
/** The port Config that selects the listening port. */
|
|
6
|
+
port: Config.Config<number>;
|
|
7
|
+
/**
|
|
8
|
+
* The origin Config for requests that reach the Fetch handler. Use `None`
|
|
9
|
+
* to derive `http://localhost:<port>` from the resolved port.
|
|
10
|
+
*/
|
|
11
|
+
origin: Config.Config<Option.Option<string>>;
|
|
12
|
+
/**
|
|
13
|
+
* The build manifest to read. Relative paths resolve from the process
|
|
14
|
+
* working directory. It defaults to `dist/server/foldkit.build.json`.
|
|
15
|
+
*/
|
|
16
|
+
manifestPath?: string;
|
|
17
|
+
/**
|
|
18
|
+
* The deployed directory that corresponds to the Vite root. Provide it when
|
|
19
|
+
* the manifest's server directory is outside that root. Relative paths
|
|
20
|
+
* resolve from the process working directory.
|
|
21
|
+
*/
|
|
22
|
+
rootDirectory?: string;
|
|
23
|
+
/**
|
|
24
|
+
* The root-relative Vite base path for client assets. It defaults to `/` and
|
|
25
|
+
* must end with `/`, such as `/app/`.
|
|
26
|
+
*/
|
|
27
|
+
basePath?: string;
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* Starts a Node HTTP server for a built Foldkit application.
|
|
31
|
+
*
|
|
32
|
+
* The server reads `foldkit.build.json`, serves its client directory for GET
|
|
33
|
+
* and HEAD requests, and sends every other application request to the emitted
|
|
34
|
+
* Web Fetch handler. Interrupting the returned Effect closes the HTTP server.
|
|
35
|
+
*/
|
|
36
|
+
export declare const serve: (options: ServeOptions) => Effect.Effect<never, Config.ConfigError | Error | PlatformError.PlatformError | Schema.SchemaError | HttpServerError.ServeError, never>;
|
|
37
|
+
//# sourceMappingURL=node.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../src/node.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,MAAM,EAIN,MAAM,EACN,aAAa,EAEb,MAAM,EACP,MAAM,QAAQ,CAAA;AACf,OAAO,EAGL,eAAe,EAIhB,MAAM,aAAa,CAAA;AAqCpB,8EAA8E;AAC9E,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC;IAClC,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IAC3B;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAA;IAC5C;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB,CAAC,CAAA;AAmTF;;;;;;GAMG;AACH,eAAO,MAAM,KAAK,YAAa,YAAY,4IACP,CAAA"}
|
package/dist/node.js
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { Effect, FileSystem, Layer, Match, Option, PlatformError, Predicate, Schema, } from 'effect';
|
|
2
|
+
import { HttpPlatform, HttpServer, HttpServerRequest, HttpServerResponse, HttpStaticServer, } from 'effect/http';
|
|
3
|
+
import { Server } from 'foldkit/experimental';
|
|
4
|
+
import { readFile } from 'node:fs/promises';
|
|
5
|
+
import { createServer } from 'node:http';
|
|
6
|
+
import { dirname, isAbsolute, posix, relative, resolve, sep } from 'node:path';
|
|
7
|
+
import { Readable } from 'node:stream';
|
|
8
|
+
import { ReadableStream } from 'node:stream/web';
|
|
9
|
+
import { pathToFileURL } from 'node:url';
|
|
10
|
+
import { NodeHttpPlatform, NodeHttpServer, NodeHttpServerRequest, NodeServices, } from '@effect/platform-node';
|
|
11
|
+
const DEFAULT_MANIFEST_PATH = 'dist/server/foldkit.build.json';
|
|
12
|
+
const FoldkitBuildManifest = Schema.Struct({
|
|
13
|
+
schemaVersion: Schema.Literals([1]),
|
|
14
|
+
client: Schema.String,
|
|
15
|
+
server: Schema.String,
|
|
16
|
+
serverEntry: Schema.String,
|
|
17
|
+
prerendered: Schema.Array(Schema.String),
|
|
18
|
+
});
|
|
19
|
+
const isFetchHandler = (value) => Predicate.hasProperty(value, 'fetch') && Predicate.isFunction(value.fetch);
|
|
20
|
+
const isFetchModule = (value) => Predicate.hasProperty(value, 'default') && isFetchHandler(value.default);
|
|
21
|
+
const isRouteNotFound = (error) => error.reason._tag === 'RouteNotFound';
|
|
22
|
+
const hostSettledResponse = () => HttpServerResponse.setHeader(HttpServerResponse.empty({
|
|
23
|
+
status: Server.HOST_METHOD_ANSWERS.refusedStatus,
|
|
24
|
+
}), 'allow', Server.HOST_METHOD_ANSWERS.allow);
|
|
25
|
+
const basePathFrom = (basePath) => {
|
|
26
|
+
const resolvedBasePath = basePath ?? '/';
|
|
27
|
+
let url;
|
|
28
|
+
try {
|
|
29
|
+
url = new URL(resolvedBasePath, 'http://localhost');
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
throw new Error('basePath must be a root-relative path ending with `/`');
|
|
33
|
+
}
|
|
34
|
+
if (!resolvedBasePath.startsWith('/') ||
|
|
35
|
+
resolvedBasePath.startsWith('//') ||
|
|
36
|
+
resolvedBasePath.includes('\\') ||
|
|
37
|
+
!resolvedBasePath.endsWith('/') ||
|
|
38
|
+
url.origin !== 'http://localhost' ||
|
|
39
|
+
url.search !== '' ||
|
|
40
|
+
url.hash !== '') {
|
|
41
|
+
throw new Error('basePath must be a root-relative path ending with `/`');
|
|
42
|
+
}
|
|
43
|
+
return url.pathname;
|
|
44
|
+
};
|
|
45
|
+
const staticPathFor = (pathname, basePath) => {
|
|
46
|
+
if (basePath === '/') {
|
|
47
|
+
return pathname;
|
|
48
|
+
}
|
|
49
|
+
if (!pathname.startsWith(basePath)) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
return `/${pathname.slice(basePath.length)}`;
|
|
53
|
+
};
|
|
54
|
+
const decodeManifest = (content) => Effect.try({
|
|
55
|
+
try: () => JSON.parse(content),
|
|
56
|
+
catch: cause => new Error('foldkit.build.json is not valid JSON', { cause }),
|
|
57
|
+
}).pipe(Effect.flatMap(Schema.decodeUnknownEffect(FoldkitBuildManifest)));
|
|
58
|
+
const buildPaths = (manifestPath, manifest, rootDirectory) => {
|
|
59
|
+
const serverDirectory = dirname(manifestPath);
|
|
60
|
+
const normalizedServerDirectory = posix.normalize(manifest.server);
|
|
61
|
+
if (rootDirectory === undefined &&
|
|
62
|
+
(normalizedServerDirectory === '..' ||
|
|
63
|
+
normalizedServerDirectory.startsWith('../'))) {
|
|
64
|
+
throw new Error('foldkit.build.json describes a server directory outside the Vite root. Pass rootDirectory so @foldkit/node can locate the client output.');
|
|
65
|
+
}
|
|
66
|
+
const resolvedRootDirectory = rootDirectory === undefined
|
|
67
|
+
? resolve(serverDirectory, relative(manifest.server, '.'))
|
|
68
|
+
: resolve(process.cwd(), rootDirectory);
|
|
69
|
+
const expectedServerDirectory = resolve(resolvedRootDirectory, manifest.server);
|
|
70
|
+
if (expectedServerDirectory !== serverDirectory) {
|
|
71
|
+
throw new Error(`rootDirectory resolves ${manifest.server} to ${expectedServerDirectory}, but the manifest is at ${serverDirectory}`);
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
clientDirectory: resolve(resolvedRootDirectory, manifest.client),
|
|
75
|
+
fetchHandlerPath: resolve(serverDirectory, manifest.serverEntry),
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
const readBuildPaths = (manifestPath, rootDirectory) => Effect.tryPromise({
|
|
79
|
+
try: () => readFile(manifestPath, 'utf8'),
|
|
80
|
+
catch: cause => new Error(`could not read Foldkit build manifest at ${manifestPath}`, {
|
|
81
|
+
cause,
|
|
82
|
+
}),
|
|
83
|
+
}).pipe(Effect.flatMap(decodeManifest), Effect.map(manifest => buildPaths(manifestPath, manifest, rootDirectory)));
|
|
84
|
+
const loadFetchHandler = (fetchHandlerPath) => Effect.tryPromise({
|
|
85
|
+
try: () => import(pathToFileURL(fetchHandlerPath).href),
|
|
86
|
+
catch: cause => new Error(`could not load the Foldkit fetch handler at ${fetchHandlerPath}. Run \`vite build\` first.`, { cause }),
|
|
87
|
+
}).pipe(Effect.flatMap(loaded => isFetchModule(loaded)
|
|
88
|
+
? Effect.succeed(loaded.default)
|
|
89
|
+
: Effect.fail(new Error(`${fetchHandlerPath} must default-export a Web fetch handler`))));
|
|
90
|
+
const fetchResponse = (app, request, requestUrl) => Effect.gen(function* () {
|
|
91
|
+
const signal = yield* Effect.abortSignal;
|
|
92
|
+
const webRequest = yield* HttpServerRequest.toWeb(request, { signal });
|
|
93
|
+
const response = yield* Effect.promise(() => app.fetch(new Request(requestUrl, webRequest)));
|
|
94
|
+
const headers = new Headers(response.headers);
|
|
95
|
+
const setCookieHeaders = headers.getSetCookie();
|
|
96
|
+
headers.delete('set-cookie');
|
|
97
|
+
if (setCookieHeaders.length > 0) {
|
|
98
|
+
NodeHttpServerRequest.toServerResponse(request).setHeader('set-cookie', setCookieHeaders);
|
|
99
|
+
}
|
|
100
|
+
const responseOptions = {
|
|
101
|
+
status: response.status,
|
|
102
|
+
statusText: response.statusText,
|
|
103
|
+
headers,
|
|
104
|
+
};
|
|
105
|
+
if (response.body === null) {
|
|
106
|
+
return HttpServerResponse.empty(responseOptions);
|
|
107
|
+
}
|
|
108
|
+
const webReader = response.body.getReader();
|
|
109
|
+
const nodeBody = Readable.fromWeb(new ReadableStream({
|
|
110
|
+
async pull(controller) {
|
|
111
|
+
const chunk = await webReader.read();
|
|
112
|
+
if (chunk.done) {
|
|
113
|
+
controller.close();
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
controller.enqueue(chunk.value);
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
cancel: reason => webReader.cancel(reason),
|
|
120
|
+
}));
|
|
121
|
+
const nodeResponse = NodeHttpServerRequest.toServerResponse(request);
|
|
122
|
+
const destroyBody = () => nodeBody.destroy();
|
|
123
|
+
nodeResponse.once('close', destroyBody);
|
|
124
|
+
nodeBody.once('close', () => nodeResponse.off('close', destroyBody));
|
|
125
|
+
if (signal.aborted) {
|
|
126
|
+
nodeBody.destroy();
|
|
127
|
+
}
|
|
128
|
+
return HttpServerResponse.raw(nodeBody, responseOptions);
|
|
129
|
+
});
|
|
130
|
+
const confinedStaticFiles = (clientDirectory) => Effect.gen(function* () {
|
|
131
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
132
|
+
const httpPlatform = yield* HttpPlatform.HttpPlatform;
|
|
133
|
+
const root = yield* fileSystem.realPath(clientDirectory);
|
|
134
|
+
const confinedRealPath = (path) => Effect.flatMap(fileSystem.realPath(path), canonicalPath => {
|
|
135
|
+
const fromRoot = relative(root, canonicalPath);
|
|
136
|
+
const isContained = fromRoot === '' ||
|
|
137
|
+
(fromRoot !== '..' &&
|
|
138
|
+
!fromRoot.startsWith(`..${sep}`) &&
|
|
139
|
+
!isAbsolute(fromRoot));
|
|
140
|
+
if (isContained) {
|
|
141
|
+
return Effect.succeed(canonicalPath);
|
|
142
|
+
}
|
|
143
|
+
return Effect.fail(PlatformError.systemError({
|
|
144
|
+
_tag: 'NotFound',
|
|
145
|
+
module: 'FileSystem',
|
|
146
|
+
method: 'realPath',
|
|
147
|
+
pathOrDescriptor: path,
|
|
148
|
+
}));
|
|
149
|
+
});
|
|
150
|
+
const confinedFileSystem = FileSystem.FileSystem.of({
|
|
151
|
+
...fileSystem,
|
|
152
|
+
stat: path => Effect.flatMap(confinedRealPath(path), fileSystem.stat),
|
|
153
|
+
});
|
|
154
|
+
const confinedPlatform = HttpPlatform.HttpPlatform.of({
|
|
155
|
+
...httpPlatform,
|
|
156
|
+
fileResponse: (path, options) => Effect.flatMap(confinedRealPath(path), canonicalPath => httpPlatform.fileResponse(canonicalPath, options)),
|
|
157
|
+
});
|
|
158
|
+
return yield* HttpStaticServer.make({ root, index: undefined }).pipe(Effect.provideService(FileSystem.FileSystem, confinedFileSystem), Effect.provideService(HttpPlatform.HttpPlatform, confinedPlatform));
|
|
159
|
+
});
|
|
160
|
+
const makeHandler = (options) => Effect.gen(function* () {
|
|
161
|
+
const port = yield* options.port;
|
|
162
|
+
const origin = Option.getOrElse(yield* options.origin, () => `http://localhost:${globalThis.String(port)}`);
|
|
163
|
+
const manifestPath = resolve(process.cwd(), options.manifestPath ?? DEFAULT_MANIFEST_PATH);
|
|
164
|
+
const paths = yield* readBuildPaths(manifestPath, options.rootDirectory);
|
|
165
|
+
const app = yield* loadFetchHandler(paths.fetchHandlerPath);
|
|
166
|
+
const basePath = basePathFrom(options.basePath);
|
|
167
|
+
const staticFiles = yield* confinedStaticFiles(paths.clientDirectory);
|
|
168
|
+
return HttpServerRequest.HttpServerRequest.use(request => {
|
|
169
|
+
const requestUrl = Server.resolveRequestUrl(request.url, origin);
|
|
170
|
+
if (requestUrl === undefined) {
|
|
171
|
+
return Effect.succeed(HttpServerResponse.empty({ status: 400 }));
|
|
172
|
+
}
|
|
173
|
+
const resolved = new URL(requestUrl);
|
|
174
|
+
const fetchRequest = request.modify({
|
|
175
|
+
url: `${resolved.pathname}${resolved.search}`,
|
|
176
|
+
});
|
|
177
|
+
const staticPath = staticPathFor(resolved.pathname, basePath);
|
|
178
|
+
const staticRequest = staticPath === undefined
|
|
179
|
+
? undefined
|
|
180
|
+
: request.modify({ url: `${staticPath}${resolved.search}` });
|
|
181
|
+
const response = Match.value(fetchRequest.method).pipe(Match.whenOr('GET', 'HEAD', () => {
|
|
182
|
+
if (staticRequest === undefined ||
|
|
183
|
+
Server.resolvesToIndexHtml(staticRequest.url)) {
|
|
184
|
+
return fetchResponse(app, fetchRequest, requestUrl);
|
|
185
|
+
}
|
|
186
|
+
return staticFiles.pipe(Effect.catchIf(isRouteNotFound, () => fetchResponse(app, fetchRequest, requestUrl)));
|
|
187
|
+
}), Match.orElse(() => {
|
|
188
|
+
if (Server.isHostSettledMethod(fetchRequest.method)) {
|
|
189
|
+
return Effect.succeed(hostSettledResponse());
|
|
190
|
+
}
|
|
191
|
+
return fetchResponse(app, fetchRequest, requestUrl);
|
|
192
|
+
}));
|
|
193
|
+
return Effect.provideService(response, HttpServerRequest.HttpServerRequest, staticRequest ?? fetchRequest);
|
|
194
|
+
}).pipe(Effect.interruptible);
|
|
195
|
+
});
|
|
196
|
+
const serverLayer = (options) => Layer.unwrap(Effect.map(makeHandler(options), handler => HttpServer.serve(handler))).pipe(HttpServer.withLogAddress, Layer.provide(NodeHttpServer.layerConfig(createServer, { port: options.port })), Layer.provide(NodeHttpPlatform.layer), Layer.provide(NodeServices.layer));
|
|
197
|
+
/**
|
|
198
|
+
* Starts a Node HTTP server for a built Foldkit application.
|
|
199
|
+
*
|
|
200
|
+
* The server reads `foldkit.build.json`, serves its client directory for GET
|
|
201
|
+
* and HEAD requests, and sends every other application request to the emitted
|
|
202
|
+
* Web Fetch handler. Interrupting the returned Effect closes the HTTP server.
|
|
203
|
+
*/
|
|
204
|
+
export const serve = (options) => Layer.launch(serverLayer(options));
|
package/package.json
CHANGED
|
@@ -1,6 +1,60 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@foldkit/node",
|
|
3
|
-
"version": "0.0.0
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "Node.js host adapter for Foldkit server-rendered applications",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"sideEffects": false,
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@effect/platform-node": "4.0.0"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"effect": "4.0.0",
|
|
24
|
+
"foldkit": ">=0.165.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@types/node": "26.4.0",
|
|
28
|
+
"effect": "4.0.0",
|
|
29
|
+
"rimraf": "^6.1.3",
|
|
30
|
+
"typescript": "^7.0.2",
|
|
31
|
+
"vitest": "^4.1.11",
|
|
32
|
+
"foldkit": "0.166.0"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"foldkit",
|
|
36
|
+
"node",
|
|
37
|
+
"server-rendering",
|
|
38
|
+
"ssr"
|
|
39
|
+
],
|
|
40
|
+
"author": "Devin Jameson",
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "https://github.com/foldkit/foldkit.git",
|
|
45
|
+
"directory": "packages/node"
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public"
|
|
49
|
+
},
|
|
50
|
+
"engines": {
|
|
51
|
+
"node": ">=20.19.0"
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"clean": "rimraf dist *.tsbuildinfo",
|
|
55
|
+
"build": "pnpm run clean && tsc -b tsconfig.build.json",
|
|
56
|
+
"watch": "tsc -b tsconfig.build.json --watch",
|
|
57
|
+
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json",
|
|
58
|
+
"test": "vitest run"
|
|
59
|
+
}
|
|
6
60
|
}
|