@server/next 0.25.10 → 0.27.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 (63) hide show
  1. package/index.js +2005 -0
  2. package/package.json +17 -13
  3. package/readme.md +1 -0
  4. package/src/{helpers/jsx.js → jsx/jsx-dev-runtime.js} +32 -17
  5. package/src/{helpers/jsx.test.jsx → jsx/jsx-runtime.test.jsx} +1 -1
  6. package/src/ServerError.js +0 -27
  7. package/src/auth/NoSession.js +0 -19
  8. package/src/auth/auth-cookie.test.js +0 -42
  9. package/src/auth/auth-token.test.js +0 -110
  10. package/src/auth/auth.js +0 -62
  11. package/src/auth/index.js +0 -104
  12. package/src/auth/index.test.js +0 -133
  13. package/src/auth/logout.js +0 -20
  14. package/src/auth/providers/email.js +0 -145
  15. package/src/auth/providers/github.js +0 -84
  16. package/src/auth/providers/index.js +0 -4
  17. package/src/auth/session.js +0 -18
  18. package/src/auth/updateUser.js +0 -6
  19. package/src/auth/user.js +0 -9
  20. package/src/context/node.js +0 -68
  21. package/src/context/parseBody.js +0 -107
  22. package/src/context/parseBody.test.js +0 -60
  23. package/src/context/parseCookies.js +0 -9
  24. package/src/context/winter.js +0 -46
  25. package/src/errors/index.js +0 -36
  26. package/src/helpers/StatusError.js +0 -6
  27. package/src/helpers/bucket.js +0 -89
  28. package/src/helpers/bucket.test.js +0 -51
  29. package/src/helpers/color.js +0 -30
  30. package/src/helpers/config.js +0 -64
  31. package/src/helpers/cookies.test.js +0 -23
  32. package/src/helpers/cors.js +0 -24
  33. package/src/helpers/cors.test.js +0 -64
  34. package/src/helpers/createCookies.js +0 -16
  35. package/src/helpers/createId.js +0 -51
  36. package/src/helpers/define.js +0 -18
  37. package/src/helpers/getMachine.js +0 -26
  38. package/src/helpers/handleRequest.js +0 -34
  39. package/src/helpers/index.js +0 -11
  40. package/src/helpers/iterate.js +0 -8
  41. package/src/helpers/parseHeaders.js +0 -15
  42. package/src/helpers/toWeb.js +0 -15
  43. package/src/helpers/types.js +0 -81
  44. package/src/helpers/validate.js +0 -34
  45. package/src/index.d.ts +0 -198
  46. package/src/index.js +0 -268
  47. package/src/index.test.js +0 -87
  48. package/src/index.types.ts +0 -28
  49. package/src/middle/assets.js +0 -17
  50. package/src/middle/assets.test.js +0 -10
  51. package/src/middle/index.js +0 -7
  52. package/src/middle/openapi.js +0 -147
  53. package/src/middle/timer.js +0 -14
  54. package/src/parseResponse.js +0 -111
  55. package/src/pathPattern.js +0 -47
  56. package/src/pathPattern.test.js +0 -99
  57. package/src/polyfill.js +0 -18
  58. package/src/reply.js +0 -153
  59. package/src/router.js +0 -53
  60. package/src/router.test.js +0 -57
  61. package/src/session.test.js +0 -65
  62. package/src/test/toSucceed.js +0 -64
  63. package/src/url.test.js +0 -26
