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 CHANGED
@@ -1,5 +1,7 @@
1
1
  # 👑 **PrinceJS**
2
2
 
3
+ ![PrinceJS Image](./src/images/og.png)
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
  ![npm](https://img.shields.io/npm/v/princejs)
@@ -65,22 +67,17 @@ app
65
67
 
66
68
  ### ✓ Response Builder
67
69
 
68
- ### OpenAPI
70
+ ### WebSocket Support
69
71
 
70
- ---
72
+ ### Auth & API Keys
71
73
 
72
- ## New Tree‑Shakable Features
74
+ ### Server-Sent Events
73
75
 
74
- ```ts
75
- import { cache, email, upload } from "princejs/helpers";
76
- import { cron, openapi } from "princejs/scheduler";
77
- ```
76
+ ### Sessions
78
77
 
79
- * `cache(60)(handler)` — In‑memory cache
80
- * `email(to, subject, html)` — Email helper
81
- * `upload()` — One‑line file upload
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
@@ -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
@@ -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
  };
@@ -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
@@ -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"}
@@ -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;
@@ -1 +1 @@
1
- {"version":3,"file":"prince.d.ts","sourceRoot":"","sources":["../src/prince.ts"],"names":[],"mappings":"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"}
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) => self.fetch(req)
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.7.8",
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
- "ssr"
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",