@spirobel/mininext 0.6.0 → 0.7.1
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/dist/mininext.d.ts +6 -0
- package/dist/mininext.js +32 -13
- package/dist/url.d.ts +62 -31
- package/dist/url.js +156 -141
- package/package.json +4 -4
package/dist/mininext.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
/// <reference types="bun-types" />
|
|
2
2
|
/// <reference types="bun-types" />
|
|
3
|
+
/// <reference types="bun-types" />
|
|
4
|
+
/// <reference types="bun-types" />
|
|
5
|
+
/// <reference types="bun-types" />
|
|
6
|
+
/// <reference types="bun-types" />
|
|
7
|
+
/// <reference types="bun-types" />
|
|
8
|
+
/// <reference types="bun-types" />
|
|
3
9
|
import { url, Mini, has, type HtmlHandler } from "./url";
|
|
4
10
|
import { isError, HtmlString, BasedHtml, head, commonHead, cssReset, basedHtml as html } from "./html";
|
|
5
11
|
import { type Server, type WebSocketHandler } from "bun";
|
package/dist/mininext.js
CHANGED
|
@@ -66,33 +66,53 @@ const nodeHttpsPlugin = {
|
|
|
66
66
|
},
|
|
67
67
|
};
|
|
68
68
|
async function buildBackend(backendPath = "backend/backend.ts") {
|
|
69
|
-
global.
|
|
70
|
-
global.FrontendScripts = [];
|
|
69
|
+
global.bundledFrontends = {};
|
|
71
70
|
global.bundledSVGs = {};
|
|
72
71
|
const i = await import(path.resolve(projectRoot(), backendPath));
|
|
73
72
|
for (const frontend of url.getFrontends()) {
|
|
74
|
-
const firstPlaceToLook = path.resolve(path.dirname(frontend.callerPath), `frontend/${frontend.
|
|
75
|
-
const secondPlaceToLook = path.resolve(projectRoot(), `frontend/${frontend.
|
|
73
|
+
const firstPlaceToLook = path.resolve(path.dirname(frontend.callerPath), `frontend/${frontend.frontendFilePath}`);
|
|
74
|
+
const secondPlaceToLook = path.resolve(projectRoot(), `frontend/${frontend.frontendFilePath}`);
|
|
76
75
|
const frontEndPath = (await Bun.file(firstPlaceToLook).exists())
|
|
77
76
|
? firstPlaceToLook
|
|
78
77
|
: secondPlaceToLook;
|
|
79
78
|
try {
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
79
|
+
const frontendResult = await $ `bun run build.ts frontend ${frontEndPath}`.json();
|
|
80
|
+
bundledFrontends[`/${frontendResult.url}`] = {
|
|
81
|
+
frontendContent: frontendResult.script,
|
|
82
|
+
frontendFilePath: frontend.frontendFilePath,
|
|
83
|
+
position: frontend.position,
|
|
84
|
+
};
|
|
83
85
|
}
|
|
84
86
|
catch (error) {
|
|
87
|
+
if (error &&
|
|
88
|
+
typeof error === "object" &&
|
|
89
|
+
"exitCode" in error &&
|
|
90
|
+
"stdout" in error &&
|
|
91
|
+
"stderr" in error &&
|
|
92
|
+
error.stdout instanceof Buffer &&
|
|
93
|
+
error.stderr instanceof Buffer) {
|
|
94
|
+
console.error(`Failed with exit code: ${error.exitCode}`);
|
|
95
|
+
console.error("Standard Output:", error.stdout.toString());
|
|
96
|
+
console.error("Standard Error:", error.stderr.toString());
|
|
97
|
+
}
|
|
85
98
|
console.log(await $ `bun run build.ts frontend ${frontEndPath}`.text());
|
|
86
99
|
}
|
|
87
100
|
}
|
|
88
|
-
for (const
|
|
89
|
-
const
|
|
90
|
-
const
|
|
101
|
+
for (const svg of url.getSvgs()) {
|
|
102
|
+
const firstPlaceToLook = path.resolve(path.dirname(svg.callerPath), `svgs/${svg.svgFilePath}`);
|
|
103
|
+
const secondPlaceToLook = path.resolve(projectRoot(), `${svg.svgFilePath}`);
|
|
104
|
+
const svgResolvedFilePath = (await Bun.file(firstPlaceToLook).exists())
|
|
105
|
+
? firstPlaceToLook
|
|
106
|
+
: secondPlaceToLook;
|
|
107
|
+
const parsedSvgPath = path.parse(svgResolvedFilePath);
|
|
108
|
+
const svgContent = Bun.file(svgResolvedFilePath);
|
|
91
109
|
const svgHash = Bun.hash(await svgContent.arrayBuffer());
|
|
92
110
|
const svgUrl = `/${parsedSvgPath.name}-${svgHash}.svg`;
|
|
93
111
|
bundledSVGs[svgUrl] = {
|
|
94
112
|
svgContent: await svgContent.text(),
|
|
95
|
-
|
|
113
|
+
svgFilePath: svg.svgFilePath,
|
|
114
|
+
position: svg.position,
|
|
115
|
+
options: svg.options,
|
|
96
116
|
};
|
|
97
117
|
}
|
|
98
118
|
const res = await Bun.build({
|
|
@@ -102,8 +122,7 @@ async function buildBackend(backendPath = "backend/backend.ts") {
|
|
|
102
122
|
minify: Bun.argv[2] === "dev" ? false : true, //production
|
|
103
123
|
target: "bun",
|
|
104
124
|
define: {
|
|
105
|
-
|
|
106
|
-
FrontendScriptUrls: JSON.stringify(FrontendScriptUrls),
|
|
125
|
+
bundledFrontends: JSON.stringify(bundledFrontends),
|
|
107
126
|
bundledSVGs: JSON.stringify(bundledSVGs),
|
|
108
127
|
},
|
|
109
128
|
});
|
package/dist/url.d.ts
CHANGED
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
/// <reference types="bun-types" />
|
|
2
2
|
/// <reference types="bun-types" />
|
|
3
|
-
|
|
3
|
+
/// <reference types="bun-types" />
|
|
4
|
+
/// <reference types="bun-types" />
|
|
5
|
+
/// <reference types="bun-types" />
|
|
6
|
+
/// <reference types="bun-types" />
|
|
7
|
+
/// <reference types="bun-types" />
|
|
8
|
+
/// <reference types="bun-types" />
|
|
9
|
+
import type { Server, WebSocketHandler, RouterTypes, BunRequest } from "bun";
|
|
4
10
|
import { html, json, dangerjson, HtmlString } from "./html";
|
|
5
11
|
import { BasedHtml, type DangerJsonInHtml, type JsonString, type JsonStringValues } from "./html";
|
|
12
|
+
export type HTTPMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH" | "HEAD" | "OPTIONS";
|
|
13
|
+
export type MiniNextRouteHandlerObject<T extends string> = {
|
|
14
|
+
[K in HTTPMethod]?: HtmlHandler<unknown, T>;
|
|
15
|
+
};
|
|
16
|
+
export type MiniNextRouteValue<T extends string> = HtmlHandler<unknown, T> | MiniNextRouteHandlerObject<T>;
|
|
17
|
+
export type BunRoutes<R extends {
|
|
18
|
+
[K in keyof R]: RouterTypes.RouteValue<Extract<K, string>>;
|
|
19
|
+
}> = R;
|
|
6
20
|
/**
|
|
7
21
|
* A helper function that helps narrow unknown objects
|
|
8
22
|
* @param object - the object of type unknown that is to be narrowed
|
|
@@ -43,13 +57,13 @@ export type NamedFormHandlerReturnType<X> = HandlerReturnType | Promise<HandlerR
|
|
|
43
57
|
* const {html,json, css, data, req, form, link, svg, deliver, route, params, header, head } = mini //pull everything out of the mini handbag
|
|
44
58
|
* ```
|
|
45
59
|
*/
|
|
46
|
-
export declare class Mini<X = unknown> {
|
|
60
|
+
export declare class Mini<X = unknown, ROUTE extends string = ""> {
|
|
47
61
|
html: typeof html<X>;
|
|
48
62
|
css: typeof html<X>;
|
|
49
63
|
json: typeof json<X>;
|
|
50
64
|
dangerjson: typeof dangerjson<X>;
|
|
51
65
|
data: X;
|
|
52
|
-
req:
|
|
66
|
+
req: BunRequest<ROUTE>;
|
|
53
67
|
head: (head: HtmlHandler | HtmlString) => undefined;
|
|
54
68
|
headers: (headers: HeadersInit, overwrite?: boolean) => undefined;
|
|
55
69
|
options: (options: ResponseInit) => undefined;
|
|
@@ -71,14 +85,19 @@ export declare class Mini<X = unknown> {
|
|
|
71
85
|
* const {html,json, css, data, req, form, link, svg, deliver, route, params, header, head } = mini //pull everything out of the mini handbag
|
|
72
86
|
* ```
|
|
73
87
|
*/
|
|
74
|
-
export type HtmlHandler<Y = unknown> = ((mini: Mini<Y>) => LazyHandlerReturnType) | (() => LazyHandlerReturnType);
|
|
88
|
+
export type HtmlHandler<Y = unknown, ROUTE extends string = ""> = ((mini: Mini<Y, ROUTE>) => LazyHandlerReturnType) | (() => LazyHandlerReturnType);
|
|
75
89
|
export type NamedFormHandler<Y = unknown, Z = undefined> = ((mini: Mini<Y>) => NamedFormHandlerReturnType<Z>) | (() => NamedFormHandlerReturnType<Z>);
|
|
76
90
|
declare global {
|
|
77
|
-
var
|
|
78
|
-
|
|
91
|
+
var bundledFrontends: Record<string, {
|
|
92
|
+
frontendFilePath: string;
|
|
93
|
+
frontendContent: string;
|
|
94
|
+
position: number;
|
|
95
|
+
}>;
|
|
79
96
|
var bundledSVGs: Record<string, {
|
|
80
97
|
svgContent: string;
|
|
81
|
-
|
|
98
|
+
svgFilePath: string;
|
|
99
|
+
options: ResponseInit;
|
|
100
|
+
position: number;
|
|
82
101
|
}>;
|
|
83
102
|
}
|
|
84
103
|
export type ScriptTag = (...params: any[]) => Promise<HtmlString>;
|
|
@@ -88,22 +107,40 @@ interface LinkSettings {
|
|
|
88
107
|
export declare class url {
|
|
89
108
|
static websocket: WebSocketHandler | undefined;
|
|
90
109
|
static server: Server;
|
|
110
|
+
static routes: BunRoutes<{}>;
|
|
91
111
|
static direct_handlers_html: Map<string, HtmlHandler>;
|
|
92
112
|
private static frontends;
|
|
93
113
|
private static svgs;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
114
|
+
/**
|
|
115
|
+
* This function takes care of bundling your svg (icons?) into the webapp
|
|
116
|
+
* they will have a hash in the name to break the cache when needed
|
|
117
|
+
* @param svgFilePath first place to look: svgs folder in the same path the calling file, after that path from project root.
|
|
118
|
+
* @param options ResponseInit, default headers for an svg
|
|
119
|
+
* @returns url to the svg
|
|
120
|
+
*/
|
|
121
|
+
static svg(svgFilePath: string, options?: ResponseInit): string | undefined;
|
|
122
|
+
/**
|
|
123
|
+
* this function helps you build frontends with any kind of framework (no framework at all) and get the bundle
|
|
124
|
+
* @param path first place to look: frontend folder in the same path the calling file, after that /frontend path from project root.
|
|
125
|
+
* @param snippet this is handy to pass in a piece of html that often goes along with a certain frontend
|
|
126
|
+
* @returns a html script element with the bundled frontend as the src
|
|
127
|
+
*/
|
|
128
|
+
static frontend<X>(frontendFilePath: string, snippet?: BasedHtml): HtmlString;
|
|
129
|
+
static frontend<X>(frontendFilePath: string, snippet?: HtmlHandler<X>): (mini: Mini<X>) => HtmlString;
|
|
97
130
|
/**
|
|
98
131
|
* This is used by the frontend bundler in order to find all frontends and their corresponding script files.
|
|
99
132
|
*/
|
|
100
133
|
static getFrontends(): {
|
|
101
|
-
|
|
134
|
+
frontendFilePath: string;
|
|
102
135
|
callerPath: string;
|
|
136
|
+
position: number;
|
|
137
|
+
}[];
|
|
138
|
+
static getSvgs(): {
|
|
139
|
+
svgFilePath: string;
|
|
140
|
+
callerPath: string;
|
|
141
|
+
position: number;
|
|
142
|
+
options: ResponseInit;
|
|
103
143
|
}[];
|
|
104
|
-
static getSvgPaths(): string[];
|
|
105
|
-
static serveFrontend(req: Request): Response | undefined;
|
|
106
|
-
static serveSvg(req: Request): Response | undefined;
|
|
107
144
|
/**
|
|
108
145
|
* tool to expose data to a frontend as a global variable.
|
|
109
146
|
* @param name this will be added as window.name to the window object in the frontend
|
|
@@ -136,7 +173,7 @@ export declare class url {
|
|
|
136
173
|
* @example const {html,json, css, data, req, form, link, svg, deliver, route, params, header, head } = mini //pull everything out of the mini handbag
|
|
137
174
|
* @returns
|
|
138
175
|
*/
|
|
139
|
-
handler: (dataHandler: HtmlHandler<T>) => (oldmini: Mini) => Promise<string | void |
|
|
176
|
+
handler: (dataHandler: HtmlHandler<T>) => (oldmini: Mini) => Promise<string | void | JsonString>;
|
|
140
177
|
dataMaker: DataMaker<T, Z>;
|
|
141
178
|
/**
|
|
142
179
|
* use this to **specify the input type for the functions**,
|
|
@@ -144,7 +181,7 @@ export declare class url {
|
|
|
144
181
|
* that you want to use in the HtmlHandlers that follow this **data blend!**
|
|
145
182
|
* @example type lol = typeof MaybeLoggedIn.$Mini
|
|
146
183
|
*/
|
|
147
|
-
$Mini: Mini<T>;
|
|
184
|
+
$Mini: Mini<T, "">;
|
|
148
185
|
/**
|
|
149
186
|
* use this to **specify the input type for the functions**,
|
|
150
187
|
*
|
|
@@ -168,19 +205,12 @@ export declare class url {
|
|
|
168
205
|
* ```
|
|
169
206
|
*/
|
|
170
207
|
static set<K extends string>(entries: [K, HtmlHandler][]): void;
|
|
208
|
+
static set<R extends {
|
|
209
|
+
[X in keyof R]: MiniNextRouteValue<Extract<X, string>>;
|
|
210
|
+
}>({ routes }: {
|
|
211
|
+
routes: R;
|
|
212
|
+
}): void;
|
|
171
213
|
static set(urlPath: string, handler: HtmlHandler): void;
|
|
172
|
-
/**
|
|
173
|
-
* use this to remove routes.
|
|
174
|
-
* @param urlPath - the route to remove
|
|
175
|
-
* @example
|
|
176
|
-
* ``` js
|
|
177
|
-
* let perma_link_defined_by_editor_or_admin_user_that_changed = "/haha"
|
|
178
|
-
* url.remove(perma_link_defined_by_editor_or_admin_user_that_changed);
|
|
179
|
-
* // add new url after removing the old one (that might come from a sqlite db)
|
|
180
|
-
* url.set("/huhu", (mini)=> mini.html`huhu`)
|
|
181
|
-
* ```
|
|
182
|
-
*/
|
|
183
|
-
static remove(urlPath: string): void;
|
|
184
214
|
/**
|
|
185
215
|
* wrap your handlers in this if you mutate something to prevent CSRF issues.
|
|
186
216
|
* @param handler - normal html handler with mini as the argument
|
|
@@ -231,9 +261,9 @@ export declare class url {
|
|
|
231
261
|
* @throws Will throw an Error if the provided url is not found in the urls array.
|
|
232
262
|
*/
|
|
233
263
|
static get(Url: string): string | null;
|
|
234
|
-
static
|
|
264
|
+
static handleWithMini(req: BunRequest<string>, server: Server, handler: HtmlHandler): Promise<Response>;
|
|
235
265
|
/**
|
|
236
|
-
*
|
|
266
|
+
* use this to set the Websocket object. Check out [the bun docs](https://bun.sh/docs/api/websockets) for more details.
|
|
237
267
|
* @param wsObject the websocketsocket object {@link WebSocketHandler}
|
|
238
268
|
*/
|
|
239
269
|
static setWebsocket<T = undefined>(wsObject: WebSocketHandler<T>): void;
|
|
@@ -250,8 +280,9 @@ export declare class url {
|
|
|
250
280
|
* @return {Promise<Response>} - The Response object.
|
|
251
281
|
*/
|
|
252
282
|
static install(): {
|
|
253
|
-
fetch: (req: Request, server: Server) =>
|
|
283
|
+
fetch: (req: Request, server: Server) => Response;
|
|
254
284
|
websocket: WebSocketHandler<undefined> | undefined;
|
|
285
|
+
routes: {};
|
|
255
286
|
};
|
|
256
287
|
}
|
|
257
288
|
export {};
|
package/dist/url.js
CHANGED
|
@@ -67,29 +67,58 @@ export class Mini {
|
|
|
67
67
|
export class url {
|
|
68
68
|
static websocket = undefined;
|
|
69
69
|
static server;
|
|
70
|
+
static routes;
|
|
70
71
|
// direct mapping of "url string" -> function leads to Html Response
|
|
71
72
|
static direct_handlers_html = new Map();
|
|
72
73
|
// An array of the uncompiled frontend files, example frontends[0] = "index.tsx" -> frontend/index.tsx (from the project root)
|
|
73
74
|
static frontends = [];
|
|
74
|
-
static svgs =
|
|
75
|
-
|
|
75
|
+
static svgs = [];
|
|
76
|
+
/**
|
|
77
|
+
* This function takes care of bundling your svg (icons?) into the webapp
|
|
78
|
+
* they will have a hash in the name to break the cache when needed
|
|
79
|
+
* @param svgFilePath first place to look: svgs folder in the same path the calling file, after that path from project root.
|
|
80
|
+
* @param options ResponseInit, default headers for an svg
|
|
81
|
+
* @returns url to the svg
|
|
82
|
+
*/
|
|
83
|
+
static svg(svgFilePath, options = {
|
|
76
84
|
headers: {
|
|
77
85
|
"Content-Type": "image/svg+xml",
|
|
78
86
|
"Content-Disposition": "attachment",
|
|
79
87
|
},
|
|
80
88
|
}) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
89
|
+
const stack = new Error().stack?.split("\n");
|
|
90
|
+
let callerPath = "";
|
|
91
|
+
if (stack) {
|
|
92
|
+
callerPath = stack[2].slice(stack[2].lastIndexOf("(") + 1, stack[2].lastIndexOf(".") + 3);
|
|
93
|
+
callerPath = callerPath.slice(callerPath.search("at") + 2).trim();
|
|
94
|
+
}
|
|
95
|
+
const position = url.svgs.length;
|
|
96
|
+
//we register the svg for bundleing.
|
|
97
|
+
url.svgs.push({
|
|
98
|
+
svgFilePath,
|
|
99
|
+
callerPath,
|
|
100
|
+
options,
|
|
101
|
+
position: url.svgs.length,
|
|
102
|
+
});
|
|
103
|
+
//this will be filled in by the bundling step.
|
|
104
|
+
var foundSvg = Object.entries(bundledSVGs).find(([key, value]) => value.position === position);
|
|
105
|
+
return foundSvg && foundSvg[0];
|
|
84
106
|
}
|
|
85
|
-
static frontend(
|
|
107
|
+
static frontend(frontendFilePath, snippet) {
|
|
86
108
|
const stack = new Error().stack?.split("\n");
|
|
87
109
|
let callerPath = "";
|
|
88
110
|
if (stack) {
|
|
89
111
|
callerPath = stack[2].slice(stack[2].lastIndexOf("(") + 1, stack[2].lastIndexOf(".") + 3);
|
|
112
|
+
callerPath = callerPath.slice(callerPath.search("at") + 2).trim();
|
|
90
113
|
}
|
|
91
|
-
const
|
|
92
|
-
|
|
114
|
+
const position = url.frontends.length;
|
|
115
|
+
//we register the frontend for bundleing.
|
|
116
|
+
url.frontends.push({ frontendFilePath, callerPath, position });
|
|
117
|
+
//this will be filled in by the bundling step.
|
|
118
|
+
const bundledFrontend = Object.entries(bundledFrontends).find(([key, value]) => value.position === position);
|
|
119
|
+
if (!bundledFrontend)
|
|
120
|
+
return;
|
|
121
|
+
const scriptUrl = bundledFrontend[0];
|
|
93
122
|
if (snippet instanceof BasedHtml || !snippet) {
|
|
94
123
|
return html ` ${snippet}
|
|
95
124
|
<script type="module" src="${scriptUrl}"></script>`; // return an html script tag with the index hash
|
|
@@ -105,26 +134,8 @@ export class url {
|
|
|
105
134
|
static getFrontends() {
|
|
106
135
|
return url.frontends;
|
|
107
136
|
}
|
|
108
|
-
static
|
|
109
|
-
return
|
|
110
|
-
}
|
|
111
|
-
static serveFrontend(req) {
|
|
112
|
-
const reqPath = new URL(req.url).pathname;
|
|
113
|
-
const index = FrontendScriptUrls.indexOf(reqPath);
|
|
114
|
-
if (index !== -1) {
|
|
115
|
-
return new Response(FrontendScripts[index], {
|
|
116
|
-
headers: {
|
|
117
|
-
"Content-Type": "application/javascript; charset=utf-8",
|
|
118
|
-
},
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
static serveSvg(req) {
|
|
123
|
-
const reqPath = new URL(req.url).pathname;
|
|
124
|
-
const resolvedSvg = bundledSVGs[reqPath];
|
|
125
|
-
if (resolvedSvg) {
|
|
126
|
-
return new Response(resolvedSvg.svgContent, url.svgs.get(resolvedSvg.svgPath));
|
|
127
|
-
}
|
|
137
|
+
static getSvgs() {
|
|
138
|
+
return url.svgs;
|
|
128
139
|
}
|
|
129
140
|
/**
|
|
130
141
|
* tool to expose data to a frontend as a global variable.
|
|
@@ -210,27 +221,14 @@ export class url {
|
|
|
210
221
|
if (typeof entries === "string" && handler) {
|
|
211
222
|
addUrl(entries, handler);
|
|
212
223
|
}
|
|
213
|
-
if (typeof entries !== "string")
|
|
224
|
+
if (typeof entries !== "string" && "routes" in entries) {
|
|
225
|
+
url.routes = entries.routes;
|
|
226
|
+
}
|
|
227
|
+
if (typeof entries !== "string" && !("routes" in entries))
|
|
214
228
|
for (const [entryUrl, entryHandler] of entries) {
|
|
215
229
|
addUrl(entryUrl, entryHandler);
|
|
216
230
|
}
|
|
217
231
|
}
|
|
218
|
-
/**
|
|
219
|
-
* use this to remove routes.
|
|
220
|
-
* @param urlPath - the route to remove
|
|
221
|
-
* @example
|
|
222
|
-
* ``` js
|
|
223
|
-
* let perma_link_defined_by_editor_or_admin_user_that_changed = "/haha"
|
|
224
|
-
* url.remove(perma_link_defined_by_editor_or_admin_user_that_changed);
|
|
225
|
-
* // add new url after removing the old one (that might come from a sqlite db)
|
|
226
|
-
* url.set("/huhu", (mini)=> mini.html`huhu`)
|
|
227
|
-
* ```
|
|
228
|
-
*/
|
|
229
|
-
static remove(urlPath) {
|
|
230
|
-
for (const u of url.generateVariations(urlPath)) {
|
|
231
|
-
url.direct_handlers_html.delete(u);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
232
|
/**
|
|
235
233
|
* wrap your handlers in this if you mutate something to prevent CSRF issues.
|
|
236
234
|
* @param handler - normal html handler with mini as the argument
|
|
@@ -387,95 +385,92 @@ export class url {
|
|
|
387
385
|
}
|
|
388
386
|
return Url;
|
|
389
387
|
}
|
|
390
|
-
static async
|
|
388
|
+
static async handleWithMini(req, server, handler) {
|
|
389
|
+
if (!url.server)
|
|
390
|
+
url.server = server;
|
|
391
391
|
const miniurl = Object.freeze(new URL(req.url));
|
|
392
|
-
|
|
393
|
-
|
|
392
|
+
const reqPath = miniurl.pathname;
|
|
393
|
+
let redirectTarget = null;
|
|
394
|
+
let redirectStatus = undefined;
|
|
395
|
+
let handlerHead = undefined;
|
|
396
|
+
let handlerOptions = {
|
|
397
|
+
headers: {
|
|
398
|
+
"Content-Type": "text/html; charset=utf-8",
|
|
399
|
+
},
|
|
400
|
+
};
|
|
401
|
+
const post = req.method === "POST";
|
|
402
|
+
let formJson;
|
|
403
|
+
let formData;
|
|
404
|
+
const urlencoded = (req.headers.get("Content-Type") + "").includes("application/x-www-form-urlencoded");
|
|
405
|
+
const multipart = (req.headers.get("Content-Type") + "").includes("multipart/form-data");
|
|
406
|
+
if (post && !urlencoded && !multipart) {
|
|
407
|
+
const length = Number(req.headers.get("content-length"));
|
|
408
|
+
const bodyNotEmpty = length > 0;
|
|
409
|
+
if (bodyNotEmpty) {
|
|
410
|
+
formJson = await req.json();
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
formJson = {};
|
|
414
|
+
}
|
|
394
415
|
}
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
416
|
+
if (post && (urlencoded || multipart)) {
|
|
417
|
+
formData = await req.formData();
|
|
418
|
+
}
|
|
419
|
+
//this is the source of mini
|
|
420
|
+
const mini = new Mini({
|
|
421
|
+
requrl: miniurl,
|
|
422
|
+
data: undefined,
|
|
423
|
+
req: req,
|
|
424
|
+
html,
|
|
425
|
+
css: html,
|
|
426
|
+
deliver: url.deliver,
|
|
427
|
+
route: reqPath,
|
|
428
|
+
params: new URL(req.url).searchParams,
|
|
429
|
+
json,
|
|
430
|
+
form: {
|
|
431
|
+
post,
|
|
432
|
+
urlencoded,
|
|
433
|
+
multipart,
|
|
434
|
+
formJson,
|
|
435
|
+
formData,
|
|
436
|
+
onPostSubmit(cb) {
|
|
437
|
+
if (post) {
|
|
438
|
+
return cb();
|
|
439
|
+
}
|
|
403
440
|
},
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
if (bodyNotEmpty) {
|
|
414
|
-
formJson = await req.json();
|
|
441
|
+
actionlink: (qs = "", settings) => url.link(reqPath, qs, settings),
|
|
442
|
+
},
|
|
443
|
+
dangerjson,
|
|
444
|
+
head: (head) => {
|
|
445
|
+
handlerHead = head;
|
|
446
|
+
},
|
|
447
|
+
headers: (headers, overwrite = false) => {
|
|
448
|
+
if (overwrite) {
|
|
449
|
+
handlerOptions.headers = headers;
|
|
415
450
|
}
|
|
416
451
|
else {
|
|
417
|
-
|
|
452
|
+
handlerOptions.headers = {
|
|
453
|
+
...handlerOptions.headers,
|
|
454
|
+
...headers,
|
|
455
|
+
};
|
|
418
456
|
}
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
route: reqPath,
|
|
432
|
-
params: new URL(req.url).searchParams,
|
|
433
|
-
json,
|
|
434
|
-
form: {
|
|
435
|
-
post,
|
|
436
|
-
urlencoded,
|
|
437
|
-
multipart,
|
|
438
|
-
formJson,
|
|
439
|
-
formData,
|
|
440
|
-
onPostSubmit(cb) {
|
|
441
|
-
if (post) {
|
|
442
|
-
return cb();
|
|
443
|
-
}
|
|
444
|
-
},
|
|
445
|
-
actionlink: (qs = "", settings) => url.link(reqPath, qs, settings),
|
|
446
|
-
},
|
|
447
|
-
dangerjson,
|
|
448
|
-
head: (head) => {
|
|
449
|
-
handlerHead = head;
|
|
450
|
-
},
|
|
451
|
-
headers: (headers, overwrite = false) => {
|
|
452
|
-
if (overwrite) {
|
|
453
|
-
handlerOptions.headers = headers;
|
|
454
|
-
}
|
|
455
|
-
else {
|
|
456
|
-
handlerOptions.headers = {
|
|
457
|
-
...handlerOptions.headers,
|
|
458
|
-
...headers,
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
},
|
|
462
|
-
options: (options) => {
|
|
463
|
-
handlerOptions = options;
|
|
464
|
-
},
|
|
465
|
-
redirect: (url, status) => {
|
|
466
|
-
redirectTarget = url;
|
|
467
|
-
redirectStatus = status;
|
|
468
|
-
},
|
|
469
|
-
}, undefined);
|
|
470
|
-
const unresolved = await handler(mini); //passing mini
|
|
471
|
-
if (redirectTarget) {
|
|
472
|
-
return Response.redirect(redirectTarget, redirectStatus);
|
|
473
|
-
}
|
|
474
|
-
return htmlResponder(mini, unresolved, handlerHead, handlerOptions);
|
|
457
|
+
},
|
|
458
|
+
options: (options) => {
|
|
459
|
+
handlerOptions = options;
|
|
460
|
+
},
|
|
461
|
+
redirect: (url, status) => {
|
|
462
|
+
redirectTarget = url;
|
|
463
|
+
redirectStatus = status;
|
|
464
|
+
},
|
|
465
|
+
}, undefined);
|
|
466
|
+
const unresolved = await handler(mini); //passing mini
|
|
467
|
+
if (redirectTarget) {
|
|
468
|
+
return Response.redirect(redirectTarget, redirectStatus);
|
|
475
469
|
}
|
|
470
|
+
return htmlResponder(mini, unresolved, handlerHead, handlerOptions);
|
|
476
471
|
}
|
|
477
472
|
/**
|
|
478
|
-
*
|
|
473
|
+
* use this to set the Websocket object. Check out [the bun docs](https://bun.sh/docs/api/websockets) for more details.
|
|
479
474
|
* @param wsObject the websocketsocket object {@link WebSocketHandler}
|
|
480
475
|
*/
|
|
481
476
|
static setWebsocket(wsObject) {
|
|
@@ -496,24 +491,44 @@ export class url {
|
|
|
496
491
|
* @return {Promise<Response>} - The Response object.
|
|
497
492
|
*/
|
|
498
493
|
static install() {
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
494
|
+
for (const route in url.routes) {
|
|
495
|
+
//handle route object split by methods and pull them through mininext
|
|
496
|
+
const handler = url.routes[route];
|
|
497
|
+
if (typeof handler === "function") {
|
|
498
|
+
url.routes[route] = (req, server) => url.handleWithMini(req, server, handler);
|
|
499
|
+
}
|
|
500
|
+
else {
|
|
501
|
+
const newHandlerObject = {};
|
|
502
|
+
for (const HTTPmethod in handler) {
|
|
503
|
+
newHandlerObject[HTTPmethod] = (req, server) => url.handleWithMini(req, server, handler[HTTPmethod]);
|
|
504
|
+
}
|
|
505
|
+
url.routes[route] = newHandlerObject;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
//TODO add fronted + svg to routes object
|
|
509
|
+
for (const [route, handler] of url.direct_handlers_html) {
|
|
510
|
+
url.routes[route] = (req, server) => url.handleWithMini(req, server, handler);
|
|
511
|
+
}
|
|
512
|
+
for (const svgUrl in bundledSVGs) {
|
|
513
|
+
const resolvedSvg = bundledSVGs[svgUrl];
|
|
514
|
+
url.routes[svgUrl] = (req, server) => new Response(resolvedSvg.svgContent, resolvedSvg.options);
|
|
515
|
+
}
|
|
516
|
+
for (const frontendUrl in bundledFrontends) {
|
|
517
|
+
const resolvedFrontend = bundledFrontends[frontendUrl];
|
|
518
|
+
url.routes[frontendUrl] = (req, server) => new Response(resolvedFrontend.frontendContent, {
|
|
519
|
+
headers: {
|
|
520
|
+
"Content-Type": "application/javascript; charset=utf-8",
|
|
521
|
+
},
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
function fetchFunction(req, server) {
|
|
514
525
|
return new Response("No matching url found", { status: 404 });
|
|
515
526
|
}
|
|
516
|
-
return {
|
|
527
|
+
return {
|
|
528
|
+
fetch: fetchFunction,
|
|
529
|
+
websocket: url.websocket,
|
|
530
|
+
routes: url.routes,
|
|
531
|
+
};
|
|
517
532
|
}
|
|
518
533
|
}
|
|
519
534
|
const no_post_warning = html `<div style="color:red;">
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@spirobel/mininext",
|
|
3
|
-
"license"
|
|
3
|
+
"license": "MIT",
|
|
4
4
|
"module": "dist/mininext/mininext.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/mininext.js",
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
"scripts": {
|
|
9
9
|
"publish": "bun run build && npm publish",
|
|
10
10
|
"build": "tsc",
|
|
11
|
-
"clean":"rm -rf ./dist"
|
|
11
|
+
"clean": "rm -rf ./dist"
|
|
12
12
|
},
|
|
13
13
|
"files": ["dist"],
|
|
14
|
-
"version": "0.
|
|
14
|
+
"version": "0.7.1",
|
|
15
15
|
"devDependencies": {
|
|
16
|
-
"@types/bun": "
|
|
16
|
+
"@types/bun": "^1.2.9"
|
|
17
17
|
},
|
|
18
18
|
"peerDependencies": {
|
|
19
19
|
"typescript": "^5.0.0"
|