@tripod311/currents 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +257 -0
  2. package/dist/binaryBody.d.ts +3 -0
  3. package/dist/binaryBody.d.ts.map +1 -0
  4. package/dist/binaryBody.js +14 -0
  5. package/dist/binaryBody.js.map +1 -0
  6. package/dist/body/binaryBody.d.ts +3 -0
  7. package/dist/body/binaryBody.d.ts.map +1 -0
  8. package/dist/body/binaryBody.js +14 -0
  9. package/dist/body/binaryBody.js.map +1 -0
  10. package/dist/body/formBody.d.ts +3 -0
  11. package/dist/body/formBody.d.ts.map +1 -0
  12. package/dist/body/formBody.js +15 -0
  13. package/dist/body/formBody.js.map +1 -0
  14. package/dist/body/jsonBody.d.ts +3 -0
  15. package/dist/body/jsonBody.d.ts.map +1 -0
  16. package/dist/body/jsonBody.js +7 -0
  17. package/dist/body/jsonBody.js.map +1 -0
  18. package/dist/body/multipartBody.d.ts +3 -0
  19. package/dist/body/multipartBody.d.ts.map +1 -0
  20. package/dist/body/multipartBody.js +115 -0
  21. package/dist/body/multipartBody.js.map +1 -0
  22. package/dist/body/textBody.d.ts +3 -0
  23. package/dist/body/textBody.d.ts.map +1 -0
  24. package/dist/body/textBody.js +7 -0
  25. package/dist/body/textBody.js.map +1 -0
  26. package/dist/context.d.ts +43 -0
  27. package/dist/context.d.ts.map +1 -0
  28. package/dist/context.js +129 -0
  29. package/dist/context.js.map +1 -0
  30. package/dist/cookie.d.ts +13 -0
  31. package/dist/cookie.d.ts.map +1 -0
  32. package/dist/cookie.js +61 -0
  33. package/dist/cookie.js.map +1 -0
  34. package/dist/cors.d.ts +9 -0
  35. package/dist/cors.d.ts.map +1 -0
  36. package/dist/cors.js +34 -0
  37. package/dist/cors.js.map +1 -0
  38. package/dist/currents.d.ts +41 -0
  39. package/dist/currents.d.ts.map +1 -0
  40. package/dist/currents.js +172 -0
  41. package/dist/currents.js.map +1 -0
  42. package/dist/formBody.d.ts +2 -0
  43. package/dist/formBody.d.ts.map +1 -0
  44. package/dist/formBody.js +2 -0
  45. package/dist/formBody.js.map +1 -0
  46. package/dist/index.d.ts +20 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +14 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/jsonBody.d.ts +2 -0
  51. package/dist/jsonBody.d.ts.map +1 -0
  52. package/dist/jsonBody.js +2 -0
  53. package/dist/jsonBody.js.map +1 -0
  54. package/dist/multipartBody.d.ts +2 -0
  55. package/dist/multipartBody.d.ts.map +1 -0
  56. package/dist/multipartBody.js +2 -0
  57. package/dist/multipartBody.js.map +1 -0
  58. package/dist/router.d.ts +24 -0
  59. package/dist/router.d.ts.map +1 -0
  60. package/dist/router.js +113 -0
  61. package/dist/router.js.map +1 -0
  62. package/dist/security.d.ts +16 -0
  63. package/dist/security.d.ts.map +1 -0
  64. package/dist/security.js +34 -0
  65. package/dist/security.js.map +1 -0
  66. package/dist/static.d.ts +9 -0
  67. package/dist/static.d.ts.map +1 -0
  68. package/dist/static.js +71 -0
  69. package/dist/static.js.map +1 -0
  70. package/dist/textBody.d.ts +3 -0
  71. package/dist/textBody.d.ts.map +1 -0
  72. package/dist/textBody.js +4 -0
  73. package/dist/textBody.js.map +1 -0
  74. package/package.json +31 -0
