@torpor/build 0.1.0 → 0.1.2
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 +13 -0
- package/dist/bin/index.cjs +198 -38
- package/dist/bin/index.cjs.map +1 -1
- package/dist/bin/index.js +11 -507
- package/dist/bin/index.js.map +1 -1
- package/dist/chunk-ENB7RXFX.js +669 -0
- package/dist/chunk-ENB7RXFX.js.map +1 -0
- package/dist/metafile-cjs.json +1 -1
- package/dist/metafile-esm.json +1 -1
- package/dist/run.cjs +755 -0
- package/dist/run.cjs.map +1 -0
- package/dist/run.d.cts +14 -0
- package/dist/run.d.ts +14 -0
- package/dist/run.js +16 -0
- package/dist/run.js.map +1 -0
- package/package.json +8 -3
- package/src/bin/index.ts +7 -43
- package/src/run.ts +6 -0
- package/src/site/run.ts +60 -0
- package/src/site/runBuild.ts +4 -5
- package/src/site/runDev.ts +3 -5
- package/tsup.config.ts +1 -0
|
@@ -0,0 +1,669 @@
|
|
|
1
|
+
import {
|
|
2
|
+
serverError
|
|
3
|
+
} from "./chunk-VAGHGWM5.js";
|
|
4
|
+
import {
|
|
5
|
+
prepareTemplate
|
|
6
|
+
} from "./chunk-V4XTDQEV.js";
|
|
7
|
+
import {
|
|
8
|
+
flattenHeaders
|
|
9
|
+
} from "./chunk-5X4T3PZN.js";
|
|
10
|
+
|
|
11
|
+
// src/site/runBuild.ts
|
|
12
|
+
import torpor from "@torpor/unplugin/vite";
|
|
13
|
+
import { existsSync, promises as fs } from "node:fs";
|
|
14
|
+
import path2 from "node:path";
|
|
15
|
+
import { build, defineConfig } from "vite";
|
|
16
|
+
|
|
17
|
+
// src/site/manifest.ts
|
|
18
|
+
import { readFileSync } from "node:fs";
|
|
19
|
+
import path from "node:path";
|
|
20
|
+
var moduleId = "@torpor/build/manifest";
|
|
21
|
+
function manifest(site, server = false) {
|
|
22
|
+
return {
|
|
23
|
+
name: "torpor-manifest",
|
|
24
|
+
resolveId: {
|
|
25
|
+
order: "pre",
|
|
26
|
+
handler(id) {
|
|
27
|
+
if (id === moduleId) {
|
|
28
|
+
return id;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
load(id) {
|
|
33
|
+
if (id === moduleId) {
|
|
34
|
+
return `
|
|
35
|
+
${!server ? "const load = { default: { load: true } };" : ""}
|
|
36
|
+
export default {
|
|
37
|
+
routes: [
|
|
38
|
+
${site.routes.map((r) => {
|
|
39
|
+
if (server || !/server\.(ts|js)$/.test(r.file)) {
|
|
40
|
+
return `{ path: "${r.path}", file: "${r.file}", type: ${r.type}, endPoint: ${server || !/server\.(ts|js)$/.test(r.file) ? `() => import(/* @vite-ignore */ "${path.join(site.root, r.file)}")` : "undefined"} }`;
|
|
41
|
+
} else {
|
|
42
|
+
const haveLoad = readFileSync(path.join(site.root, r.file)).includes("load:");
|
|
43
|
+
return `{ path: "${r.path}", file: "${r.file}", type: ${r.type}, endPoint: ${haveLoad ? "() => load" : "undefined"} }`;
|
|
44
|
+
}
|
|
45
|
+
}).join(",\n ")}
|
|
46
|
+
],
|
|
47
|
+
};
|
|
48
|
+
`;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/site/runBuild.ts
|
|
55
|
+
async function runBuild(site) {
|
|
56
|
+
const distFolder = path2.resolve(site.root, "dist");
|
|
57
|
+
if (existsSync(distFolder)) {
|
|
58
|
+
await fs.rm(distFolder, { recursive: true });
|
|
59
|
+
}
|
|
60
|
+
const clientFolder = path2.join(distFolder, "client");
|
|
61
|
+
const serverFolder = path2.join(distFolder, "server");
|
|
62
|
+
if (site.adapter.prebuild) {
|
|
63
|
+
await site.adapter.prebuild(site);
|
|
64
|
+
}
|
|
65
|
+
let siteHtml = path2.resolve(site.root, "src/site.html");
|
|
66
|
+
const siteFolder = path2.resolve(site.root, "./node_modules/@torpor/build/src/site/");
|
|
67
|
+
let clientScript = path2.join(siteFolder, "clientEntry.ts");
|
|
68
|
+
let serverScript = path2.join(siteFolder, "serverEntry.ts");
|
|
69
|
+
await build(
|
|
70
|
+
defineConfig({
|
|
71
|
+
plugins: [
|
|
72
|
+
manifest(site),
|
|
73
|
+
// @ts-ignore
|
|
74
|
+
torpor(),
|
|
75
|
+
...site.plugins
|
|
76
|
+
],
|
|
77
|
+
build: {
|
|
78
|
+
outDir: clientFolder,
|
|
79
|
+
rollupOptions: {
|
|
80
|
+
input: [
|
|
81
|
+
siteHtml,
|
|
82
|
+
clientScript,
|
|
83
|
+
...site.routes.filter((r) => !/server\.(ts|js)$/.test(r.file)).map((r) => path2.resolve(site.root, r.file))
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
ssrManifest: true
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
);
|
|
90
|
+
await build(
|
|
91
|
+
defineConfig({
|
|
92
|
+
plugins: [
|
|
93
|
+
manifest(site, true),
|
|
94
|
+
// @ts-ignore
|
|
95
|
+
torpor(),
|
|
96
|
+
...site.plugins
|
|
97
|
+
],
|
|
98
|
+
build: {
|
|
99
|
+
outDir: serverFolder,
|
|
100
|
+
rollupOptions: {
|
|
101
|
+
input: [serverScript, ...site.routes.map((r) => path2.resolve(site.root, r.file))]
|
|
102
|
+
},
|
|
103
|
+
ssr: serverScript
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
);
|
|
107
|
+
siteHtml = path2.join(clientFolder, "site.html");
|
|
108
|
+
await fs.rename(path2.join(clientFolder, "src", "site.html"), siteHtml);
|
|
109
|
+
await fs.rm(path2.join(clientFolder, "src"), { recursive: true });
|
|
110
|
+
if (site.adapter.postbuild) {
|
|
111
|
+
await site.adapter.postbuild(site);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// src/site/runDev.ts
|
|
116
|
+
import torpor2 from "@torpor/unplugin/vite";
|
|
117
|
+
import { configDotenv } from "dotenv";
|
|
118
|
+
import { promises as fs2 } from "node:fs";
|
|
119
|
+
import path3 from "node:path";
|
|
120
|
+
import { fileURLToPath } from "node:url";
|
|
121
|
+
import { createServer as createViteServer } from "vite";
|
|
122
|
+
|
|
123
|
+
// src/adapters/node/nodeMessageToNodeResponse.ts
|
|
124
|
+
import {
|
|
125
|
+
ServerResponse
|
|
126
|
+
} from "node:http";
|
|
127
|
+
import { PassThrough, Readable } from "node:stream";
|
|
128
|
+
function nodeMessageToNodeResponse(incomingMessage) {
|
|
129
|
+
const res = new ServerResponse(incomingMessage);
|
|
130
|
+
const passThrough = new PassThrough();
|
|
131
|
+
let handled = false;
|
|
132
|
+
const onReadable = (cb) => {
|
|
133
|
+
const handleReadable = () => {
|
|
134
|
+
if (handled) return;
|
|
135
|
+
handled = true;
|
|
136
|
+
cb({
|
|
137
|
+
readable: Readable.from(passThrough),
|
|
138
|
+
headers: res.getHeaders(),
|
|
139
|
+
status: res.statusCode
|
|
140
|
+
});
|
|
141
|
+
};
|
|
142
|
+
passThrough.once("readable", handleReadable);
|
|
143
|
+
passThrough.once("end", handleReadable);
|
|
144
|
+
};
|
|
145
|
+
passThrough.once("finish", () => {
|
|
146
|
+
res.emit("finish");
|
|
147
|
+
});
|
|
148
|
+
passThrough.once("close", () => {
|
|
149
|
+
res.destroy();
|
|
150
|
+
res.emit("close");
|
|
151
|
+
});
|
|
152
|
+
passThrough.on("drain", () => {
|
|
153
|
+
res.emit("drain");
|
|
154
|
+
});
|
|
155
|
+
res.write = passThrough.write.bind(passThrough);
|
|
156
|
+
res.end = passThrough.end.bind(passThrough);
|
|
157
|
+
res.writeHead = function writeHead(statusCode, statusMessage, headers) {
|
|
158
|
+
res.statusCode = statusCode;
|
|
159
|
+
if (typeof statusMessage === "object") {
|
|
160
|
+
headers = statusMessage;
|
|
161
|
+
statusMessage = void 0;
|
|
162
|
+
}
|
|
163
|
+
if (headers) {
|
|
164
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
165
|
+
if (value !== void 0) {
|
|
166
|
+
res.setHeader(key, value);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return res;
|
|
171
|
+
};
|
|
172
|
+
return {
|
|
173
|
+
res,
|
|
174
|
+
onReadable
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// src/adapters/node/readableToBuffer.ts
|
|
179
|
+
function readableToBuffer(req) {
|
|
180
|
+
return new Promise((resolve, reject) => {
|
|
181
|
+
const chunks = [];
|
|
182
|
+
req.on("data", (chunk) => {
|
|
183
|
+
chunks.push(chunk);
|
|
184
|
+
});
|
|
185
|
+
req.on("end", () => {
|
|
186
|
+
resolve(Buffer.concat(chunks));
|
|
187
|
+
});
|
|
188
|
+
req.on("error", (err) => {
|
|
189
|
+
reject(err);
|
|
190
|
+
});
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// src/adapters/node/requestToNodeMessage.ts
|
|
195
|
+
import { Readable as Readable2 } from "node:stream";
|
|
196
|
+
var DUMMY_BASE_URL = "http://localhost";
|
|
197
|
+
function requestToNodeMessage(request) {
|
|
198
|
+
const parsedUrl = new URL(request.url, DUMMY_BASE_URL);
|
|
199
|
+
const pathAndQuery = (parsedUrl.pathname || "") + (parsedUrl.search || "");
|
|
200
|
+
const body = (
|
|
201
|
+
/*request.body ? Readable.fromWeb(request.body as any) :*/
|
|
202
|
+
Readable2.from([])
|
|
203
|
+
);
|
|
204
|
+
return Object.assign(body, {
|
|
205
|
+
url: pathAndQuery,
|
|
206
|
+
method: request.method,
|
|
207
|
+
headers: Object.fromEntries(request.headers)
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// src/adapters/node/createMiddlewareHandler.ts
|
|
212
|
+
function createMiddlewareHandler(handler) {
|
|
213
|
+
return async (ev, next) => {
|
|
214
|
+
const req = requestToNodeMessage(ev.request);
|
|
215
|
+
const { res, onReadable } = nodeMessageToNodeResponse(req);
|
|
216
|
+
return new Promise(async (resolve, reject) => {
|
|
217
|
+
onReadable(async ({ readable, headers, status }) => {
|
|
218
|
+
const responseBody = statusCodesWithoutBody.includes(status) ? null : (
|
|
219
|
+
//(Readable.toWeb(readable) as ReadableStream);
|
|
220
|
+
// HACK: Chunked bodies are not being
|
|
221
|
+
// read correctly somewhere...
|
|
222
|
+
await readableToBuffer(readable)
|
|
223
|
+
);
|
|
224
|
+
ev.response = new Response(responseBody, {
|
|
225
|
+
status,
|
|
226
|
+
headers: flattenHeaders(headers)
|
|
227
|
+
});
|
|
228
|
+
resolve();
|
|
229
|
+
});
|
|
230
|
+
const cnext = async (error) => {
|
|
231
|
+
if (error) {
|
|
232
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
233
|
+
} else {
|
|
234
|
+
await next();
|
|
235
|
+
resolve();
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
try {
|
|
239
|
+
const handled = await handler(req, res, cnext);
|
|
240
|
+
if (handled === false) {
|
|
241
|
+
res.destroy();
|
|
242
|
+
resolve();
|
|
243
|
+
}
|
|
244
|
+
} catch (e) {
|
|
245
|
+
cnext(e);
|
|
246
|
+
}
|
|
247
|
+
});
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
var statusCodesWithoutBody = [
|
|
251
|
+
100,
|
|
252
|
+
// Continue
|
|
253
|
+
101,
|
|
254
|
+
// Switching Protocols
|
|
255
|
+
102,
|
|
256
|
+
// Processing (WebDAV)
|
|
257
|
+
103,
|
|
258
|
+
// Early Hints
|
|
259
|
+
204,
|
|
260
|
+
// No Content
|
|
261
|
+
205,
|
|
262
|
+
// Reset Content
|
|
263
|
+
304
|
|
264
|
+
// Not Modified
|
|
265
|
+
];
|
|
266
|
+
|
|
267
|
+
// src/site/pathToRegex.ts
|
|
268
|
+
function pathToRegex(path6) {
|
|
269
|
+
const pattern = path6.split("/").map((p) => {
|
|
270
|
+
return p.replace(/\[([^\/]+?)\]/, "(?<$1>[^\\/]+?)");
|
|
271
|
+
}).join("\\/").replaceAll("*", ".*");
|
|
272
|
+
return new RegExp(`^${pattern}$`);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// src/server/CookieHelper.ts
|
|
276
|
+
import { parse, serialize } from "cookie";
|
|
277
|
+
var CookieHelper = class {
|
|
278
|
+
request;
|
|
279
|
+
cookies = /* @__PURE__ */ new Map();
|
|
280
|
+
constructor(request) {
|
|
281
|
+
this.request = request;
|
|
282
|
+
}
|
|
283
|
+
get(name) {
|
|
284
|
+
if (this.cookies.has(name)) {
|
|
285
|
+
return this.cookies.get(name);
|
|
286
|
+
}
|
|
287
|
+
const header = this.request.headers.get("cookie");
|
|
288
|
+
return parse(header ?? "")[name];
|
|
289
|
+
}
|
|
290
|
+
set(name, value, options) {
|
|
291
|
+
options ??= {};
|
|
292
|
+
options.httpOnly ??= true;
|
|
293
|
+
options.secure ??= true;
|
|
294
|
+
options.sameSite ??= "lax";
|
|
295
|
+
this.cookies.set(name, serialize(name, value, options));
|
|
296
|
+
}
|
|
297
|
+
delete(name, options) {
|
|
298
|
+
options ??= {};
|
|
299
|
+
options.expires = /* @__PURE__ */ new Date(0);
|
|
300
|
+
this.cookies.set(name, serialize(name, "", options));
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
// src/server/HeaderHelper.ts
|
|
305
|
+
var HeaderHelper = class {
|
|
306
|
+
request;
|
|
307
|
+
headers = /* @__PURE__ */ new Map();
|
|
308
|
+
constructor(request) {
|
|
309
|
+
this.request = request;
|
|
310
|
+
}
|
|
311
|
+
get(name) {
|
|
312
|
+
if (this.headers.has(name)) {
|
|
313
|
+
return this.headers.get(name);
|
|
314
|
+
}
|
|
315
|
+
return this.request.headers.get(name) ?? void 0;
|
|
316
|
+
}
|
|
317
|
+
set(name, value) {
|
|
318
|
+
this.headers.set(name, value);
|
|
319
|
+
}
|
|
320
|
+
delete(name) {
|
|
321
|
+
this.headers.delete(name);
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
// src/server/ServerEvent.ts
|
|
326
|
+
var ServerEvent = class {
|
|
327
|
+
request;
|
|
328
|
+
response;
|
|
329
|
+
// TODO: Should we cast types??
|
|
330
|
+
params;
|
|
331
|
+
cookies;
|
|
332
|
+
headers;
|
|
333
|
+
constructor(request, params) {
|
|
334
|
+
this.request = request;
|
|
335
|
+
this.params = params;
|
|
336
|
+
this.cookies = new CookieHelper(request);
|
|
337
|
+
this.headers = new HeaderHelper(request);
|
|
338
|
+
}
|
|
339
|
+
addHeaders() {
|
|
340
|
+
if (!this.response) {
|
|
341
|
+
throw new Error("Response not created yet");
|
|
342
|
+
}
|
|
343
|
+
for (let cookie of this.cookies.cookies.values()) {
|
|
344
|
+
this.response.headers.append("set-cookie", cookie);
|
|
345
|
+
}
|
|
346
|
+
for (let header of this.headers.headers.entries()) {
|
|
347
|
+
this.response.headers.append(header[0], header[1]);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
// src/server/Server.ts
|
|
353
|
+
var noop = () => {
|
|
354
|
+
};
|
|
355
|
+
var Server = class {
|
|
356
|
+
// TODO: We don't use any of the routes, just add("*") in runDev/runBuild...
|
|
357
|
+
routes = [];
|
|
358
|
+
// TODO: We only use the Vite middleware here
|
|
359
|
+
middleware = [];
|
|
360
|
+
constructor() {
|
|
361
|
+
this.routes = [];
|
|
362
|
+
this.middleware = [];
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* The standard Fetch API method that should work in any runtime (including
|
|
366
|
+
* Node with polyfills).
|
|
367
|
+
* @returns
|
|
368
|
+
*/
|
|
369
|
+
fetch = async (input, init) => {
|
|
370
|
+
const request = new Request(input, init);
|
|
371
|
+
const url = new URL(request.url);
|
|
372
|
+
const match = this.match(url.pathname);
|
|
373
|
+
let ev = new ServerEvent(request, match?.params);
|
|
374
|
+
if (this.middleware.length) {
|
|
375
|
+
let buildNext2 = function(middleware, i) {
|
|
376
|
+
if (ev.response) {
|
|
377
|
+
return noop;
|
|
378
|
+
}
|
|
379
|
+
if (i < middleware.length - 1) {
|
|
380
|
+
let next = middleware[i + 1];
|
|
381
|
+
return async () => next(ev, buildNext2(middleware, i + 1));
|
|
382
|
+
} else {
|
|
383
|
+
return match ? async () => {
|
|
384
|
+
ev.response = await match.fn(ev);
|
|
385
|
+
} : noop;
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
var buildNext = buildNext2;
|
|
389
|
+
await this.middleware[0](ev, buildNext2(this.middleware, 0));
|
|
390
|
+
} else if (match) {
|
|
391
|
+
ev.response = await match.fn(ev);
|
|
392
|
+
} else {
|
|
393
|
+
return new Response(null, { status: 404 });
|
|
394
|
+
}
|
|
395
|
+
ev.response ??= new Response(null, { status: 200 });
|
|
396
|
+
ev.addHeaders();
|
|
397
|
+
return ev.response;
|
|
398
|
+
};
|
|
399
|
+
/**
|
|
400
|
+
* Adds a server function at a route path.
|
|
401
|
+
* @param path The route path pattern.
|
|
402
|
+
* @param fn The function to call when the pattern is matched.
|
|
403
|
+
* @returns
|
|
404
|
+
*/
|
|
405
|
+
add(path6, fn) {
|
|
406
|
+
this.routes.push(new RouteHandler(path6, fn));
|
|
407
|
+
return this;
|
|
408
|
+
}
|
|
409
|
+
match(path6) {
|
|
410
|
+
for (let handler of this.routes) {
|
|
411
|
+
let match = path6.match(handler.regex);
|
|
412
|
+
if (match) {
|
|
413
|
+
return {
|
|
414
|
+
fn: handler.fn,
|
|
415
|
+
params: match.groups
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
console.log(`Server path not found: ${path6}`);
|
|
420
|
+
}
|
|
421
|
+
// TODO:
|
|
422
|
+
//use(path: string, ...fn: MiddlewareFunction[])
|
|
423
|
+
use(...fn) {
|
|
424
|
+
this.middleware = this.middleware.concat(fn);
|
|
425
|
+
return this;
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
var RouteHandler = class {
|
|
429
|
+
path;
|
|
430
|
+
regex;
|
|
431
|
+
fn;
|
|
432
|
+
constructor(path6, fn) {
|
|
433
|
+
this.path = path6;
|
|
434
|
+
this.regex = pathToRegex(path6);
|
|
435
|
+
this.fn = fn;
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
// src/site/runDev.ts
|
|
440
|
+
var __dirname = path3.dirname(fileURLToPath(import.meta.url));
|
|
441
|
+
async function runDev(site) {
|
|
442
|
+
const server = new Server();
|
|
443
|
+
const vite = await createViteServer({
|
|
444
|
+
server: { middlewareMode: true },
|
|
445
|
+
appType: "custom",
|
|
446
|
+
plugins: [
|
|
447
|
+
manifest(site, true),
|
|
448
|
+
// @ts-ignore not sure...
|
|
449
|
+
torpor2(),
|
|
450
|
+
...site.plugins
|
|
451
|
+
]
|
|
452
|
+
});
|
|
453
|
+
const templateFile = path3.resolve(site.root, "src/site.html");
|
|
454
|
+
let template = await fs2.readFile(templateFile, "utf-8");
|
|
455
|
+
template = await vite.transformIndexHtml("", template);
|
|
456
|
+
const clientScript = path3.resolve(__dirname, "../../src/site/clientEntry.ts");
|
|
457
|
+
const serverScript = path3.resolve(__dirname, "../../src/site/serverEntry.ts");
|
|
458
|
+
template = prepareTemplate(template, clientScript);
|
|
459
|
+
server.use(createMiddlewareHandler(vite.middlewares));
|
|
460
|
+
server.add("*", async (ev) => {
|
|
461
|
+
try {
|
|
462
|
+
const { load } = await vite.ssrLoadModule(serverScript);
|
|
463
|
+
return await load(ev, template);
|
|
464
|
+
} catch (e) {
|
|
465
|
+
vite.ssrFixStacktrace(e);
|
|
466
|
+
return serverError(e);
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
configDotenv();
|
|
470
|
+
process.env.PROTOCOL ??= "http:";
|
|
471
|
+
process.env.HOST ??= "localhost";
|
|
472
|
+
process.env.PORT ??= "7059";
|
|
473
|
+
site.adapter.serve(server, site);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// src/site/runPreview.ts
|
|
477
|
+
import { configDotenv as configDotenv2 } from "dotenv";
|
|
478
|
+
import { existsSync as existsSync2, promises as fs3 } from "node:fs";
|
|
479
|
+
import path4 from "node:path";
|
|
480
|
+
|
|
481
|
+
// src/server/contentType.ts
|
|
482
|
+
function contentType(extension) {
|
|
483
|
+
return types[extension] || "application/octet-stream";
|
|
484
|
+
}
|
|
485
|
+
var types = {
|
|
486
|
+
".aac": "audio/aac",
|
|
487
|
+
".abw": "application/x-abiword",
|
|
488
|
+
".apng": "image/apng",
|
|
489
|
+
".arc": "application/x-freearc",
|
|
490
|
+
".avif": "image/avif",
|
|
491
|
+
".avi": "video/x-msvideo",
|
|
492
|
+
".azw": "application/vnd.amazon.ebook",
|
|
493
|
+
".bin": "application/octet-stream",
|
|
494
|
+
".bmp": "image/bmp",
|
|
495
|
+
".bz": "application/x-bzip",
|
|
496
|
+
".bz2": "application/x-bzip2",
|
|
497
|
+
".cda": "application/x-cdf",
|
|
498
|
+
".csh": "application/x-csh",
|
|
499
|
+
".css": "text/css",
|
|
500
|
+
".csv": "text/csv",
|
|
501
|
+
".doc": "application/msword",
|
|
502
|
+
".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
503
|
+
".eot": "application/vnd.ms-fontobject",
|
|
504
|
+
".epub": "application/epub+zip",
|
|
505
|
+
".gz": "application/gzip",
|
|
506
|
+
".gif": "image/gif",
|
|
507
|
+
".htm": "text/html",
|
|
508
|
+
".html": "text/html",
|
|
509
|
+
".ico": "image/vnd.microsoft.icon",
|
|
510
|
+
".ics": "text/calendar",
|
|
511
|
+
".jar": "application/java-archive",
|
|
512
|
+
".jpeg": "image/jpeg",
|
|
513
|
+
".jpg": "image/jpeg",
|
|
514
|
+
".js": "text/javascript",
|
|
515
|
+
".json": "application/json",
|
|
516
|
+
".jsonld": "application/ld+json",
|
|
517
|
+
".mid": "audio/midi",
|
|
518
|
+
".midi": "audio/midi",
|
|
519
|
+
".mjs": "text/javascript",
|
|
520
|
+
".mp3": "audio/mpeg",
|
|
521
|
+
".mp4": "video/mp4",
|
|
522
|
+
".mpeg": "video/mpeg",
|
|
523
|
+
".mpkg": "application/vnd.apple.installer+xml",
|
|
524
|
+
".odp": "application/vnd.oasis.opendocument.presentation",
|
|
525
|
+
".ods": "application/vnd.oasis.opendocument.spreadsheet",
|
|
526
|
+
".odt": "application/vnd.oasis.opendocument.text",
|
|
527
|
+
".oga": "audio/ogg",
|
|
528
|
+
".ogv": "video/ogg",
|
|
529
|
+
".ogx": "application/ogg",
|
|
530
|
+
".opus": "audio/ogg",
|
|
531
|
+
".otf": "font/otf",
|
|
532
|
+
".png": "image/png",
|
|
533
|
+
".pdf": "application/pdf",
|
|
534
|
+
".php": "application/x-httpd-php",
|
|
535
|
+
".ppt": "application/vnd.ms-powerpoint",
|
|
536
|
+
".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
537
|
+
".rar": "application/vnd.rar",
|
|
538
|
+
".rtf": "application/rtf",
|
|
539
|
+
".sh": "application/x-sh",
|
|
540
|
+
".svg": "image/svg+xml",
|
|
541
|
+
".tar": "application/x-tar",
|
|
542
|
+
".tif": "image/tiff",
|
|
543
|
+
".tiff": "image/tiff",
|
|
544
|
+
".ts": "video/mp2t",
|
|
545
|
+
".ttf": "font/ttf",
|
|
546
|
+
".txt": "text/plain",
|
|
547
|
+
".vsd": "application/vnd.visio",
|
|
548
|
+
".wav": "audio/wav",
|
|
549
|
+
".weba": "audio/webm",
|
|
550
|
+
".webm": "video/webm",
|
|
551
|
+
".webp": "image/webp",
|
|
552
|
+
".woff": "font/woff",
|
|
553
|
+
".woff2": "font/woff2",
|
|
554
|
+
".xhtml": "application/xhtml+xml",
|
|
555
|
+
".xls": "application/vnd.ms-excel",
|
|
556
|
+
".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
557
|
+
".xml": "application/xml",
|
|
558
|
+
".xul": "application/vnd.mozilla.xul+xml",
|
|
559
|
+
".zip": "application/zip",
|
|
560
|
+
".3gp": "video/3gpp",
|
|
561
|
+
".3g2": "video/3gpp2",
|
|
562
|
+
".7z": "application/x-7z-compressed"
|
|
563
|
+
};
|
|
564
|
+
|
|
565
|
+
// src/site/runPreview.ts
|
|
566
|
+
async function runPreview(site) {
|
|
567
|
+
await runBuild(site);
|
|
568
|
+
const distFolder = path4.resolve(site.root, "dist");
|
|
569
|
+
const clientFolder = path4.join(distFolder, "client");
|
|
570
|
+
const serverFolder = path4.join(distFolder, "server");
|
|
571
|
+
let clientScript = (await fs3.readdir(path4.join(clientFolder, "assets"))).find(
|
|
572
|
+
(f) => f.startsWith("clientEntry-")
|
|
573
|
+
);
|
|
574
|
+
if (!clientScript) {
|
|
575
|
+
throw new Error("clientEntry.js not found");
|
|
576
|
+
}
|
|
577
|
+
clientScript = `/assets/${clientScript}`;
|
|
578
|
+
let siteHtml = path4.join(clientFolder, "site.html");
|
|
579
|
+
let template = await fs3.readFile(siteHtml, "utf-8");
|
|
580
|
+
template = prepareTemplate(template, clientScript);
|
|
581
|
+
const server = new Server();
|
|
582
|
+
server.add("/assets/*", async (ev) => {
|
|
583
|
+
try {
|
|
584
|
+
const url = new URL(ev.request.url);
|
|
585
|
+
const file = path4.join(site.root, "dist", "client", url.pathname);
|
|
586
|
+
if (existsSync2(file)) {
|
|
587
|
+
return new Response(await fs3.readFile(file), {
|
|
588
|
+
status: 200,
|
|
589
|
+
headers: {
|
|
590
|
+
"Content-Type": contentType(path4.extname(file))
|
|
591
|
+
}
|
|
592
|
+
});
|
|
593
|
+
}
|
|
594
|
+
} catch (e) {
|
|
595
|
+
return serverError(e);
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
const serverScript = path4.resolve(serverFolder, "serverEntry.js");
|
|
599
|
+
server.add("*", async (ev) => {
|
|
600
|
+
try {
|
|
601
|
+
const { load } = await import(serverScript);
|
|
602
|
+
return await load(ev, template);
|
|
603
|
+
} catch (e) {
|
|
604
|
+
return serverError(e);
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
configDotenv2();
|
|
608
|
+
process.env.PROTOCOL ??= "http:";
|
|
609
|
+
process.env.HOST ??= "localhost";
|
|
610
|
+
process.env.PORT ??= "7059";
|
|
611
|
+
site.adapter.serve(server, site);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// src/site/run.ts
|
|
615
|
+
import fs4 from "node:fs";
|
|
616
|
+
import path5 from "node:path";
|
|
617
|
+
import { transformWithEsbuild } from "vite";
|
|
618
|
+
async function run(folder, mode) {
|
|
619
|
+
let configFile = "";
|
|
620
|
+
let deleteConfigFile = false;
|
|
621
|
+
const jsConfigFile = path5.join(folder, "site.config.js");
|
|
622
|
+
const tsConfigFile = path5.join(folder, "site.config.ts");
|
|
623
|
+
if (fs4.existsSync(jsConfigFile)) {
|
|
624
|
+
configFile = jsConfigFile;
|
|
625
|
+
} else if (fs4.existsSync(tsConfigFile)) {
|
|
626
|
+
configFile = path5.join(folder, "site.config.temp.js");
|
|
627
|
+
let source = (await transformWithEsbuild(fs4.readFileSync(tsConfigFile, "utf-8"), tsConfigFile, {
|
|
628
|
+
loader: "ts"
|
|
629
|
+
})).code;
|
|
630
|
+
fs4.writeFileSync(configFile, source);
|
|
631
|
+
deleteConfigFile = true;
|
|
632
|
+
} else {
|
|
633
|
+
throw new Error("site.config file not found");
|
|
634
|
+
}
|
|
635
|
+
const site = (await import(configFile)).default;
|
|
636
|
+
if (!site || !site.root || !site.routes) {
|
|
637
|
+
throw new Error("Invalid site in config file");
|
|
638
|
+
}
|
|
639
|
+
if (deleteConfigFile) {
|
|
640
|
+
fs4.rmSync(configFile);
|
|
641
|
+
}
|
|
642
|
+
switch (mode) {
|
|
643
|
+
case "dev": {
|
|
644
|
+
await runDev(site);
|
|
645
|
+
break;
|
|
646
|
+
}
|
|
647
|
+
case "build": {
|
|
648
|
+
await runBuild(site);
|
|
649
|
+
break;
|
|
650
|
+
}
|
|
651
|
+
case "preview": {
|
|
652
|
+
await runPreview(site);
|
|
653
|
+
break;
|
|
654
|
+
}
|
|
655
|
+
default: {
|
|
656
|
+
console.log("No mode passed, running in dev");
|
|
657
|
+
await runDev(site);
|
|
658
|
+
break;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
export {
|
|
664
|
+
runBuild,
|
|
665
|
+
runDev,
|
|
666
|
+
runPreview,
|
|
667
|
+
run
|
|
668
|
+
};
|
|
669
|
+
//# sourceMappingURL=chunk-ENB7RXFX.js.map
|