arri 0.0.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/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # server
2
+
3
+ This library was generated with [Nx](https://nx.dev).
4
+
5
+ ## Building
6
+
7
+ Run `nx build server` to build the library.
8
+
9
+ ## Running unit tests
10
+
11
+ Run `nx test server` to execute the unit tests via [Jest](https://jestjs.io).
package/dist/cli.cjs ADDED
@@ -0,0 +1,55 @@
1
+ #!/user/bin/env node
2
+ 'use strict';
3
+
4
+ const citty = require('citty');
5
+ const consola = require('consola');
6
+
7
+ const devLogger = consola.consola.create({});
8
+ consola.consola.create({});
9
+
10
+ const dev = citty.defineCommand({
11
+ meta: {
12
+ name: "dev"
13
+ },
14
+ args: {
15
+ config: {
16
+ type: "string",
17
+ description: "path to a config file",
18
+ default: "./arri.config.ts",
19
+ alias: "c",
20
+ valueHint: "./arri.config.ts"
21
+ }
22
+ },
23
+ run({ args }) {
24
+ devLogger.log(args.config);
25
+ }
26
+ });
27
+
28
+ const build = citty.defineCommand({
29
+ meta: {
30
+ name: "build"
31
+ },
32
+ args: {
33
+ config: {
34
+ type: "string",
35
+ alias: "c",
36
+ default: "./arri.config.ts",
37
+ valueHint: "./arri.config.ts"
38
+ }
39
+ },
40
+ run({ args }) {
41
+ devLogger.log("Running build");
42
+ devLogger.log(args.config);
43
+ }
44
+ });
45
+
46
+ const main = citty.defineCommand({
47
+ meta: {
48
+ name: "arri"
49
+ },
50
+ subCommands: {
51
+ dev,
52
+ build
53
+ }
54
+ });
55
+ citty.runMain(main);
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/dist/cli.mjs ADDED
@@ -0,0 +1,53 @@
1
+ #!/user/bin/env node
2
+ import { defineCommand, runMain } from 'citty';
3
+ import { consola } from 'consola';
4
+
5
+ const devLogger = consola.create({});
6
+ consola.create({});
7
+
8
+ const dev = defineCommand({
9
+ meta: {
10
+ name: "dev"
11
+ },
12
+ args: {
13
+ config: {
14
+ type: "string",
15
+ description: "path to a config file",
16
+ default: "./arri.config.ts",
17
+ alias: "c",
18
+ valueHint: "./arri.config.ts"
19
+ }
20
+ },
21
+ run({ args }) {
22
+ devLogger.log(args.config);
23
+ }
24
+ });
25
+
26
+ const build = defineCommand({
27
+ meta: {
28
+ name: "build"
29
+ },
30
+ args: {
31
+ config: {
32
+ type: "string",
33
+ alias: "c",
34
+ default: "./arri.config.ts",
35
+ valueHint: "./arri.config.ts"
36
+ }
37
+ },
38
+ run({ args }) {
39
+ devLogger.log("Running build");
40
+ devLogger.log(args.config);
41
+ }
42
+ });
43
+
44
+ const main = defineCommand({
45
+ meta: {
46
+ name: "arri"
47
+ },
48
+ subCommands: {
49
+ dev,
50
+ build
51
+ }
52
+ });
53
+ runMain(main);
package/dist/index.cjs ADDED
@@ -0,0 +1,149 @@
1
+ 'use strict';
2
+
3
+ const h3 = require('h3');
4
+ const h3Zod = require('h3-zod');
5
+
6
+ function isH3Error(input) {
7
+ if (typeof input !== "object" || input == null) {
8
+ return false;
9
+ }
10
+ const keys = Object.keys(input);
11
+ if (keys.includes("statusCode") && typeof input["statusCode"] === "number") {
12
+ return true;
13
+ }
14
+ return false;
15
+ }
16
+ function defineError(statusCode, opts = {}) {
17
+ const statusMessage = opts.statusMessage ?? opts.message;
18
+ const message = opts.message ?? opts.statusMessage;
19
+ return h3.createError({
20
+ statusCode,
21
+ ...opts,
22
+ statusMessage,
23
+ message
24
+ });
25
+ }
26
+
27
+ const defineRoute = (route) => route;
28
+ const defineMiddleware = (middleware) => middleware;
29
+ async function handleRoute(event, route, middlewares) {
30
+ const processedEvent = event;
31
+ try {
32
+ if (route.schema?.body) {
33
+ const body = await h3Zod.zh.useValidatedBody(event, route.schema.body);
34
+ processedEvent.context.body = body;
35
+ }
36
+ if (route.schema?.query) {
37
+ const query = await h3Zod.zh.useValidatedQuery(event, route.schema.query);
38
+ processedEvent.context.query = query;
39
+ }
40
+ for (const item of middlewares) {
41
+ await item(processedEvent);
42
+ }
43
+ if (processedEvent._handled) {
44
+ return;
45
+ }
46
+ const result = await route.handler(processedEvent);
47
+ await h3.send(processedEvent, result);
48
+ if (route.postHandler) {
49
+ processedEvent.context.response = result;
50
+ await route.postHandler(processedEvent);
51
+ }
52
+ } catch (err) {
53
+ if (isH3Error(err)) {
54
+ h3.setResponseStatus(processedEvent, err.statusCode);
55
+ h3.sendError(processedEvent, err);
56
+ }
57
+ h3.setResponseStatus(processedEvent, 500);
58
+ h3.sendError(
59
+ processedEvent,
60
+ defineError(500, {
61
+ statusMessage: "an unknown error occurred",
62
+ message: "an unknown error occurred",
63
+ data: err
64
+ })
65
+ );
66
+ }
67
+ }
68
+ function registerArriRoutes(app, routeMap) {
69
+ const routes = [];
70
+ Object.keys(routeMap).forEach((key) => {
71
+ const routeGetMap = routeMap[key];
72
+ Object.keys(routeGetMap).forEach((path) => {
73
+ routes.push(routeGetMap[path]);
74
+ });
75
+ });
76
+ for (const route of routes) {
77
+ registerArriRoute(app, route);
78
+ }
79
+ }
80
+ function registerArriRoute(app, route) {
81
+ app.use(
82
+ route.path,
83
+ h3.defineEventHandler(async (event) => {
84
+ const parsedContext = event.context;
85
+ parsedContext.params = event.context.params ?? {};
86
+ if (route.schema?.body && methodAllowsBody(route.method)) {
87
+ const body = await h3Zod.zh.useSafeValidatedBody(
88
+ event,
89
+ route.schema.body
90
+ );
91
+ if (!body || !body.success) {
92
+ throw defineError(400, {
93
+ statusMessage: "Invalid request body",
94
+ data: body.error.errors
95
+ });
96
+ }
97
+ parsedContext.body = body.data;
98
+ }
99
+ if (route.schema?.query) {
100
+ const query = await h3Zod.zh.useSafeValidatedQuery(
101
+ event,
102
+ route.schema.query
103
+ );
104
+ if (!query || !query.success) {
105
+ const params = [];
106
+ for (const err of query.error.errors) {
107
+ if (err.path.length) {
108
+ params.push(err.path[0]);
109
+ }
110
+ }
111
+ throw defineError(400, {
112
+ statusMessage: `Missing/invalid required url query parameters: [${params.join(
113
+ ", "
114
+ )}]`,
115
+ data: query.error.errors
116
+ });
117
+ }
118
+ parsedContext.query = query.data;
119
+ }
120
+ event.context = parsedContext;
121
+ const response = await route.handler(event);
122
+ event.context.response = response;
123
+ if (route.postHandler) {
124
+ await route.postHandler(event);
125
+ }
126
+ }),
127
+ { lazy: true }
128
+ );
129
+ }
130
+ const methodAllowsBody = (method) => {
131
+ switch (method) {
132
+ case "patch":
133
+ case "post":
134
+ case "put":
135
+ case "delete":
136
+ return true;
137
+ default:
138
+ return false;
139
+ }
140
+ };
141
+
142
+ exports.defineError = defineError;
143
+ exports.defineMiddleware = defineMiddleware;
144
+ exports.defineRoute = defineRoute;
145
+ exports.handleRoute = handleRoute;
146
+ exports.isH3Error = isH3Error;
147
+ exports.methodAllowsBody = methodAllowsBody;
148
+ exports.registerArriRoute = registerArriRoute;
149
+ exports.registerArriRoutes = registerArriRoutes;
@@ -0,0 +1,39 @@
1
+ import { H3Error, H3Event, RouterMethod, App } from 'h3';
2
+ import { ZodTypeAny, AnyZodObject } from 'zod';
3
+
4
+ declare function isH3Error(input: unknown): input is H3Error;
5
+ declare function defineError(statusCode: number, opts?: Partial<Omit<H3Error, "statusCode">>): H3Error;
6
+
7
+ type ExtractParam<Path, NextPart> = Path extends `:${infer Param}` ? Record<Param, string> & NextPart : NextPart;
8
+ type ExtractParams<Path> = Path extends `${infer Segment}/${infer Rest}` ? ExtractParam<Segment, ExtractParams<Rest>> : ExtractParam<Path, {}>;
9
+
10
+ interface RouteEventContext<Params extends Record<string, string> = any, Body = any, Query = any, Response = any> {
11
+ params?: Params;
12
+ body?: Body;
13
+ query?: Query;
14
+ response?: Response;
15
+ }
16
+ interface RouteEvent<Context extends RouteEventContext> extends H3Event {
17
+ context: Context;
18
+ }
19
+ type ArriRouteHandler<Params extends Record<string, string>, Body, Query, Response> = (event: RouteEvent<RouteEventContext<Params, Body, Query>>) => Response | Promise<Response>;
20
+ interface ArriRoute<Path extends string = "", Method extends RouterMethod = "get", Body extends undefined | ZodTypeAny = undefined, Query extends undefined | AnyZodObject = undefined, Response = any> {
21
+ id?: string;
22
+ path: Path;
23
+ method: Method;
24
+ schema?: {
25
+ body?: Body;
26
+ query?: Query;
27
+ };
28
+ handler: ArriRouteHandler<ExtractParams<Path>, Body extends ZodTypeAny ? Body["_type"] : undefined, Query extends AnyZodObject ? Query["_type"] : undefined, Response>;
29
+ postHandler?: (event: RouteEvent<RouteEventContext<ExtractParams<Path>, Body extends ZodTypeAny ? Body["_type"] : undefined, Query extends AnyZodObject ? Query["_type"] : undefined, Response>>) => any;
30
+ }
31
+ declare const defineRoute: <Path extends string, Method extends "get" | "head" | "patch" | "post" | "put" | "delete" | "connect" | "options" | "trace", Body_1 extends ZodTypeAny | undefined, Query extends AnyZodObject | undefined, Response_1 = any>(route: ArriRoute<Path, Method, Body_1, Query, Response_1>) => ArriRoute<Path, Method, Body_1, Query, Response_1>;
32
+ type ApiRouteMiddleware = (event: RouteEvent<RouteEventContext<Record<string, string>, any, any, undefined>>) => void | Promise<void>;
33
+ declare const defineMiddleware: (middleware: ApiRouteMiddleware) => ApiRouteMiddleware;
34
+ declare function handleRoute(event: H3Event, route: ArriRoute, middlewares: ApiRouteMiddleware[]): Promise<void>;
35
+ declare function registerArriRoutes(app: App, routeMap: any): void;
36
+ declare function registerArriRoute(app: App, route: ArriRoute): void;
37
+ declare const methodAllowsBody: (method: RouterMethod) => boolean;
38
+
39
+ export { ApiRouteMiddleware, ArriRoute, ArriRouteHandler, ExtractParam, ExtractParams, RouteEvent, RouteEventContext, defineError, defineMiddleware, defineRoute, handleRoute, isH3Error, methodAllowsBody, registerArriRoute, registerArriRoutes };
package/dist/index.mjs ADDED
@@ -0,0 +1,140 @@
1
+ import { createError, send, setResponseStatus, sendError, defineEventHandler } from 'h3';
2
+ import { zh } from 'h3-zod';
3
+
4
+ function isH3Error(input) {
5
+ if (typeof input !== "object" || input == null) {
6
+ return false;
7
+ }
8
+ const keys = Object.keys(input);
9
+ if (keys.includes("statusCode") && typeof input["statusCode"] === "number") {
10
+ return true;
11
+ }
12
+ return false;
13
+ }
14
+ function defineError(statusCode, opts = {}) {
15
+ const statusMessage = opts.statusMessage ?? opts.message;
16
+ const message = opts.message ?? opts.statusMessage;
17
+ return createError({
18
+ statusCode,
19
+ ...opts,
20
+ statusMessage,
21
+ message
22
+ });
23
+ }
24
+
25
+ const defineRoute = (route) => route;
26
+ const defineMiddleware = (middleware) => middleware;
27
+ async function handleRoute(event, route, middlewares) {
28
+ const processedEvent = event;
29
+ try {
30
+ if (route.schema?.body) {
31
+ const body = await zh.useValidatedBody(event, route.schema.body);
32
+ processedEvent.context.body = body;
33
+ }
34
+ if (route.schema?.query) {
35
+ const query = await zh.useValidatedQuery(event, route.schema.query);
36
+ processedEvent.context.query = query;
37
+ }
38
+ for (const item of middlewares) {
39
+ await item(processedEvent);
40
+ }
41
+ if (processedEvent._handled) {
42
+ return;
43
+ }
44
+ const result = await route.handler(processedEvent);
45
+ await send(processedEvent, result);
46
+ if (route.postHandler) {
47
+ processedEvent.context.response = result;
48
+ await route.postHandler(processedEvent);
49
+ }
50
+ } catch (err) {
51
+ if (isH3Error(err)) {
52
+ setResponseStatus(processedEvent, err.statusCode);
53
+ sendError(processedEvent, err);
54
+ }
55
+ setResponseStatus(processedEvent, 500);
56
+ sendError(
57
+ processedEvent,
58
+ defineError(500, {
59
+ statusMessage: "an unknown error occurred",
60
+ message: "an unknown error occurred",
61
+ data: err
62
+ })
63
+ );
64
+ }
65
+ }
66
+ function registerArriRoutes(app, routeMap) {
67
+ const routes = [];
68
+ Object.keys(routeMap).forEach((key) => {
69
+ const routeGetMap = routeMap[key];
70
+ Object.keys(routeGetMap).forEach((path) => {
71
+ routes.push(routeGetMap[path]);
72
+ });
73
+ });
74
+ for (const route of routes) {
75
+ registerArriRoute(app, route);
76
+ }
77
+ }
78
+ function registerArriRoute(app, route) {
79
+ app.use(
80
+ route.path,
81
+ defineEventHandler(async (event) => {
82
+ const parsedContext = event.context;
83
+ parsedContext.params = event.context.params ?? {};
84
+ if (route.schema?.body && methodAllowsBody(route.method)) {
85
+ const body = await zh.useSafeValidatedBody(
86
+ event,
87
+ route.schema.body
88
+ );
89
+ if (!body || !body.success) {
90
+ throw defineError(400, {
91
+ statusMessage: "Invalid request body",
92
+ data: body.error.errors
93
+ });
94
+ }
95
+ parsedContext.body = body.data;
96
+ }
97
+ if (route.schema?.query) {
98
+ const query = await zh.useSafeValidatedQuery(
99
+ event,
100
+ route.schema.query
101
+ );
102
+ if (!query || !query.success) {
103
+ const params = [];
104
+ for (const err of query.error.errors) {
105
+ if (err.path.length) {
106
+ params.push(err.path[0]);
107
+ }
108
+ }
109
+ throw defineError(400, {
110
+ statusMessage: `Missing/invalid required url query parameters: [${params.join(
111
+ ", "
112
+ )}]`,
113
+ data: query.error.errors
114
+ });
115
+ }
116
+ parsedContext.query = query.data;
117
+ }
118
+ event.context = parsedContext;
119
+ const response = await route.handler(event);
120
+ event.context.response = response;
121
+ if (route.postHandler) {
122
+ await route.postHandler(event);
123
+ }
124
+ }),
125
+ { lazy: true }
126
+ );
127
+ }
128
+ const methodAllowsBody = (method) => {
129
+ switch (method) {
130
+ case "patch":
131
+ case "post":
132
+ case "put":
133
+ case "delete":
134
+ return true;
135
+ default:
136
+ return false;
137
+ }
138
+ };
139
+
140
+ export { defineError, defineMiddleware, defineRoute, handleRoute, isH3Error, methodAllowsBody, registerArriRoute, registerArriRoutes };
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "arri",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "main": "./dist/index.cjs",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "bin": {
12
+ "arri": "./dist/cli.cjs"
13
+ },
14
+ "dependencies": {
15
+ "citty": "^0.1.2",
16
+ "consola": "^3.2.3",
17
+ "h3": "^1.7.1",
18
+ "h3-zod": "^0.5.1",
19
+ "zod": "^3.21.4"
20
+ }
21
+ }