package/README.md ADDED
@@ -0,0 +1,257 @@
1
+ # Currents
2
+
3
+ **Currents** is a lightweight pipeline-based API constructor, designed to cover 90% of API use cases.
4
+
5
+ ## Features
6
+
7
+ * 🚦 Routing
8
+ * 🌍 CORS headers
9
+ * 🍪 Cookie management
10
+ * 🛡️ Security headers
11
+ * 📂 Static file delivery
12
+ * 📦 Parsing of popular request bodies (JSON, multipart, etc.)
13
+ * ⚡ HTTP/2 support
14
+
15
+ ## Concept
16
+
17
+ Currents is **pipeline-based**: every route is treated as a chain of handlers. Instead of plugin registration, you just add or remove handlers from the chain. This gives you full control over every route.
18
+
19
+ ---
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install @tripod311/currents
25
+ ```
26
+
27
+ ---
28
+
29
+ ## Example
30
+
31
+ ```ts
32
+ import { Currents, Context, JsonBody, MultipartBody, ServeStatic } from "@tripod311/currents"
33
+
34
+ const app = Currents.fromOptions({});
35
+
36
+ app.get("/", [
37
+ (ctx: Context) => {
38
+ ctx.text("Hello world");
39
+ }
40
+ ]);
41
+
42
+ app.post('/table/:id', [
43
+ JsonBody,
44
+ (ctx: Context) => {
45
+ const body = ctx.body as { some: "body" };
46
+ ctx.json({ hello: "world" });
47
+ }
48
+ ]);
49
+
50
+ app.put('/images/*', [
51
+ MultipartBody,
52
+ (ctx: Context) => {
53
+ // some operations with body
54
+ ctx.binary(result_buffer);
55
+ }
56
+ ]);
57
+
58
+ app.get('/images/', [
59
+ ServeStatic({
60
+ basePath: '/images',
61
+ rootDir: '/home/me/images',
62
+ cacheControl: ["public", "max-age=0"],
63
+ fallback: 'default.png'
64
+ })
65
+ ])
66
+
67
+ app.server.listen({ port: 80 });
68
+ ```
69
+
70
+ ---
71
+
72
+ ## API
73
+
74
+ ### Currents
75
+
76
+ The main application class. Holds the server and provides the interface for routing.
77
+
78
+ #### Constructor
79
+
80
+ ```ts
81
+ Currents.fromOptions({
82
+ forceHttpVersion?: 1 | 2,
83
+ certificates: {
84
+ cert: "path-to-cert",
85
+ key: "path-to-key",
86
+ ca?: "path-to-ca"
87
+ }
88
+ })
89
+ ```
90
+
91
+ * Creates the app and sets up the server with given configuration.
92
+ * If you don’t force HTTP version: with certificates → defaults to **HTTP/2**, without → defaults to **HTTP/1**.
93
+
94
+ ```ts
95
+ Currents.fromServer(server: HttpServer | Http2Server)
96
+ ```
97
+
98
+ * Create Currents app with an already configured server.
99
+
100
+ #### Methods
101
+
102
+ ```ts
103
+ app.get(route: string, handlers: RouteHandler[])
104
+ app.post(route: string, handlers: RouteHandler[])
105
+ app.put(route: string, handlers: RouteHandler[])
106
+ app.delete(route: string, handlers: RouteHandler[])
107
+ app.any(route: string, handlers: RouteHandler[])
108
+ ```
109
+
110
+ #### Properties
111
+
112
+ ```ts
113
+ app.notFoundHandler(chain: RouteHandler[])
114
+ ```
115
+
116
+ Custom 404 handler. By default returns: `Cannot find ${route}`.
117
+
118
+ ```ts
119
+ app.errorHandler(handler: (err: any, ctx: Context) => void)
120
+ ```
121
+
122
+ Custom error handler.
123
+
124
+ ---
125
+
126
+ ### Context
127
+
128
+ Context represents a single request/response.
129
+
130
+ #### Properties
131
+
132
+ * `ctx.method: string` → Request method
133
+ * `ctx.path: string` → URL-decoded request path
134
+ * `ctx.headers: Record<string, string>` → Request headers
135
+ * `ctx.cookies: Record<string, string>` → Filled if you use `ParseCookies`
136
+ * `ctx.params: Record<string, string>` → Route params (`/table/:id`)
137
+ * `ctx.query: UrlSearchParams` → Query parameters
138
+ * `ctx.body: any` → Filled if body parsers are used
139
+ * `ctx.locals: Record<string, any>` → Custom data (pass between handlers)
140
+ * `ctx.finished: boolean` → Response already sent
141
+ * `ctx.notFound: boolean` → NotFound chain should be executed
142
+
143
+ #### Methods
144
+
145
+ * `ctx.responseHeader(header, value)` → set response header
146
+ * `ctx.status(code)` → set HTTP status
147
+ * `ctx.json(value)` → send JSON with proper header
148
+ * `ctx.text(value)` → send text response
149
+ * `ctx.binary(value)` → send buffer response
150
+ * `ctx.send(data, contentLength?)` → send custom buffer or stream
151
+ * `ctx.end()` → end response with empty body
152
+ * `ctx.redirect(to)` → 307 redirect
153
+ * `ctx.callNotFound()` → call default notFound chain
154
+
155
+ ---
156
+
157
+ ### Body parsers
158
+
159
+ Default handlers to populate `ctx.body`:
160
+
161
+ ```ts
162
+ import { BinaryBody, TextBody, JsonBody, FormBody, MultipartBody } from "@tripod311/currents"
163
+ ```
164
+
165
+ * **BinaryBody** → dumps buffer into body
166
+ * **TextBody** → UTF-8 string body
167
+ * **JsonBody** → parses JSON
168
+ * **FormBody** → parses `application/x-www-form-urlencoded`
169
+ * **MultipartBody** → parses multipart bodies
170
+
171
+ ---
172
+
173
+ ### Cookies
174
+
175
+ ```ts
176
+ import { Context, ParseCookies, SetCookie } from "@tripod311/currents"
177
+
178
+ app.get('/', [
179
+ ParseCookies(),
180
+ (ctx: Context) => {
181
+ ctx.cookies; // filled with cookies
182
+ SetCookie(ctx, 'myCookie', 'myValue', {
183
+ maxAge?: number,
184
+ expires?: Date,
185
+ httpOnly?: boolean,
186
+ secure?: boolean,
187
+ sameSite?: "Strict" | "Lax" | "None",
188
+ path?: string,
189
+ domain?: string
190
+ });
191
+ }
192
+ ])
193
+ ```
194
+
195
+ You can provide a secret string to `ParseCookies` if you want signed cookies.
196
+
197
+ ---
198
+
199
+ ### Static files
200
+
201
+ ```ts
202
+ import { ServeStatic } from "@tripod311/currents"
203
+
204
+ app.get('/*', [
205
+ ServeStatic({
206
+ basePath: '/',
207
+ rootDir: '/home/me/site',
208
+ cacheControl: ["public", "max-age=0"],
209
+ fallback: 'index.html'
210
+ })
211
+ ])
212
+ ```
213
+
214
+ * **cacheControl** and **fallback** are optional
215
+ * **basePath** defines which part of path should be cut before file lookup
216
+ * **fallback** is useful for SPA
217
+
218
+ ---
219
+
220
+ ### CORS
221
+
222
+ ```ts
223
+ import { Cors } from "@tripod311/currents"
224
+
225
+ app.get('/*', [
226
+ Cors({
227
+ allowedOrigin: string | string[],
228
+ allowedMethods?: string[],
229
+ allowedHeaders?: string[],
230
+ credentials?: boolean
231
+ })
232
+ ])
233
+ ```
234
+
235
+ ---
236
+
237
+ ### Security headers
238
+
239
+ ```ts
240
+ import { SecurityHeaders } from "@tripod311/currents"
241
+
242
+ app.get('/*', [
243
+ SecurityHeaders({
244
+ contentTypeOptions?: boolean,
245
+ xFrameOptions?: 'DENY' | 'SAMEORIGIN',
246
+ referrerPolicy?: "no-referrer" | "no-referrer-when-downgrade" | "origin" | "origin-when-cross-origin" | "same-origin" | "strict-origin" | "strict-origin-when-cross-origin" | "unsafe-url",
247
+ transportSecurity?: {
248
+ maxAge: number,
249
+ includeSubDomains?: boolean,
250
+ preload?: boolean
251
+ },
252
+ contentSecurityPolicy?: string,
253
+ crossOriginResourcePolicy?: 'same-origin' | 'same-site' | 'cross-origin',
254
+ permissionsPolicy?: string
255
+ })
256
+ ])
257
+ ```
@@ -0,0 +1,3 @@
1
+ import { Context } from "./context.js";
2
+ export default function BinaryBody(ctx: Context): Promise<void>;
3
+ //# sourceMappingURL=binaryBody.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binaryBody.d.ts","sourceRoot":"","sources":["../src/binaryBody.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,CAAC,OAAO,UAAU,UAAU,CAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAc/D"}
@@ -0,0 +1,14 @@
1
+ import { Context } from "./context.js";
2
+ export default function BinaryBody(ctx) {
3
+ return new Promise((resolve, reject) => {
4
+ ctx.body = Buffer.alloc(0);
5
+ const stream = ctx.raw.httpVersion === 1 ? ctx.raw.req : ctx.raw.stream;
6
+ stream.on('data', (chunk) => {
7
+ ctx.body = Buffer.concat([ctx.body, chunk]);
8
+ });
9
+ stream.on('end', () => {
10
+ resolve();
11
+ });
12
+ });
13
+ }
14
+ //# sourceMappingURL=binaryBody.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binaryBody.js","sourceRoot":"","sources":["../src/binaryBody.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA;AAEtC,MAAM,CAAC,OAAO,UAAU,UAAU,CAAE,GAAY;IAC/C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACtC,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAE3B,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC;QAExE,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YAC3B,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACrB,OAAO,EAAE,CAAC;QACX,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Context } from "../context.js";
2
+ export default function BinaryBody(ctx: Context): Promise<void>;
3
+ //# sourceMappingURL=binaryBody.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binaryBody.d.ts","sourceRoot":"","sources":["../../src/body/binaryBody.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAEvC,MAAM,CAAC,OAAO,UAAU,UAAU,CAAE,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAc/D"}
@@ -0,0 +1,14 @@
1
+ import { Context } from "../context.js";
2
+ export default function BinaryBody(ctx) {
3
+ return new Promise((resolve, reject) => {
4
+ ctx.body = Buffer.alloc(0);
5
+ const stream = ctx.raw.httpVersion === 1 ? ctx.raw.req : ctx.raw.stream;
6
+ stream.on('data', (chunk) => {
7
+ ctx.body = Buffer.concat([ctx.body, chunk]);
8
+ });
9
+ stream.on('end', () => {
10
+ resolve();
11
+ });
12
+ });
13
+ }
14
+ //# sourceMappingURL=binaryBody.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binaryBody.js","sourceRoot":"","sources":["../../src/body/binaryBody.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAEvC,MAAM,CAAC,OAAO,UAAU,UAAU,CAAE,GAAY;IAC/C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACtC,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAE3B,MAAM,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,WAAW,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC;QAExE,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YAC3B,GAAG,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACrB,OAAO,EAAE,CAAC;QACX,CAAC,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Context } from "../context.js";
2
+ export default function FormBody(ctx: Context): Promise<void>;
3
+ //# sourceMappingURL=formBody.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formBody.d.ts","sourceRoot":"","sources":["../../src/body/formBody.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAcvC,wBAA8B,QAAQ,CAAE,GAAG,EAAE,OAAO,iBAInD"}
@@ -0,0 +1,15 @@
1
+ import { Context } from "../context.js";
2
+ import TextBody from "./textBody.js";
3
+ function urlParamsToObject(params) {
4
+ const obj = {};
5
+ for (const key of params.keys()) {
6
+ const values = params.getAll(key);
7
+ obj[key] = values.length === 1 ? values[0] : values;
8
+ }
9
+ return obj;
10
+ }
11
+ export default async function FormBody(ctx) {
12
+ await TextBody(ctx);
13
+ ctx.body = urlParamsToObject(new URLSearchParams(ctx.body));
14
+ }
15
+ //# sourceMappingURL=formBody.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formBody.js","sourceRoot":"","sources":["../../src/body/formBody.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,QAAQ,MAAM,eAAe,CAAA;AAEpC,SAAS,iBAAiB,CAAC,MAAuB;IAChD,MAAM,GAAG,GAAsC,EAAE,CAAC;IAElD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAClC,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACtD,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,QAAQ,CAAE,GAAY;IACnD,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;IAEpB,GAAG,CAAC,IAAI,GAAG,iBAAiB,CAAC,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7D,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Context } from "../context.js";
2
+ export default function JsonBody(ctx: Context): Promise<void>;
3
+ //# sourceMappingURL=jsonBody.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonBody.d.ts","sourceRoot":"","sources":["../../src/body/jsonBody.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAGvC,wBAA8B,QAAQ,CAAE,GAAG,EAAE,OAAO,iBAInD"}
@@ -0,0 +1,7 @@
1
+ import { Context } from "../context.js";
2
+ import TextBody from "./textBody.js";
3
+ export default async function JsonBody(ctx) {
4
+ await TextBody(ctx);
5
+ ctx.body = JSON.parse(ctx.body);
6
+ }
7
+ //# sourceMappingURL=jsonBody.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jsonBody.js","sourceRoot":"","sources":["../../src/body/jsonBody.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,QAAQ,MAAM,eAAe,CAAA;AAEpC,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,QAAQ,CAAE,GAAY;IACnD,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;IAEpB,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Context } from "../context.js";
2
+ export default function MultipartBody(ctx: Context): Promise<void>;
3
+ //# sourceMappingURL=multipartBody.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multipartBody.d.ts","sourceRoot":"","sources":["../../src/body/multipartBody.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAcvC,wBAA8B,aAAa,CAAE,GAAG,EAAE,OAAO,iBAexD"}
@@ -0,0 +1,115 @@
1
+ import { Context } from "../context.js";
2
+ import BinaryBody from "./binaryBody.js";
3
+ const RN_MARK_2 = Buffer.from("\r\n\r\n", "utf8");
4
+ const RN_MARK = '\r\n';
5
+ export default async function MultipartBody(ctx) {
6
+ await BinaryBody(ctx);
7
+ let ct = ctx.headers["content-type"].split(';');
8
+ let boundary = "";
9
+ for (let i = 0; i < ct.length; i++) {
10
+ let str = ct[i].trim();
11
+ if (str.match(/^boundary\=.*$/)) {
12
+ boundary = str.slice(str.indexOf('=') + 1);
13
+ break;
14
+ }
15
+ }
16
+ if (!boundary)
17
+ throw new Error("MultipartBody error: No boundary");
18
+ ctx.body = parseMultipart(ctx.body, Buffer.from(boundary, "utf8"));
19
+ }
20
+ function deQuote(str) {
21
+ if (str[0] === '"' && str[str.length - 1] === '"') {
22
+ return str.slice(1, str.length - 1);
23
+ }
24
+ else {
25
+ return str;
26
+ }
27
+ }
28
+ function parseMultipart(body, boundary) {
29
+ const result = {};
30
+ let index = body.indexOf(boundary);
31
+ while (index != -1) {
32
+ // extracting the part. If there is next boundary, read until it, else read to end of buffer.
33
+ let part;
34
+ let nIndex = body.indexOf(boundary, index + boundary.length);
35
+ if (nIndex == -1) {
36
+ part = body.subarray(index + boundary.length + RN_MARK.length);
37
+ }
38
+ else {
39
+ part = body.subarray(index + boundary.length + RN_MARK.length, nIndex);
40
+ }
41
+ // extract headers from part
42
+ const headersIndex = part.indexOf(RN_MARK_2);
43
+ if (headersIndex === -1) {
44
+ if (nIndex === -1) {
45
+ break;
46
+ }
47
+ else {
48
+ index = nIndex;
49
+ continue;
50
+ }
51
+ }
52
+ const headers = part.subarray(0, headersIndex).toString("utf8").split(RN_MARK);
53
+ let isFile, fileName, partName, mimeType;
54
+ for (let i = 0; i < headers.length; i++) {
55
+ const header = headers[i];
56
+ if (header.startsWith("Content-Disposition")) {
57
+ const arr = header.split("; ").slice(1);
58
+ for (let j = 0; j < arr.length; j++) {
59
+ const pair = arr[j].split("=");
60
+ switch (pair[0]) {
61
+ case "name":
62
+ partName = pair[1];
63
+ break;
64
+ case "filename":
65
+ isFile = true;
66
+ fileName = pair[1];
67
+ break;
68
+ }
69
+ }
70
+ }
71
+ else if (header.startsWith("Content-Type")) {
72
+ mimeType = header.split(": ")[1];
73
+ }
74
+ }
75
+ if (!partName) {
76
+ if (nIndex === -1) {
77
+ break;
78
+ }
79
+ else {
80
+ index = nIndex;
81
+ continue;
82
+ }
83
+ }
84
+ // extract value
85
+ const fieldName = deQuote(partName);
86
+ let content;
87
+ if (isFile) {
88
+ content = {
89
+ fileName: deQuote(fileName || ""),
90
+ mimeType: mimeType || "application/octet-stream",
91
+ content: part.subarray(headersIndex + RN_MARK_2.length, part.length - RN_MARK.length)
92
+ };
93
+ }
94
+ else {
95
+ content = part.subarray(headersIndex + RN_MARK_2.length, part.length - RN_MARK.length).toString("utf8");
96
+ }
97
+ if (result[fieldName] === undefined) {
98
+ result[fieldName] = content;
99
+ }
100
+ else if (Array.isArray(result[fieldName])) {
101
+ result[fieldName].push(content);
102
+ }
103
+ else {
104
+ result[fieldName] = [result[fieldName], content];
105
+ }
106
+ if (nIndex === -1) {
107
+ break;
108
+ }
109
+ else {
110
+ index = nIndex;
111
+ }
112
+ }
113
+ return result;
114
+ }
115
+ //# sourceMappingURL=multipartBody.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multipartBody.js","sourceRoot":"","sources":["../../src/body/multipartBody.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Context } from "../context.js";
2
+ export default function TextBody(ctx: Context): Promise<void>;
3
+ //# sourceMappingURL=textBody.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textBody.d.ts","sourceRoot":"","sources":["../../src/body/textBody.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAGvC,wBAA8B,QAAQ,CAAE,GAAG,EAAE,OAAO,iBAInD"}
@@ -0,0 +1,7 @@
1
+ import { Context } from "../context.js";
2
+ import BinaryBody from "./binaryBody.js";
3
+ export default async function TextBody(ctx) {
4
+ await BinaryBody(ctx);
5
+ ctx.body = ctx.body.toString('utf-8');
6
+ }
7
+ //# sourceMappingURL=textBody.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textBody.js","sourceRoot":"","sources":["../../src/body/textBody.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,UAAU,MAAM,iBAAiB,CAAA;AAExC,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,QAAQ,CAAE,GAAY;IACnD,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;IAEtB,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;AACvC,CAAC"}
@@ -0,0 +1,43 @@
1
+ import { Readable } from "stream";
2
+ import { IncomingMessage, ServerResponse } from "http";
3
+ import type { ServerHttp2Stream, IncomingHttpHeaders } from "http2";
4
+ export interface RawHttp1 {
5
+ httpVersion: 1;
6
+ req: IncomingMessage;
7
+ res: ServerResponse;
8
+ }
9
+ export interface RawHttp2 {
10
+ httpVersion: 2;
11
+ stream: ServerHttp2Stream;
12
+ headers: IncomingHttpHeaders;
13
+ }
14
+ export type RawHttp = RawHttp1 | RawHttp2;
15
+ export declare class Context {
16
+ raw: RawHttp;
17
+ private _finished;
18
+ private _notFound;
19
+ method: string;
20
+ path: string;
21
+ headers: Record<string, string>;
22
+ cookies: Record<string, string>;
23
+ params: Record<string, string>;
24
+ query: URLSearchParams;
25
+ body: any;
26
+ locals: Record<string, any>;
27
+ private _status;
28
+ private _responseHeaders;
29
+ constructor(raw: RawHttp);
30
+ parsePath(): void;
31
+ responseHeader(header: string, value: string): Context;
32
+ status(code: number): Context;
33
+ json(data: any): void;
34
+ text(data: string): void;
35
+ binary(data: Buffer | Readable): void;
36
+ send(data: Buffer | Readable, contentLength?: number): void;
37
+ end(): void;
38
+ redirect(to: string): void;
39
+ callNotFound(): void;
40
+ get finished(): boolean;
41
+ get notFound(): boolean;
42
+ }
43
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AACjC,OAAO,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAA;AACtD,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,OAAO,CAAA;AAEnE,MAAM,WAAW,QAAQ;IACxB,WAAW,EAAE,CAAC,CAAC;IACf,GAAG,EAAE,eAAe,CAAC;IACrB,GAAG,EAAE,cAAc,CAAC;CACpB;AAED,MAAM,WAAW,QAAQ;IACxB,WAAW,EAAE,CAAC,CAAC;IACf,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,mBAAmB,CAAC;CAC7B;AAED,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE1C,qBAAa,OAAO;IACZ,GAAG,EAAE,OAAO,CAAC;IACpB,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,SAAS,CAAkB;IAE5B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM;IACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAM;IACpC,KAAK,EAAG,eAAe,CAAC;IACxB,IAAI,EAAE,GAAG,CAAC;IAEV,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAM;IAExC,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,gBAAgB,CAAyC;gBAEpD,GAAG,EAAE,OAAO;IAczB,SAAS;IAMT,cAAc,CAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO;IAevD,MAAM,CAAE,IAAI,EAAE,MAAM,GAAG,OAAO;IAK9B,IAAI,CAAE,IAAI,EAAE,GAAG;IAKf,IAAI,CAAE,IAAI,EAAE,MAAM;IAKlB,MAAM,CAAE,IAAI,EAAE,MAAM,GAAG,QAAQ;IAK/B,IAAI,CAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,aAAa,CAAC,EAAE,MAAM;IAmCrD,GAAG;IAiBH,QAAQ,CAAE,EAAE,EAAE,MAAM;IAIpB,YAAY;IAIZ,IAAI,QAAQ,IAAK,OAAO,CAEvB;IAED,IAAI,QAAQ,IAAK,OAAO,CAEvB;CACD"}