@@ -1,89 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
- import fsp from "node:fs/promises";
4
-
5
- function thinLocalBucket(root) {
6
- const absolute = (name) => {
7
- if (!name) throw new Error("File name is required");
8
- return path.resolve(path.join(root, name));
9
- };
10
-
11
- return {
12
- read: async (name) => {
13
- const fullPath = absolute(name);
14
- const stats = await fsp.stat(fullPath).catch(() => null);
15
- if (!stats || !stats.isFile()) return null;
16
-
17
- const nodeStream = fs.createReadStream(fullPath);
18
- return new ReadableStream({
19
- start(controller) {
20
- nodeStream.on("data", (chunk) => controller.enqueue(chunk));
21
- nodeStream.on("end", () => controller.close());
22
- nodeStream.on("error", (err) => controller.error(err));
23
- },
24
- cancel() {
25
- nodeStream.destroy();
26
- },
27
- });
28
- },
29
- write: (name, value, type) => {
30
- const fullPath = absolute(name);
31
- if (value) {
32
- return fsp.writeFile(fullPath, value, type).then(() => fullPath);
33
- }
34
- return fs.createWriteStream(fullPath);
35
- },
36
- delete: async (name) => {
37
- const fullPath = absolute(name);
38
- try {
39
- await fsp.unlink(fullPath);
40
- return true;
41
- } catch (error) {
42
- return false;
43
- }
44
- },
45
- };
46
- }
47
-
48
- function thinBunBucket(s3) {
49
- return {
50
- read: async (name) => {
51
- const file = s3.file(name);
52
- if (!(await file.exists())) return null;
53
- return await file.stream();
54
- },
55
- write: async (name, value) => {
56
- const file = s3.file(name);
57
- if (value) {
58
- await file.write(value);
59
- return name;
60
- }
61
- return s3.presign(name, { expiresIn: 3600, acl: "public-read-write" });
62
- },
63
- delete: async (name) => {
64
- const file = s3.file(name);
65
- if (!(await file.exists())) return null;
66
- return await file.delete();
67
- },
68
- };
69
- }
70
-
71
- // A fake tiny implementation of a generic bucket, it needs
72
- // at the very least a read(id) and write(id, value), both returning
73
- // promises. If possible both are also pipeable/streamable.
74
- export default function (root) {
75
- if (!root) return null;
76
-
77
- // Already a bucket, no need to do anything with it, just return it:
78
- if (typeof root === "string") {
79
- return thinLocalBucket(root);
80
- }
81
-
82
- // Bun's S3
83
- if (root.file && root.write) {
84
- return thinBunBucket(root);
85
- }
86
-
87
- // Assuming the base is already implementing our API
88
- return root;
89
- }
@@ -1,51 +0,0 @@
1
- import bucket from "./bucket.js";
2
- import fsp from "node:fs/promises";
3
- import path from "node:path";
4
- import fs from "node:fs";
5
-
6
- const localBucket = bucket("./tests/uploads/");
7
-
8
- describe("bucket", () => {
9
- afterAll(async () => {
10
- const filePath = path.resolve("./tests/uploads/testFile.txt");
11
- if (fs.existsSync(filePath)) {
12
- await fsp.unlink(filePath);
13
- }
14
- });
15
-
16
- it("writes a file", async () => {
17
- const filePath = await localBucket.write("testFile.txt", "Hello, World!");
18
- expect(filePath.endsWith("testFile.txt")).toBe(true);
19
- });
20
-
21
- it("reads a file", async () => {
22
- const stream = await localBucket.read("testFile.txt");
23
- expect(stream).not.toBeNull();
24
- let data = "";
25
- const reader = stream.getReader();
26
- while (true) {
27
- const { done, value } = await reader.read();
28
- if (done) break;
29
- data += new TextDecoder().decode(value);
30
- }
31
- expect(data).toBe("Hello, World!");
32
- });
33
-
34
- it("deletes a file", async () => {
35
- const filePath = path.resolve("./tests/uploads/testFile.txt");
36
- await fsp.unlink(filePath);
37
- const stream = await localBucket.read("testFile.txt");
38
- expect(stream).toBeNull();
39
- });
40
-
41
- it("removes an existing file", async () => {
42
- await localBucket.write("testFile.txt", "To be deleted");
43
- const isDeleted = await localBucket.delete("testFile.txt");
44
- expect(isDeleted).toBe(true);
45
- });
46
-
47
- it("tries to remove a non-existing file", async () => {
48
- const isDeleted = await localBucket.delete("nonExistentFile.txt");
49
- expect(isDeleted).toBe(false);
50
- });
51
- });
@@ -1,30 +0,0 @@
1
- // Add color to a string: color('hello {bright}world{/bright}')
2
- // or a template literal: color`hello {bright}world{/bright}`
3
- // Supports NO_COLOR, multiple styles, and closing with "{/}"
4
- // prettier-ignore
5
- const map = {
6
- reset: 0, bright: 1, dim: 2, under: 4, blink: 5, reverse: 7,
7
-
8
- black: 30, red: 31, green: 32, yellow: 33,
9
- blue: 34, magenta: 35, cyan: 36, white: 37,
10
-
11
- bgblack: 40, bgred: 41, bggreen: 42, bgyellow: 43,
12
- bgblue: 44, bgmagenta: 45, bgcyan: 46, bgwhite: 47,
13
- };
14
-
15
- const replace = (k) => {
16
- if (process.env.NO_COLOR) return "";
17
- if (!(k in map)) throw new Error(`"{${k}}" is not a valid color`);
18
- return `\x1b[${map[k]}m`;
19
- };
20
-
21
- export default function color(str, ...vals) {
22
- if (typeof str === "string") {
23
- return str
24
- .replaceAll(/\{(\w+)\}/g, (m, k) => replace(k))
25
- .replaceAll(/\{\/\w*\}/g, replace("reset"));
26
- }
27
-
28
- // Template literals, put them together first and then color them
29
- return color(str[0] + vals.map((v, i) => v + str[i + 1]).join(""));
30
- }
@@ -1,64 +0,0 @@
1
- import auth from "../auth/index.js";
2
- import Bucket from "./bucket.js";
3
- import createId from "./createId.js";
4
-
5
- // Big mess; parse all of the options for server, which can be at launch time
6
- // or dynamically per-request for the functions (so have to read ENV inside)
7
- export default function config(options = {}) {
8
- const env = globalThis.env;
9
-
10
- // Basic options
11
- options.port = options.port || env.PORT || 3000;
12
- options.secret = options.secret || env.SECRET || `unsafe-${createId()}`;
13
-
14
- // CORS
15
- options.cors = options.cors || env.CORS || null;
16
- if (options.cors) {
17
- if (options.cors === true) {
18
- options.cors = { origin: options.cors };
19
- }
20
- if (typeof options.cors === "string") {
21
- options.cors = { origin: options.cors };
22
- }
23
- if (Array.isArray(options.cors)) {
24
- options.cors = { origin: options.cors };
25
- }
26
- if (Array.isArray(options.cors.origin)) {
27
- options.cors.origin = options.cors.origin.join(",");
28
- }
29
- if (typeof options.cors.origin === "string") {
30
- options.cors.origin = options.cors.origin.toLowerCase();
31
- }
32
-
33
- if (!options.cors.methods) {
34
- options.cors.methods = "GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS";
35
- }
36
- if (!options.cors.headers) {
37
- options.cors.headers = "*";
38
- }
39
- }
40
-
41
- // Bucket
42
- options.views = options.views ? Bucket(options.views) : null;
43
- options.public = options.public ? Bucket(options.public) : null;
44
- options.uploads = options.uploads ? Bucket(options.uploads) : null;
45
-
46
- // Stores
47
- options.store = options.store ?? null;
48
- options.cookies = options.cookies ?? {};
49
- if (options.store && options.cookies) {
50
- options.session = { store: options.store.prefix("session:") };
51
- }
52
-
53
- // AUTH
54
- options.auth = auth.parseOptions(options.auth || env.AUTH || null, options);
55
-
56
- // OpenAPI
57
- if (options.openapi) {
58
- if (options.openapi === true) {
59
- options.openapi = {};
60
- }
61
- }
62
-
63
- return options;
64
- }
@@ -1,23 +0,0 @@
1
- import server, { cookies } from "../index.js";
2
-
3
- describe("set-cookie", () => {
4
- const app = server()
5
- .get("/hello", () => {
6
- return cookies({ hello: "world" }).send();
7
- })
8
- .get("/multiple", () => {
9
- return cookies({ a: "b", c: "d" }).send();
10
- });
11
-
12
- it("sets the right cookie", async () => {
13
- const api = app.test();
14
- const res = await api.get("/hello");
15
- expect(res.headers["set-cookie"]).toBe("hello=world;Path=/");
16
- });
17
-
18
- it("can set multiple cookies", async () => {
19
- const api = app.test();
20
- const res = await api.get("/multiple");
21
- expect(res.headers["set-cookie"]).toEqual(["a=b;Path=/", "c=d;Path=/"]);
22
- });
23
- });
@@ -1,24 +0,0 @@
1
- const localhost = /^https?:\/\/localhost(:\d+)?$/;
2
-
3
- // Based on https://expressjs.com/en/resources/middleware/cors.html#configuration-options
4
- export default function cors(config, origin = "") {
5
- origin = origin.toLowerCase();
6
-
7
- // When it's true, reflect the origin
8
- if (config === true) return origin || null;
9
-
10
- // A star should always return a star
11
- if (config === "*") return "*";
12
-
13
- // No origin, it's okay since that means we don't need CORS
14
- if (!origin) return null;
15
-
16
- // Coming from localhost
17
- if (localhost.test(origin)) return origin;
18
-
19
- const arr = Array.isArray(config) ? config : config.split(/\s*,\s*/g);
20
- if (arr.includes(origin)) return origin;
21
-
22
- console.warn(`CORS: Origin "${origin}" not allowed. Allowed "${config}"`);
23
- return null;
24
- }
@@ -1,64 +0,0 @@
1
- import server from "../index.js";
2
-
3
- const origin = "http://localhost:3000/";
4
-
5
- describe("cors", () => {
6
- it("can simply enable the cors", async () => {
7
- const cors = "*";
8
- const { headers } = await server({ cors })
9
- .get("/", () => 200)
10
- .test()
11
- .get("/", { headers: { origin } });
12
-
13
- expect(headers).toEqual({
14
- "access-control-allow-origin": "*",
15
- "access-control-allow-headers": "*",
16
- "access-control-allow-methods": "GET,POST,PUT,DELETE,PATCH,HEAD,OPTIONS",
17
- });
18
- });
19
-
20
- it("can disable the cors", async () => {
21
- const cors = false;
22
- const { headers } = await server({ cors })
23
- .get("/", () => 200)
24
- .test()
25
- .get("/", { headers: { origin } });
26
- expect(headers["access-control-allow-origin"]).toBe(undefined);
27
- });
28
-
29
- it("gets the wildcard without the origin", async () => {
30
- const cors = "*";
31
- const { headers } = await server({ cors })
32
- .get("/", () => 200)
33
- .test()
34
- .get("/");
35
- expect(headers["access-control-allow-origin"]).toBe("*");
36
- });
37
-
38
- it("gets the origin with true", async () => {
39
- const cors = true;
40
- const { headers } = await server({ cors })
41
- .get("/", () => 200)
42
- .test()
43
- .get("/", { headers: { origin } });
44
- expect(headers["access-control-allow-origin"]).toBe(origin);
45
- });
46
-
47
- it("gets the correct origin with multiple as string", async () => {
48
- const cors = "https://a.com/,https://b.com/";
49
- const { headers } = await server({ cors })
50
- .get("/", () => 200)
51
- .test()
52
- .get("/", { headers: { origin: "https://b.com/" } });
53
- expect(headers["access-control-allow-origin"]).toBe("https://b.com/");
54
- });
55
-
56
- it("gets the correct origin with multiple as array", async () => {
57
- const cors = ["https://a.com/", "https://b.com/"];
58
- const { headers } = await server({ cors })
59
- .get("/", () => 200)
60
- .test()
61
- .get("/", { headers: { origin: "https://b.com/" } });
62
- expect(headers["access-control-allow-origin"]).toBe("https://b.com/");
63
- });
64
- });
@@ -1,16 +0,0 @@
1
- // Takes an object and returns a string with the proper cookie values
2
- export default function createCookies(cookies) {
3
- if (!cookies || !Object.keys(cookies).length) return [];
4
- return Object.entries(cookies).map(([key, val]) => {
5
- if (!val) {
6
- val = { value: "", expires: new Date(0).toUTCString() };
7
- }
8
- if (typeof val === "string") {
9
- val = { value: val };
10
- }
11
- const { value, path, expires } = val;
12
- const pathPart = `;Path=${path || "/"}`;
13
- const expiresPart = expires ? `;Expires=${expires}` : "";
14
- return `${key}=${value || ""}${pathPart}${expiresPart}`;
15
- });
16
- }
@@ -1,51 +0,0 @@
1
- const alphabet =
2
- "useandom26T198340PX75pxJACKVERYMINDBUSHWOLFGQZbfghjklqvwyzrict";
3
-
4
- export const random = (bytes) => crypto.getRandomValues(new Uint8Array(bytes));
5
-
6
- // Credit: https://stackoverflow.com/a/52171480/938236
7
- const cyrb53 = (str, seed = 0) => {
8
- if (typeof str !== "string") str = String(str);
9
- let h1 = 0xdeadbeef ^ seed;
10
- let h2 = 0x41c6ce57 ^ seed;
11
- for (let i = 0, ch; i < str.length; i++) {
12
- ch = str.charCodeAt(i);
13
- h1 = Math.imul(h1 ^ ch, 2654435761);
14
- h2 = Math.imul(h2 ^ ch, 1597334677);
15
- }
16
- h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507);
17
- h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909);
18
- h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507);
19
- h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909);
20
-
21
- return 4294967296 * (2097151 & h2) + (h1 >>> 0);
22
- };
23
-
24
- const hash = (str, size) => {
25
- let chars = "";
26
-
27
- let num = cyrb53(str);
28
- for (let i = 0; i < size; i++) {
29
- if (num < alphabet.length) num = cyrb53(str, i);
30
- chars += alphabet[num % alphabet.length];
31
- num = Math.floor(num / alphabet.length);
32
- }
33
- return chars;
34
- };
35
-
36
- const randomId = (size = 16) => {
37
- let id = "";
38
- const bytes = random(size);
39
- while (size--) {
40
- // Using the bitwise AND operator to "cap" the value of
41
- // the random byte from 255 to 63, in that way we can make sure
42
- // that the value will be a valid index for the "chars" string.
43
- id += alphabet[bytes[size] & 61];
44
- }
45
- return id;
46
- };
47
-
48
- export default function createId(source, size = 16) {
49
- if (source) return hash(source, size);
50
- return randomId(size);
51
- }
@@ -1,18 +0,0 @@
1
- // An amazing lazy-definition. It will _not_ parse these properties
2
- // until needed, and once it has parsed them, it'll replace itself
3
- // with the value at once, hence it's called 0-1 times even if the
4
- // properties are accessed 0-N times
5
- export default function define(obj, key, cb) {
6
- Object.defineProperty(obj, key, {
7
- configurable: true,
8
- get() {
9
- const value = cb(obj);
10
- Object.defineProperty(obj, key, {
11
- configurable: true,
12
- writable: true,
13
- value,
14
- });
15
- return obj[key];
16
- },
17
- });
18
- }
@@ -1,26 +0,0 @@
1
- function getProvider() {
2
- if (typeof Netlify !== "undefined") return "netlify";
3
- return null;
4
- }
5
-
6
- function getRuntime() {
7
- if (typeof Bun !== "undefined") return "bun";
8
- if (typeof Deno !== "undefined") return "deno";
9
- if (globalThis.process?.versions?.node) return "node";
10
- return null;
11
- }
12
-
13
- function getProduction() {
14
- // Can I cry now?
15
- if (typeof Netlify !== "undefined")
16
- return Netlify.env.get("NETLIFY_DEV") !== "true";
17
- return process.env.NODE_ENV === "production";
18
- }
19
-
20
- export default function getMachine() {
21
- return {
22
- provider: getProvider(),
23
- runtime: getRuntime(),
24
- production: getProduction(),
25
- };
26
- }
@@ -1,34 +0,0 @@
1
- import parseResponse from "../parseResponse.js";
2
- import pathPattern from "../pathPattern.js";
3
- import define from "./define.js";
4
- import validate from "./validate.js";
5
-
6
- export default async function handleRequest(handlers, ctx) {
7
- for (const [method, matcher, ...cbs] of handlers[ctx.method]) {
8
- const match = pathPattern(matcher, ctx.url.pathname || "/");
9
- // Skip this whole middleware if there was no match
10
- if (!match) continue;
11
-
12
- define(ctx.url, "params", () => match);
13
-
14
- for (const cb of cbs) {
15
- if (typeof cb === "function") {
16
- const res = await cb(ctx);
17
- const out = await parseResponse(res, ctx);
18
- if (out) return out;
19
- } else {
20
- validate(ctx, cb);
21
- }
22
- }
23
-
24
- // When it's an HTTP method, break free after it's done (which will 404)
25
- if (method !== "*") break;
26
- }
27
-
28
- // In Netlify, a non-response is perfectly valid, which would indicate
29
- // the edge function to just go ahead and consume the original resource
30
- if (ctx.machine.provider === "netlify") return;
31
-
32
- // In other environments, a non-response is wrong and we should 404 then
33
- return new Response("Not Found", { status: 404 });
34
- }
@@ -1,11 +0,0 @@
1
- export { default as createCookies } from "./createCookies.js";
2
- export { default as createId } from "./createId.js";
3
- export { default as config } from "./config.js";
4
- export { default as cors } from "./cors.js";
5
- export { default as define } from "./define.js";
6
- export { default as getMachine } from "./getMachine.js";
7
- export { default as handleRequest } from "./handleRequest.js";
8
- export { default as iterate } from "./iterate.js";
9
- export { default as parseHeaders } from "./parseHeaders.js";
10
- export { default as toWeb } from "./toWeb.js";
11
- export { default as types } from "./types.js";
@@ -1,8 +0,0 @@
1
- export default async function iterate(stream, cb) {
2
- const reader = stream.getReader();
3
- while (true) {
4
- const chunk = await reader.read();
5
- if (chunk.done || !chunk.value) return;
6
- cb(chunk.value);
7
- }
8
- }
@@ -1,15 +0,0 @@
1
- export default (raw) => {
2
- const headers = {};
3
- for (let [key, value] of raw.entries()) {
4
- key = key.toLowerCase();
5
- if (headers[key]) {
6
- if (!Array.isArray(headers[key])) {
7
- headers[key] = [headers[key]];
8
- }
9
- headers[key].push(value);
10
- } else {
11
- headers[key] = value;
12
- }
13
- }
14
- return headers;
15
- };
@@ -1,15 +0,0 @@
1
- export default function toWeb(nodeStream) {
2
- if (typeof ReadableStream === "undefined") {
3
- throw new Error("Environment not supported, please report this as a bug");
4
- }
5
- return new ReadableStream({
6
- start(controller) {
7
- nodeStream.on("data", (chunk) => controller.enqueue(chunk));
8
- nodeStream.on("end", () => controller.close());
9
- nodeStream.on("error", (err) => controller.error(err));
10
- },
11
- cancel() {
12
- nodeStream.destroy();
13
- },
14
- });
15
- }
@@ -1,81 +0,0 @@
1
- // From https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
2
- export default {
3
- aac: "audio/aac",
4
- abw: "application/x-abiword",
5
- arc: "application/x-freearc",
6
- avif: "image/avif",
7
- avi: "video/x-msvideo",
8
- azw: "application/vnd.amazon.ebook",
9
- bin: "application/octet-stream",
10
- bmp: "image/bmp",
11
- bz: "application/x-bzip",
12
- bz2: "application/x-bzip2",
13
- cda: "application/x-cdf",
14
- csh: "application/x-csh",
15
- css: "text/css",
16
- csv: "text/csv",
17
- doc: "application/msword",
18
- docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
19
- eot: "application/vnd.ms-fontobject",
20
- epub: "application/epub+zip",
21
- gz: "application/gzip",
22
- gif: "image/gif",
23
- htm: "text/html",
24
- html: "text/html",
25
- ico: "image/vnd.microsoft.icon",
26
- ics: "text/calendar",
27
- jar: "application/java-archive",
28
- jpeg: "image/jpeg",
29
- jpg: "image/jpeg",
30
- js: "text/javascript",
31
- json: "application/json",
32
- jsonld: "application/ld+json",
33
- md: "text/markdown",
34
- mid: "audio/midi",
35
- midi: "audio/midi",
36
- mjs: "text/javascript",
37
- mp3: "audio/mpeg",
38
- mp4: "video/mp4",
39
- mpeg: "video/mpeg",
40
- mpkg: "application/vnd.apple.installer+xml",
41
- odp: "application/vnd.oasis.opendocument.presentation",
42
- ods: "application/vnd.oasis.opendocument.spreadsheet",
43
- odt: "application/vnd.oasis.opendocument.text",
44
- oga: "audio/ogg",
45
- ogv: "video/ogg",
46
- ogx: "application/ogg",
47
- opus: "audio/opus",
48
- otf: "font/otf",
49
- png: "image/png",
50
- pdf: "application/pdf",
51
- php: "application/x-httpd-php",
52
- ppt: "application/vnd.ms-powerpoint",
53
- pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
54
- rar: "application/vnd.rar",
55
- rtf: "application/rtf",
56
- sh: "application/x-sh",
57
- svg: "image/svg+xml",
58
- tar: "application/x-tar",
59
- text: "text/plain",
60
- tif: "image/tiff",
61
- tiff: "image/tiff",
62
- ts: "video/mp2t",
63
- ttf: "font/ttf",
64
- txt: "text/plain",
65
- vsd: "application/vnd.visio",
66
- wav: "audio/wav",
67
- weba: "audio/webm",
68
- webm: "video/webm",
69
- webp: "image/webp",
70
- woff: "font/woff",
71
- woff2: "font/woff2",
72
- xhtml: "application/xhtml+xml",
73
- xls: "application/vnd.ms-excel",
74
- xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
75
- xml: "application/xml",
76
- xul: "application/vnd.mozilla.xul+xml",
77
- zip: "application/zip",
78
- "3gp": "video/3gpp",
79
- "3g2": "video/3gpp2",
80
- "7z": "application/x-7z-compressed",
81
- };
@@ -1,34 +0,0 @@
1
- import StatusError from "./StatusError.js";
2
-
3
- export default function validate(ctx, schema) {
4
- if (!schema || typeof schema !== "object") return;
5
-
6
- let base;
7
- try {
8
- if (typeof schema?.body === "function") {
9
- base = "body";
10
- schema.body(ctx.body || {});
11
- }
12
- if (typeof schema?.body?.parse === "function") {
13
- base = "body";
14
- schema.body.parse(ctx.body || {});
15
- }
16
- if (typeof schema?.query === "function") {
17
- base = "query";
18
- schema.query(ctx.url.query || {});
19
- }
20
- if (typeof schema?.query?.parse === "function") {
21
- base = "query";
22
- schema.query.parse(ctx.url.query || {});
23
- }
24
- } catch (error) {
25
- if (error.name === "ZodError" || error.constructor.name === "ZodError") {
26
- const message = error.issues
27
- .map(({ path, message }) => `[${base}.${path.join(".")}]: ${message}`)
28
- .sort()
29
- .join("\n");
30
- throw new StatusError(message, 422);
31
- }
32
- throw error;
33
- }
34
- }