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 +11 -0
- package/dist/cli.cjs +55 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.mjs +53 -0
- package/dist/index.cjs +149 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.mjs +140 -0
- package/package.json +21 -0
package/README.md
ADDED
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
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;
|
package/dist/index.d.ts
ADDED
|
@@ -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
|
+
}
|