princejs 1.7.8 → 1.8.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/Readme.md +37 -14
- package/dist/db.d.ts +10 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +28 -0
- package/dist/helpers.d.ts +1 -0
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +31 -0
- package/dist/middleware.d.ts +16 -0
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +105 -1
- package/dist/prince.d.ts +7 -0
- package/dist/prince.d.ts.map +1 -1
- package/dist/prince.js +39 -1
- package/package.json +12 -3
package/Readme.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# 👑 **PrinceJS**
|
|
2
2
|
|
|
3
|
+

|
|
4
|
+
|
|
3
5
|
### ⚡ Ultra-clean, modern & minimal Bun web framework built by a 13 year old. Among the top three in performance.
|
|
4
6
|
|
|
5
7
|

|
|
@@ -65,22 +67,17 @@ app
|
|
|
65
67
|
|
|
66
68
|
### ✓ Response Builder
|
|
67
69
|
|
|
68
|
-
###
|
|
70
|
+
### WebSocket Support
|
|
69
71
|
|
|
70
|
-
|
|
72
|
+
### Auth & API Keys
|
|
71
73
|
|
|
72
|
-
|
|
74
|
+
### Server-Sent Events
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
import { cache, email, upload } from "princejs/helpers";
|
|
76
|
-
import { cron, openapi } from "princejs/scheduler";
|
|
77
|
-
```
|
|
76
|
+
### Sessions
|
|
78
77
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
* `cron("*/2 * * * *", task)` — Cron jobs
|
|
83
|
-
* `openapi({ title, version })` — Auto docs
|
|
78
|
+
### Response Compression
|
|
79
|
+
|
|
80
|
+
### Database (SQLite)
|
|
84
81
|
|
|
85
82
|
---
|
|
86
83
|
|
|
@@ -101,11 +98,12 @@ import { cron, openapi } from "princejs/scheduler";
|
|
|
101
98
|
|
|
102
99
|
```ts
|
|
103
100
|
import { prince } from "princejs";
|
|
104
|
-
import { cors, logger, rateLimit } from "princejs/middleware";
|
|
101
|
+
import { cors, logger, rateLimit, auth, apiKey, jwt, session, compress, serve } from "princejs/middleware";
|
|
105
102
|
import { validate } from "princejs/validation";
|
|
106
|
-
import { cache, upload } from "princejs/helpers";
|
|
103
|
+
import { cache, upload, sse } from "princejs/helpers";
|
|
107
104
|
import { cron } from "princejs/scheduler";
|
|
108
105
|
import { Html, Head, Body, H1, P, render } from "princejs/jsx"
|
|
106
|
+
import { db } from "princejs/db";
|
|
109
107
|
import { z } from "zod";
|
|
110
108
|
|
|
111
109
|
const app = prince(true);
|
|
@@ -114,8 +112,14 @@ app.use(cors());
|
|
|
114
112
|
app.use(logger());
|
|
115
113
|
app.use(rateLimit({ max: 100, window: 60 }));
|
|
116
114
|
|
|
115
|
+
app.use(serve({ root: "./public" }));
|
|
116
|
+
|
|
117
117
|
app.use(validate(z.object({ name: z.string() })));
|
|
118
118
|
|
|
119
|
+
app.use(jwt(key));
|
|
120
|
+
app.use(session({ secret: "key" }));
|
|
121
|
+
app.use(compress());
|
|
122
|
+
|
|
119
123
|
const Page = () => (
|
|
120
124
|
Html({
|
|
121
125
|
children: [
|
|
@@ -138,6 +142,17 @@ const Page = () => (
|
|
|
138
142
|
})
|
|
139
143
|
);
|
|
140
144
|
|
|
145
|
+
const users = db.sqlite("./db.sqlite", "CREATE TABLE users...");
|
|
146
|
+
|
|
147
|
+
app.ws("/chat", {
|
|
148
|
+
open: (ws) => ws.send("Welcome!"),
|
|
149
|
+
message: (ws, msg) => ws.send(`Echo: ${msg}`)
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
app.get("/protected", auth(), (req) => ({ user: req.user }));
|
|
154
|
+
app.get("/api", apiKey({ keys: ["key_123"] }), handler);
|
|
155
|
+
|
|
141
156
|
app.get("/", () => ({ message: "Welcome to PrinceJS" }));
|
|
142
157
|
|
|
143
158
|
app.get("/users/:id", (req) => ({ id: req.params.id }));
|
|
@@ -148,6 +163,14 @@ app.get("/data", cache(60)(() => ({ time: Date.now() })));
|
|
|
148
163
|
|
|
149
164
|
app.post("/upload", upload(), (req) => ({ files: Object.keys(req.files || {}) }));
|
|
150
165
|
|
|
166
|
+
app.get("/events", sse(), (req) => {
|
|
167
|
+
setInterval(() => req.sseSend({ time: Date.now() }), 1000);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
app.get("/count", (req) => ({ visits: req.session.visits++ || 1 }));
|
|
171
|
+
|
|
172
|
+
app.get("/users", () => users.query("SELECT * FROM users"));
|
|
173
|
+
|
|
151
174
|
cron("*/1 * * * *", () => console.log("PrinceJS heartbeat"));
|
|
152
175
|
|
|
153
176
|
app.listen(3000);
|
package/dist/db.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const db: {
|
|
2
|
+
sqlite: (path: string, init?: string) => {
|
|
3
|
+
query: (sql: string, params?: any[]) => unknown[];
|
|
4
|
+
get: (sql: string, params?: any[]) => unknown;
|
|
5
|
+
run: (sql: string, params?: any[]) => import("bun:sqlite").Changes;
|
|
6
|
+
prepare: (sql: string) => import("bun:sqlite").Statement<unknown, import("bun:sqlite").SQLQueryBindings[] | [null] | [string] | [number] | [bigint] | [false] | [true] | [Uint8Array<ArrayBufferLike>] | [Uint8ClampedArray<ArrayBufferLike>] | [Uint16Array<ArrayBufferLike>] | [Uint32Array<ArrayBufferLike>] | [Int8Array<ArrayBufferLike>] | [Int16Array<ArrayBufferLike>] | [Int32Array<ArrayBufferLike>] | [BigUint64Array<ArrayBufferLike>] | [BigInt64Array<ArrayBufferLike>] | [Float16Array<ArrayBufferLike>] | [Float32Array<ArrayBufferLike>] | [Float64Array<ArrayBufferLike>] | [Record<string, string | number | bigint | boolean | NodeJS.TypedArray<ArrayBufferLike> | null>]>;
|
|
7
|
+
close: () => void;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=db.d.ts.map
|
package/dist/db.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,EAAE;mBACE,MAAM,SAAS,MAAM;qBAKnB,MAAM,WAAW,GAAG,EAAE;mBAIxB,MAAM,WAAW,GAAG,EAAE;mBAItB,MAAM,WAAW,GAAG,EAAE;uBAIlB,MAAM;;;CAO1B,CAAC"}
|
package/dist/db.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/db.ts
|
|
3
|
+
import { Database } from "bun:sqlite";
|
|
4
|
+
var db = {
|
|
5
|
+
sqlite: (path, init) => {
|
|
6
|
+
const db2 = new Database(path);
|
|
7
|
+
if (init)
|
|
8
|
+
db2.run(init);
|
|
9
|
+
return {
|
|
10
|
+
query: (sql, params) => {
|
|
11
|
+
return db2.query(sql).all(params);
|
|
12
|
+
},
|
|
13
|
+
get: (sql, params) => {
|
|
14
|
+
return db2.query(sql).get(params);
|
|
15
|
+
},
|
|
16
|
+
run: (sql, params) => {
|
|
17
|
+
return db2.run(sql, params);
|
|
18
|
+
},
|
|
19
|
+
prepare: (sql) => {
|
|
20
|
+
return db2.query(sql);
|
|
21
|
+
},
|
|
22
|
+
close: () => db2.close()
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
export {
|
|
27
|
+
db
|
|
28
|
+
};
|
package/dist/helpers.d.ts
CHANGED
|
@@ -2,4 +2,5 @@ import type { PrinceRequest } from "./prince";
|
|
|
2
2
|
export declare const cache: (ttl: number) => (handler: any) => (req: PrinceRequest) => Promise<any>;
|
|
3
3
|
export declare const email: (to: string, subject: string, html: string) => Promise<void>;
|
|
4
4
|
export declare const upload: () => (req: PrinceRequest) => Promise<Response>;
|
|
5
|
+
export declare const sse: () => (req: PrinceRequest) => Response;
|
|
5
6
|
//# sourceMappingURL=helpers.d.ts.map
|
package/dist/helpers.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG9C,eAAO,MAAM,KAAK,GAAI,KAAK,MAAM,MAEvB,SAAS,GAAG,MAAY,KAAK,aAAa,iBASnD,CAAC;AAGF,eAAO,MAAM,KAAK,GAAU,IAAI,MAAM,EAAE,SAAS,MAAM,EAAE,MAAM,MAAM,kBAMpE,CAAC;AAGF,eAAO,MAAM,MAAM,SACH,KAAK,aAAa,sBA4CjC,CAAC"}
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAG9C,eAAO,MAAM,KAAK,GAAI,KAAK,MAAM,MAEvB,SAAS,GAAG,MAAY,KAAK,aAAa,iBASnD,CAAC;AAGF,eAAO,MAAM,KAAK,GAAU,IAAI,MAAM,EAAE,SAAS,MAAM,EAAE,MAAM,MAAM,kBAMpE,CAAC;AAGF,eAAO,MAAM,MAAM,SACH,KAAK,aAAa,sBA4CjC,CAAC;AAGF,eAAO,MAAM,GAAG,SACN,KAAK,aAAa,aA0B3B,CAAC"}
|
package/dist/helpers.js
CHANGED
|
@@ -51,8 +51,39 @@ var upload = () => {
|
|
|
51
51
|
}
|
|
52
52
|
};
|
|
53
53
|
};
|
|
54
|
+
var sse = () => {
|
|
55
|
+
return (req) => {
|
|
56
|
+
let controller;
|
|
57
|
+
const stream = new ReadableStream({
|
|
58
|
+
start(c) {
|
|
59
|
+
controller = c;
|
|
60
|
+
req.sseSend = (data, event, id) => {
|
|
61
|
+
let message = "";
|
|
62
|
+
if (event)
|
|
63
|
+
message += `event: ${event}
|
|
64
|
+
`;
|
|
65
|
+
if (id)
|
|
66
|
+
message += `id: ${id}
|
|
67
|
+
`;
|
|
68
|
+
message += `data: ${typeof data === "string" ? data : JSON.stringify(data)}
|
|
69
|
+
|
|
70
|
+
`;
|
|
71
|
+
controller.enqueue(new TextEncoder().encode(message));
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
return new Response(stream, {
|
|
76
|
+
headers: {
|
|
77
|
+
"Content-Type": "text/event-stream",
|
|
78
|
+
"Cache-Control": "no-cache",
|
|
79
|
+
Connection: "keep-alive"
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
};
|
|
54
84
|
export {
|
|
55
85
|
upload,
|
|
86
|
+
sse,
|
|
56
87
|
email,
|
|
57
88
|
cache
|
|
58
89
|
};
|
package/dist/middleware.d.ts
CHANGED
|
@@ -7,5 +7,21 @@ export declare const signJWT: (payload: any, secret: Uint8Array, expiresIn: stri
|
|
|
7
7
|
export declare const jwt: (key: Uint8Array) => (req: PrinceRequest, next: Next) => Promise<Response | undefined>;
|
|
8
8
|
export declare const rateLimit: (max: number, window?: number) => (req: PrinceRequest, next: Next) => Promise<Response | undefined>;
|
|
9
9
|
export declare const validate: (schema: z.ZodSchema) => (req: any, next: Function) => Promise<any>;
|
|
10
|
+
export declare const auth: (options?: {
|
|
11
|
+
roles?: string[];
|
|
12
|
+
}) => (req: PrinceRequest, next: Next) => Promise<Response | undefined>;
|
|
13
|
+
export declare const apiKey: (options: {
|
|
14
|
+
keys: string[];
|
|
15
|
+
header?: string;
|
|
16
|
+
}) => (req: PrinceRequest, next: Next) => Promise<Response | undefined>;
|
|
17
|
+
export declare const compress: (options?: {
|
|
18
|
+
threshold?: number;
|
|
19
|
+
filter?: (req: PrinceRequest) => boolean;
|
|
20
|
+
}) => (req: PrinceRequest, next: Next) => Promise<Response | undefined>;
|
|
21
|
+
export declare const session: (options: {
|
|
22
|
+
secret: string;
|
|
23
|
+
maxAge?: number;
|
|
24
|
+
name?: string;
|
|
25
|
+
}) => (req: PrinceRequest, next: Next) => Promise<Response | undefined>;
|
|
10
26
|
export {};
|
|
11
27
|
//# sourceMappingURL=middleware.d.ts.map
|
package/dist/middleware.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,KAAK,IAAI,GAAG,MAAM,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC;AAKhD,eAAO,MAAM,IAAI,GAAI,SAAQ,MAAY,MACzB,KAAK,GAAG,EAAE,MAAM,QAAQ,iBA+BvC,CAAC;AAGF,eAAO,MAAM,MAAM,SACH,KAAK,aAAa,EAAE,MAAM,IAAI,kCAM7C,CAAC;AAGF,eAAO,MAAM,OAAO,GAAU,SAAS,GAAG,EAAE,QAAQ,UAAU,EAAE,WAAW,MAAM,oBAQhF,CAAC;AAGF,eAAO,MAAM,GAAG,GAAI,KAAK,UAAU,MACnB,KAAK,aAAa,EAAE,MAAM,IAAI,kCAuB7C,CAAC;AAGF,eAAO,MAAM,SAAS,GAAI,KAAK,MAAM,EAAE,eAAW,MAGlC,KAAK,aAAa,EAAE,MAAM,IAAI,kCAuC7C,CAAC;AAIF,eAAO,MAAM,QAAQ,GAAI,QAAQ,CAAC,CAAC,SAAS,MAC5B,KAAK,GAAG,EAAE,MAAM,QAAQ,iBAiCvC,CAAC"}
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAC9C,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,KAAK,IAAI,GAAG,MAAM,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC;AAKhD,eAAO,MAAM,IAAI,GAAI,SAAQ,MAAY,MACzB,KAAK,GAAG,EAAE,MAAM,QAAQ,iBA+BvC,CAAC;AAGF,eAAO,MAAM,MAAM,SACH,KAAK,aAAa,EAAE,MAAM,IAAI,kCAM7C,CAAC;AAGF,eAAO,MAAM,OAAO,GAAU,SAAS,GAAG,EAAE,QAAQ,UAAU,EAAE,WAAW,MAAM,oBAQhF,CAAC;AAGF,eAAO,MAAM,GAAG,GAAI,KAAK,UAAU,MACnB,KAAK,aAAa,EAAE,MAAM,IAAI,kCAuB7C,CAAC;AAGF,eAAO,MAAM,SAAS,GAAI,KAAK,MAAM,EAAE,eAAW,MAGlC,KAAK,aAAa,EAAE,MAAM,IAAI,kCAuC7C,CAAC;AAIF,eAAO,MAAM,QAAQ,GAAI,QAAQ,CAAC,CAAC,SAAS,MAC5B,KAAK,GAAG,EAAE,MAAM,QAAQ,iBAiCvC,CAAC;AAGF,eAAO,MAAM,IAAI,GAAI,UAAU;IAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,MACnC,KAAK,aAAa,EAAE,MAAM,IAAI,kCAyB7C,CAAC;AAGF,eAAO,MAAM,MAAM,GAAI,SAAS;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,MAInD,KAAK,aAAa,EAAE,MAAM,IAAI,kCAa7C,CAAC;AAGF,eAAO,MAAM,QAAQ,GAAI,UAAU;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,aAAa,KAAK,OAAO,CAAC;CAC1C,MAIe,KAAK,aAAa,EAAE,MAAM,IAAI,kCAyC7C,CAAC;AAGF,eAAO,MAAM,OAAO,GAAI,SAAS;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,MAee,KAAK,aAAa,EAAE,MAAM,IAAI,kCAyC7C,CAAC"}
|
package/dist/middleware.js
CHANGED
|
@@ -13915,11 +13915,115 @@ var validate = (schema) => {
|
|
|
13915
13915
|
}
|
|
13916
13916
|
};
|
|
13917
13917
|
};
|
|
13918
|
+
var auth = (options) => {
|
|
13919
|
+
return async (req, next) => {
|
|
13920
|
+
if (!req.user) {
|
|
13921
|
+
return new Response(JSON.stringify({ error: "Unauthorized" }), { status: 401, headers: { "Content-Type": "application/json" } });
|
|
13922
|
+
}
|
|
13923
|
+
if (options?.roles) {
|
|
13924
|
+
const userRole = req.user.role || req.user.roles;
|
|
13925
|
+
const hasRole = Array.isArray(userRole) ? options.roles.some((r) => userRole.includes(r)) : options.roles.includes(userRole);
|
|
13926
|
+
if (!hasRole) {
|
|
13927
|
+
return new Response(JSON.stringify({ error: "Forbidden" }), { status: 403, headers: { "Content-Type": "application/json" } });
|
|
13928
|
+
}
|
|
13929
|
+
}
|
|
13930
|
+
return next();
|
|
13931
|
+
};
|
|
13932
|
+
};
|
|
13933
|
+
var apiKey = (options) => {
|
|
13934
|
+
const keySet = new Set(options.keys);
|
|
13935
|
+
const headerName = (options.header || "x-api-key").toLowerCase();
|
|
13936
|
+
return async (req, next) => {
|
|
13937
|
+
const key = req.headers.get(headerName);
|
|
13938
|
+
if (!key || !keySet.has(key)) {
|
|
13939
|
+
return new Response(JSON.stringify({ error: "Invalid API key" }), { status: 401, headers: { "Content-Type": "application/json" } });
|
|
13940
|
+
}
|
|
13941
|
+
req.apiKey = key;
|
|
13942
|
+
return next();
|
|
13943
|
+
};
|
|
13944
|
+
};
|
|
13945
|
+
var compress = (options) => {
|
|
13946
|
+
const threshold = options?.threshold || 1024;
|
|
13947
|
+
const filter = options?.filter || (() => true);
|
|
13948
|
+
return async (req, next) => {
|
|
13949
|
+
const response = await next();
|
|
13950
|
+
if (!response || !filter(req))
|
|
13951
|
+
return response;
|
|
13952
|
+
const contentType = response.headers.get("content-type") || "";
|
|
13953
|
+
if (!contentType.includes("json") && !contentType.includes("text") && !contentType.includes("javascript") && !contentType.includes("xml")) {
|
|
13954
|
+
return response;
|
|
13955
|
+
}
|
|
13956
|
+
const acceptEncoding = req.headers.get("accept-encoding") || "";
|
|
13957
|
+
if (!acceptEncoding.includes("gzip") && !acceptEncoding.includes("br")) {
|
|
13958
|
+
return response;
|
|
13959
|
+
}
|
|
13960
|
+
const body = await response.text();
|
|
13961
|
+
if (body.length < threshold) {
|
|
13962
|
+
return new Response(body, response);
|
|
13963
|
+
}
|
|
13964
|
+
const compressed = Bun.gzipSync(new TextEncoder().encode(body));
|
|
13965
|
+
const headers = new Headers(response.headers);
|
|
13966
|
+
headers.set("Content-Encoding", "gzip");
|
|
13967
|
+
headers.set("Content-Length", String(compressed.length));
|
|
13968
|
+
return new Response(compressed, {
|
|
13969
|
+
status: response.status,
|
|
13970
|
+
statusText: response.statusText,
|
|
13971
|
+
headers
|
|
13972
|
+
});
|
|
13973
|
+
};
|
|
13974
|
+
};
|
|
13975
|
+
var session = (options) => {
|
|
13976
|
+
const sessions = new Map;
|
|
13977
|
+
const cookieName = options.name || "prince.sid";
|
|
13978
|
+
const maxAge = options.maxAge || 3600;
|
|
13979
|
+
setInterval(() => {
|
|
13980
|
+
const now = Date.now();
|
|
13981
|
+
for (const [id, data] of sessions.entries()) {
|
|
13982
|
+
if (data._expires && data._expires < now) {
|
|
13983
|
+
sessions.delete(id);
|
|
13984
|
+
}
|
|
13985
|
+
}
|
|
13986
|
+
}, 300000);
|
|
13987
|
+
return async (req, next) => {
|
|
13988
|
+
const cookies = req.headers.get("cookie");
|
|
13989
|
+
let sessionId;
|
|
13990
|
+
if (cookies) {
|
|
13991
|
+
const match = cookies.match(new RegExp(`${cookieName}=([^;]+)`));
|
|
13992
|
+
sessionId = match?.[1];
|
|
13993
|
+
}
|
|
13994
|
+
if (sessionId && sessions.has(sessionId)) {
|
|
13995
|
+
req.session = sessions.get(sessionId);
|
|
13996
|
+
} else {
|
|
13997
|
+
sessionId = crypto.randomUUID();
|
|
13998
|
+
req.session = { _expires: Date.now() + maxAge * 1000 };
|
|
13999
|
+
}
|
|
14000
|
+
req.session.destroy = () => {
|
|
14001
|
+
if (sessionId)
|
|
14002
|
+
sessions.delete(sessionId);
|
|
14003
|
+
};
|
|
14004
|
+
const response = await next();
|
|
14005
|
+
if (!response)
|
|
14006
|
+
return response;
|
|
14007
|
+
req.session._expires = Date.now() + maxAge * 1000;
|
|
14008
|
+
sessions.set(sessionId, req.session);
|
|
14009
|
+
const headers = new Headers(response.headers);
|
|
14010
|
+
headers.append("Set-Cookie", `${cookieName}=${sessionId}; Max-Age=${maxAge}; HttpOnly; SameSite=Lax; Path=/`);
|
|
14011
|
+
return new Response(response.body, {
|
|
14012
|
+
status: response.status,
|
|
14013
|
+
statusText: response.statusText,
|
|
14014
|
+
headers
|
|
14015
|
+
});
|
|
14016
|
+
};
|
|
14017
|
+
};
|
|
13918
14018
|
export {
|
|
13919
14019
|
validate,
|
|
13920
14020
|
signJWT,
|
|
14021
|
+
session,
|
|
13921
14022
|
rateLimit,
|
|
13922
14023
|
logger,
|
|
13923
14024
|
jwt2 as jwt,
|
|
13924
|
-
cors
|
|
14025
|
+
cors,
|
|
14026
|
+
compress,
|
|
14027
|
+
auth,
|
|
14028
|
+
apiKey
|
|
13925
14029
|
};
|
package/dist/prince.d.ts
CHANGED
|
@@ -9,6 +9,12 @@ export interface PrinceRequest extends Request {
|
|
|
9
9
|
query?: URLSearchParams;
|
|
10
10
|
[key: string]: any;
|
|
11
11
|
}
|
|
12
|
+
interface WebSocketHandler {
|
|
13
|
+
open?: (ws: any) => void;
|
|
14
|
+
message?: (ws: any, msg: string | Buffer) => void;
|
|
15
|
+
close?: (ws: any, code?: number, reason?: string) => void;
|
|
16
|
+
drain?: (ws: any) => void;
|
|
17
|
+
}
|
|
12
18
|
type RouteHandler = (req: PrinceRequest) => Promise<HandlerResult> | HandlerResult;
|
|
13
19
|
declare class ResponseBuilder {
|
|
14
20
|
private _status;
|
|
@@ -43,6 +49,7 @@ export declare class Prince {
|
|
|
43
49
|
delete(path: string, handler: RouteHandler): this;
|
|
44
50
|
patch(path: string, handler: RouteHandler): this;
|
|
45
51
|
options(path: string, handler: RouteHandler): this;
|
|
52
|
+
ws(path: string, handlers: WebSocketHandler): this;
|
|
46
53
|
private add;
|
|
47
54
|
private buildRouter;
|
|
48
55
|
private insertRoute;
|
package/dist/prince.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prince.d.ts","sourceRoot":"","sources":["../src/prince.ts"],"names":[],"mappings":"AAIA,KAAK,IAAI,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;AACpC,KAAK,UAAU,GAAG,CAAC,GAAG,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,GAAG,QAAQ,GAAG,SAAS,CAAC;AAC3G,KAAK,aAAa,GAAG,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,GAAG,UAAU,CAAC;AAE1E,MAAM,WAAW,aAAc,SAAQ,OAAO;IAC5C,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC7B,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"prince.d.ts","sourceRoot":"","sources":["../src/prince.ts"],"names":[],"mappings":"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"}
|
package/dist/prince.js
CHANGED
|
@@ -85,6 +85,10 @@ class Prince {
|
|
|
85
85
|
options(path, handler) {
|
|
86
86
|
return this.add("OPTIONS", path, handler);
|
|
87
87
|
}
|
|
88
|
+
ws(path, handlers) {
|
|
89
|
+
this.wsRoutes[path] = handlers;
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
88
92
|
add(method, path, handler) {
|
|
89
93
|
if (!path.startsWith("/"))
|
|
90
94
|
path = "/" + path;
|
|
@@ -361,7 +365,41 @@ class Prince {
|
|
|
361
365
|
const self = this;
|
|
362
366
|
Bun.serve({
|
|
363
367
|
port,
|
|
364
|
-
fetch: (req, server) =>
|
|
368
|
+
fetch: (req, server) => {
|
|
369
|
+
const url = new URL(req.url);
|
|
370
|
+
if (self.wsRoutes[url.pathname] && server.upgrade(req, {
|
|
371
|
+
data: { path: url.pathname }
|
|
372
|
+
})) {
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
return self.fetch(req);
|
|
376
|
+
},
|
|
377
|
+
websocket: {
|
|
378
|
+
open(ws) {
|
|
379
|
+
const path = ws.data?.path;
|
|
380
|
+
if (path && self.wsRoutes[path]?.open) {
|
|
381
|
+
self.wsRoutes[path].open(ws);
|
|
382
|
+
}
|
|
383
|
+
},
|
|
384
|
+
message(ws, message) {
|
|
385
|
+
const path = ws.data?.path;
|
|
386
|
+
if (path && self.wsRoutes[path]?.message) {
|
|
387
|
+
self.wsRoutes[path].message(ws, message);
|
|
388
|
+
}
|
|
389
|
+
},
|
|
390
|
+
close(ws, code, reason) {
|
|
391
|
+
const path = ws.data?.path;
|
|
392
|
+
if (path && self.wsRoutes[path]?.close) {
|
|
393
|
+
self.wsRoutes[path].close(ws, code, reason);
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
drain(ws) {
|
|
397
|
+
const path = ws.data?.path;
|
|
398
|
+
if (path && self.wsRoutes[path]?.drain) {
|
|
399
|
+
self.wsRoutes[path].drain(ws);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
365
403
|
});
|
|
366
404
|
console.log(`\uD83D\uDE80 PrinceJS running on http://localhost:${port}`);
|
|
367
405
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "princejs",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.2",
|
|
4
4
|
"description": "An easy and fast backend framework that is among the top three — by a 13yo developer, for developers.",
|
|
5
5
|
"main": "dist/prince.js",
|
|
6
6
|
"types": "dist/prince.d.ts",
|
|
@@ -28,6 +28,10 @@
|
|
|
28
28
|
"./jsx": {
|
|
29
29
|
"import": "./dist/jsx.js",
|
|
30
30
|
"types": "./dist/jsx.d.ts"
|
|
31
|
+
},
|
|
32
|
+
"./db": {
|
|
33
|
+
"import": "./dist/db.js",
|
|
34
|
+
"types": "./dist/db.d.ts"
|
|
31
35
|
}
|
|
32
36
|
},
|
|
33
37
|
"files": [
|
|
@@ -50,7 +54,12 @@
|
|
|
50
54
|
"scheduler",
|
|
51
55
|
"fast",
|
|
52
56
|
"lightweight",
|
|
53
|
-
"
|
|
57
|
+
"sse",
|
|
58
|
+
"database",
|
|
59
|
+
"sqlite",
|
|
60
|
+
"zod",
|
|
61
|
+
"jose",
|
|
62
|
+
"jwt"
|
|
54
63
|
],
|
|
55
64
|
"author": "Matthew Michael (MatthewTheCoder1218)",
|
|
56
65
|
"license": "MIT",
|
|
@@ -86,7 +95,7 @@
|
|
|
86
95
|
"jose": "^6.1.2"
|
|
87
96
|
},
|
|
88
97
|
"scripts": {
|
|
89
|
-
"build:js": "bun build src/prince.ts --outdir dist --target bun && bun build src/middleware.ts --outdir dist --target bun && bun build src/helpers.ts --outdir dist --target bun && bun build src/scheduler.ts --outdir dist --target bun && bun build bin/create.ts --outdir dist --target bun && bun build src/jsx.ts --outdir dist --target bun --format esm",
|
|
98
|
+
"build:js": "bun build src/prince.ts --outdir dist --target bun && bun build src/middleware.ts --outdir dist --target bun && bun build src/helpers.ts --outdir dist --target bun && bun build src/scheduler.ts --outdir dist --target bun && bun build bin/create.ts --outdir dist --target bun && bun build src/jsx.ts --outdir dist --target bun && bun build src/db.ts --outdir dist --target bun --format esm",
|
|
90
99
|
"build:types": "tsc --emitDeclarationOnly --skipLibCheck",
|
|
91
100
|
"build": "bun run build:js && bun run build:types",
|
|
92
101
|
"test": "bun test",
|