@arkstack/driver-h3 0.4.3 → 0.5.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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @arkstack/driver-h3
2
2
 
3
- H3 driver package for Arkstack providing H3-specific implementations of core Arkstack features such as routing, middleware, and database integration.
3
+ H3 driver for Arkstack, providing H3-based runtime integration for the framework.
4
4
 
5
5
  ## Auth Middleware
6
6
 
@@ -0,0 +1,50 @@
1
+ import { ArkstackKitDriver, ArkstackMiddlewareConfig, ArkstackRouteListOptions, PromiseOrValue } from "@arkstack/contract";
2
+ import { H3, H3Event, HTTPError, HTTPResponse } from "h3";
3
+ import { Router } from "clear-router/h3";
4
+ import { H3App, Handler, HttpContext, Middleware } from "clear-router/types/h3";
5
+ import { Route } from "clear-router";
6
+
7
+ //#region src/error-handler.d.ts
8
+ declare const defaultErrorHandler: (err: HTTPError | Error | string, event: H3Event) => HTTPResponse | {
9
+ error: boolean;
10
+ message: string;
11
+ status: "error";
12
+ code: number;
13
+ errors?: unknown;
14
+ stack?: string;
15
+ };
16
+ //#endregion
17
+ //#region src/Router.d.ts
18
+ declare class Router$1 extends Router {
19
+ static bind(app: H3): Promise<H3App>;
20
+ static list(_options: ArkstackRouteListOptions | undefined, app: H3): Promise<Route<HttpContext, Middleware, Handler>[]>;
21
+ }
22
+ //#endregion
23
+ //#region src/index.d.ts
24
+ type H3Middleware = Middleware | [Middleware, Record<string, any>];
25
+ interface H3DriverOptions {
26
+ bindRouter: (app: H3) => PromiseOrValue<void>;
27
+ mountPublicAssets?: (app: H3, publicPath: string) => PromiseOrValue<void>;
28
+ createApp?: () => H3;
29
+ onError?: (err: Error | string, event: H3Event) => unknown;
30
+ }
31
+ declare class H3EventResponse {
32
+ response: Response;
33
+ status: number;
34
+ statusText?: string;
35
+ constructor(response: Response);
36
+ get headers(): Headers;
37
+ }
38
+ declare class H3Driver extends ArkstackKitDriver<H3, H3Middleware> {
39
+ readonly name = "h3";
40
+ private readonly options;
41
+ constructor(options: H3DriverOptions);
42
+ createApp(): H3;
43
+ mountPublicAssets(app: H3, publicPath: string): PromiseOrValue<void>;
44
+ bindRouter(app: H3): PromiseOrValue<void>;
45
+ applyMiddleware(app: H3, middleware: H3Middleware | ArkstackMiddlewareConfig<H3Middleware>): void;
46
+ start(app: H3, port: number): void;
47
+ }
48
+ //#endregion
49
+ export { Router$1 as a, H3Middleware as i, H3DriverOptions as n, defaultErrorHandler as o, H3EventResponse as r, H3Driver as t };
50
+ //# sourceMappingURL=index-B3NOMsXC.d.ts.map
package/dist/index.d.ts CHANGED
@@ -1,33 +1,2 @@
1
- import { n as defaultErrorHandler, t as Router } from "./Router-CmVPb5OI.js";
2
- import { ArkstackKitDriver, ArkstackMiddlewareConfig, PromiseOrValue } from "@arkstack/contract";
3
- import { H3, H3Event } from "h3";
4
- import { Middleware } from "clear-router/types/h3";
5
-
6
- //#region src/index.d.ts
7
- type H3Middleware = Middleware | [Middleware, Record<string, any>];
8
- interface H3DriverOptions {
9
- bindRouter: (app: H3) => PromiseOrValue<void>;
10
- mountPublicAssets?: (app: H3, publicPath: string) => PromiseOrValue<void>;
11
- createApp?: () => H3;
12
- onError?: (err: Error | string, event: H3Event) => unknown;
13
- }
14
- declare class H3EventResponse {
15
- response: Response;
16
- status: number;
17
- statusText?: string;
18
- constructor(response: Response);
19
- get headers(): Headers;
20
- }
21
- declare class H3Driver extends ArkstackKitDriver<H3, H3Middleware> {
22
- readonly name = "h3";
23
- private readonly options;
24
- constructor(options: H3DriverOptions);
25
- createApp(): H3;
26
- mountPublicAssets(app: H3, publicPath: string): PromiseOrValue<void>;
27
- bindRouter(app: H3): PromiseOrValue<void>;
28
- applyMiddleware(app: H3, middleware: H3Middleware | ArkstackMiddlewareConfig<H3Middleware>): void;
29
- start(app: H3, port: number): void;
30
- }
31
- //#endregion
32
- export { H3Driver, H3DriverOptions, H3EventResponse, H3Middleware, Router, defaultErrorHandler };
33
- //# sourceMappingURL=index.d.ts.map
1
+ import { a as Router, i as H3Middleware, n as H3DriverOptions, o as defaultErrorHandler, r as H3EventResponse, t as H3Driver } from "./index-B3NOMsXC.js";
2
+ export { H3Driver, H3DriverOptions, H3EventResponse, H3Middleware, Router, defaultErrorHandler };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { staticAssetHandler } from "./middlewares/index.js";
1
+ import { t as staticAssetHandler } from "./middlewares-DIYzSTD5.js";
2
2
  import { ArkstackKitDriver } from "@arkstack/contract";
3
3
  import { H3, HTTPResponse, serve, toResponse } from "h3";
4
4
  import { ErrorHandler, Logger, importFile, renderError } from "@arkstack/common";
@@ -6,7 +6,6 @@ import { join } from "node:path";
6
6
  import { Router as Router$1 } from "clear-router/h3";
7
7
  import { clearRouterH3Plugin } from "@resora/plugin-clear-router";
8
8
  import { registerPlugin } from "resora";
9
-
10
9
  //#region src/error-handler.ts
11
10
  const defaultErrorHandler = (err, event) => {
12
11
  const responseBody = ErrorHandler.createErrorPayload(err);
@@ -32,18 +31,20 @@ const defaultErrorHandler = (err, event) => {
32
31
  headers: { "Content-Type": "text/html" }
33
32
  });
34
33
  };
35
-
36
34
  //#endregion
37
35
  //#region src/Router.ts
38
36
  registerPlugin(clearRouterH3Plugin);
37
+ Router$1.configure({ inferParamName: true });
39
38
  var Router = class extends Router$1 {
40
39
  static async bind(app) {
41
- await Router$1.group("/api", async () => {
42
- await importFile(join(process.cwd(), "src/routes/api.ts"));
43
- });
44
- await Router$1.group("/", async () => {
45
- await importFile(join(process.cwd(), "src/routes/web.ts"));
46
- });
40
+ try {
41
+ await Router$1.group("/api", async () => {
42
+ await importFile(join(process.cwd(), "src/routes/api.ts"));
43
+ });
44
+ await Router$1.group("/", async () => {
45
+ await importFile(join(process.cwd(), "src/routes/web.ts"));
46
+ });
47
+ } catch {}
47
48
  return Router$1.apply(app);
48
49
  }
49
50
  static async list(_options = {}, app) {
@@ -51,10 +52,10 @@ var Router = class extends Router$1 {
51
52
  return this.allRoutes();
52
53
  }
53
54
  };
54
-
55
55
  //#endregion
56
56
  //#region src/index.ts
57
57
  var H3EventResponse = class {
58
+ response;
58
59
  status = 200;
59
60
  statusText;
60
61
  constructor(response) {
@@ -146,7 +147,7 @@ var H3Driver = class extends ArkstackKitDriver {
146
147
  });
147
148
  }
148
149
  };
149
-
150
150
  //#endregion
151
151
  export { H3Driver, H3EventResponse, Router, defaultErrorHandler };
152
+
152
153
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["ClearRouter"],"sources":["../src/error-handler.ts","../src/Router.ts","../src/index.ts"],"sourcesContent":["import {\n ErrorHandler,\n renderError,\n} from '@arkstack/common'\nimport { H3Event, HTTPError, HTTPResponse } from 'h3'\n\nexport const defaultErrorHandler = (err: HTTPError | Error | string, event: H3Event) => {\n const responseBody = ErrorHandler.createErrorPayload(err)\n\n if (ErrorHandler.shouldLogError(err)) {\n ErrorHandler.logUnhandledError(err, {\n headers: Object.fromEntries(event.req.headers.entries()),\n method: event.req.method,\n url: event.req.url,\n }, 'Unhandled H3 request error')\n }\n\n if (process.env.NODE_ENV === 'development') console.error(responseBody)\n\n const code = ErrorHandler.normalizeStatusCode(responseBody.code)\n event.res.status = code\n\n const acceptsHeader = event.req.headers.get('accept') ?? ''\n const expectsJson = acceptsHeader.includes('application/json') || event.req._url?.pathname?.startsWith('/api')\n\n if (expectsJson) {\n return {\n ...responseBody,\n error: true,\n message: responseBody.message,\n }\n }\n\n return new HTTPResponse(renderError({\n message: String(responseBody.message),\n stack: typeof responseBody.stack === 'string' ? responseBody.stack : undefined,\n code,\n }), {\n status: code,\n headers: {\n 'Content-Type': 'text/html',\n },\n })\n}\n\nexport default defaultErrorHandler\n","import { ArkstackRouteListOptions } from '@arkstack/contract'\nimport { Router as ClearRouter } from 'clear-router/h3'\nimport { H3 } from 'h3'\nimport type { H3App, Handler, HttpContext, Middleware } from 'clear-router/types/h3'\nimport { type Route } from 'clear-router'\nimport { clearRouterH3Plugin } from '@resora/plugin-clear-router'\nimport { importFile } from '@arkstack/common'\nimport { join } from 'node:path'\nimport { registerPlugin } from 'resora'\n\nregisterPlugin(clearRouterH3Plugin)\n\nexport class Router extends ClearRouter {\n static async bind (app: H3): Promise<H3App> {\n // Register API routes\n await ClearRouter.group('/api', async () => {\n await importFile(join(process.cwd(), 'src/routes/api.ts'))\n })\n\n // Register web routes\n await ClearRouter.group('/', async () => {\n await importFile(join(process.cwd(), 'src/routes/web.ts'))\n })\n\n // Apply the registered routes to the H3 application\n const router = ClearRouter.apply(app)\n\n return router\n }\n\n static async list (\n _options: ArkstackRouteListOptions = {}, app: H3\n ): Promise<Route<HttpContext, Middleware, Handler>[]> {\n await this.bind(app)\n\n return this.allRoutes()\n }\n}\n","import { ArkstackKitDriver, ArkstackMiddlewareConfig, PromiseOrValue } from '@arkstack/contract'\nimport { H3, H3Event, serve, toResponse } from 'h3'\n\nimport { Middleware as H3BaseMiddleware } from 'clear-router/types/h3'\nimport { Logger } from '@arkstack/common'\nimport { defaultErrorHandler } from './error-handler'\nimport { staticAssetHandler } from './middlewares'\n\n// oxlint-disable-next-line typescript/no-explicit-any\nexport type H3Middleware = H3BaseMiddleware | [H3BaseMiddleware, Record<string, any>];\n\nexport interface H3DriverOptions {\n bindRouter: (app: H3) => PromiseOrValue<void>;\n mountPublicAssets?: (app: H3, publicPath: string) => PromiseOrValue<void>;\n createApp?: () => H3;\n onError?: (err: Error | string, event: H3Event) => unknown;\n}\n\nexport class H3EventResponse {\n status: number = 200\n statusText?: string\n\n constructor(public response: Response) {\n this.status = response.status\n this.statusText = response.statusText\n }\n\n get headers (): Headers {\n return this.response.headers\n }\n}\n\n/**\n * The H3Driver class implements the ArkstackKitDriver contract for the H3 framework.\n */\nexport class H3Driver extends ArkstackKitDriver<H3, H3Middleware> {\n readonly name = 'h3'\n private readonly options: H3DriverOptions\n\n /**\n * Creates an instance of H3Driver.\n * \n * @param options \n */\n constructor(options: H3DriverOptions) {\n super()\n this.options = options\n }\n\n /**\n * Creates an H3 application instance.\n * \n * @returns \n */\n createApp (): H3 {\n return this.options.createApp?.() ?? new H3({\n onError: this.options.onError ?? defaultErrorHandler,\n })\n }\n\n /**\n * Mounts static assets from the specified public path to the H3 application.\n * \n * @param app \n * @param publicPath \n */\n mountPublicAssets (app: H3, publicPath: string): PromiseOrValue<void> {\n if (this.options.mountPublicAssets) {\n return this.options.mountPublicAssets(app, publicPath)\n }\n\n app.use(staticAssetHandler(publicPath))\n }\n\n /**\n * Binds the router to the H3 application using the provided bindRouter function.\n * \n * @param app \n */\n bindRouter (app: H3): PromiseOrValue<void> {\n return this.options.bindRouter(app)\n }\n\n /**\n * Applies middleware to the H3 application.\n * \n * @param app \n * @param middleware \n */\n applyMiddleware (\n app: H3,\n middleware: H3Middleware | ArkstackMiddlewareConfig<H3Middleware>,\n ): void {\n const mw = Array.isArray(middleware) ? middleware[0] : middleware\n const conf = Array.isArray(middleware) && middleware[1] ? middleware[1] : {}\n\n if (typeof mw === 'function') {\n app.use(mw, conf)\n\n return\n }\n\n for (const [pos, entries] of Object.entries(middleware) as [string, H3Middleware[]][]) {\n for (const entry of entries) {\n const mw = Array.isArray(entry) ? entry[0] : entry\n const conf = Array.isArray(entry) && entry[1] ? entry[1] : {}\n\n if (pos === 'after') {\n app.use(async (evt, next) => {\n const response = await toResponse(await next(), evt)\n // evt.res.status = response.status\n evt[Symbol.for('h3.internal.event.res') as never] = new H3EventResponse(response) as never\n await mw(evt, next)\n next()\n }, conf)\n } else {\n app.use(mw, conf)\n }\n }\n }\n }\n\n /**\n * Starts the H3 server on the specified port.\n * \n * @param app \n * @param port \n */\n start (app: H3, port: number): void {\n serve(app, { port, silent: true }).ready().then(() => {\n Logger.log([\n ['Server is running on', 'white'],\n [`http://localhost:${port}`, 'cyan']\n ], ' ')\n })\n }\n}\n\nexport * from './error-handler'\nexport * from './Router'\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["ClearRouter"],"sources":["../src/error-handler.ts","../src/Router.ts","../src/index.ts"],"sourcesContent":["import {\n ErrorHandler,\n renderError,\n} from '@arkstack/common'\nimport { H3Event, HTTPError, HTTPResponse } from 'h3'\n\nexport const defaultErrorHandler = (err: HTTPError | Error | string, event: H3Event) => {\n const responseBody = ErrorHandler.createErrorPayload(err)\n\n if (ErrorHandler.shouldLogError(err)) {\n ErrorHandler.logUnhandledError(err, {\n headers: Object.fromEntries(event.req.headers.entries()),\n method: event.req.method,\n url: event.req.url,\n }, 'Unhandled H3 request error')\n }\n\n if (process.env.NODE_ENV === 'development') console.error(responseBody)\n\n const code = ErrorHandler.normalizeStatusCode(responseBody.code)\n event.res.status = code\n\n const acceptsHeader = event.req.headers.get('accept') ?? ''\n const expectsJson = acceptsHeader.includes('application/json') || event.req._url?.pathname?.startsWith('/api')\n\n if (expectsJson) {\n return {\n ...responseBody,\n error: true,\n message: responseBody.message,\n }\n }\n\n return new HTTPResponse(renderError({\n message: String(responseBody.message),\n stack: typeof responseBody.stack === 'string' ? responseBody.stack : undefined,\n code,\n }), {\n status: code,\n headers: {\n 'Content-Type': 'text/html',\n },\n })\n}\n\nexport default defaultErrorHandler\n","import { ArkstackRouteListOptions } from '@arkstack/contract'\nimport { Router as ClearRouter } from 'clear-router/h3'\nimport { H3 } from 'h3'\nimport type { H3App, Handler, HttpContext, Middleware } from 'clear-router/types/h3'\nimport { type Route } from 'clear-router'\nimport { clearRouterH3Plugin } from '@resora/plugin-clear-router'\nimport { importFile } from '@arkstack/common'\nimport { join } from 'node:path'\nimport { registerPlugin } from 'resora'\n\nregisterPlugin(clearRouterH3Plugin)\nClearRouter.configure({\n inferParamName: true\n})\n\nexport class Router extends ClearRouter {\n static async bind (app: H3): Promise<H3App> {\n try {\n // Register API routes\n await ClearRouter.group('/api', async () => {\n await importFile(join(process.cwd(), 'src/routes/api.ts'))\n })\n\n // Register web routes\n await ClearRouter.group('/', async () => {\n await importFile(join(process.cwd(), 'src/routes/web.ts'))\n })\n\n } catch { /** */ }\n\n // Apply the registered routes to the H3 application\n const router = ClearRouter.apply(app)\n\n return router\n }\n\n static async list (\n _options: ArkstackRouteListOptions = {}, app: H3\n ): Promise<Route<HttpContext, Middleware, Handler>[]> {\n await this.bind(app)\n\n return this.allRoutes() as never\n }\n}\n","import { ArkstackKitDriver, ArkstackMiddlewareConfig, PromiseOrValue } from '@arkstack/contract'\nimport { H3, H3Event, serve, toResponse } from 'h3'\n\nimport { Middleware as H3BaseMiddleware } from 'clear-router/types/h3'\nimport { Logger } from '@arkstack/common'\nimport { defaultErrorHandler } from './error-handler'\nimport { staticAssetHandler } from './middlewares'\n\n// oxlint-disable-next-line typescript/no-explicit-any\nexport type H3Middleware = H3BaseMiddleware | [H3BaseMiddleware, Record<string, any>];\n\nexport interface H3DriverOptions {\n bindRouter: (app: H3) => PromiseOrValue<void>;\n mountPublicAssets?: (app: H3, publicPath: string) => PromiseOrValue<void>;\n createApp?: () => H3;\n onError?: (err: Error | string, event: H3Event) => unknown;\n}\n\nexport class H3EventResponse {\n status: number = 200\n statusText?: string\n\n constructor(public response: Response) {\n this.status = response.status\n this.statusText = response.statusText\n }\n\n get headers (): Headers {\n return this.response.headers\n }\n}\n\n/**\n * The H3Driver class implements the ArkstackKitDriver contract for the H3 framework.\n */\nexport class H3Driver extends ArkstackKitDriver<H3, H3Middleware> {\n readonly name = 'h3'\n private readonly options: H3DriverOptions\n\n /**\n * Creates an instance of H3Driver.\n * \n * @param options \n */\n constructor(options: H3DriverOptions) {\n super()\n this.options = options\n }\n\n /**\n * Creates an H3 application instance.\n * \n * @returns \n */\n createApp (): H3 {\n return this.options.createApp?.() ?? new H3({\n onError: this.options.onError ?? defaultErrorHandler,\n })\n }\n\n /**\n * Mounts static assets from the specified public path to the H3 application.\n * \n * @param app \n * @param publicPath \n */\n mountPublicAssets (app: H3, publicPath: string): PromiseOrValue<void> {\n if (this.options.mountPublicAssets) {\n return this.options.mountPublicAssets(app, publicPath)\n }\n\n app.use(staticAssetHandler(publicPath))\n }\n\n /**\n * Binds the router to the H3 application using the provided bindRouter function.\n * \n * @param app \n */\n bindRouter (app: H3): PromiseOrValue<void> {\n return this.options.bindRouter(app)\n }\n\n /**\n * Applies middleware to the H3 application.\n * \n * @param app \n * @param middleware \n */\n applyMiddleware (\n app: H3,\n middleware: H3Middleware | ArkstackMiddlewareConfig<H3Middleware>,\n ): void {\n const mw = Array.isArray(middleware) ? middleware[0] : middleware\n const conf = Array.isArray(middleware) && middleware[1] ? middleware[1] : {}\n\n if (typeof mw === 'function') {\n app.use(mw, conf)\n\n return\n }\n\n for (const [pos, entries] of Object.entries(middleware) as [string, H3Middleware[]][]) {\n for (const entry of entries) {\n const mw = Array.isArray(entry) ? entry[0] : entry\n const conf = Array.isArray(entry) && entry[1] ? entry[1] : {}\n\n if (pos === 'after') {\n app.use(async (evt, next) => {\n const response = await toResponse(await next(), evt)\n // evt.res.status = response.status\n evt[Symbol.for('h3.internal.event.res') as never] = new H3EventResponse(response) as never\n await mw(evt, next)\n next()\n }, conf)\n } else {\n app.use(mw, conf)\n }\n }\n }\n }\n\n /**\n * Starts the H3 server on the specified port.\n * \n * @param app \n * @param port \n */\n start (app: H3, port: number): void {\n serve(app, { port, silent: true }).ready().then(() => {\n Logger.log([\n ['Server is running on', 'white'],\n [`http://localhost:${port}`, 'cyan']\n ], ' ')\n })\n }\n}\n\nexport * from './error-handler'\nexport * from './Router'\n"],"mappings":"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"}
@@ -1,11 +1,23 @@
1
- import "../Router-CmVPb5OI.js";
2
- import { H3Middleware } from "../index.js";
3
- import * as h3 from "h3";
1
+ import { i as H3Middleware } from "../index-B3NOMsXC.js";
2
+ import * as _$h3 from "h3";
4
3
  import { H3Event } from "h3";
4
+ import { NextFunction } from "clear-router/types/h3";
5
5
 
6
6
  //#region src/middlewares/auth.d.ts
7
7
  declare const auth: (event: H3Event, next: () => unknown | Promise<unknown>) => Promise<unknown>;
8
8
  //#endregion
9
+ //#region src/middlewares/cors.d.ts
10
+ declare const cors: (options?: {
11
+ origin?: string | string[] | RegExp | boolean;
12
+ methods?: string[] | string;
13
+ allowedHeaders?: string[] | string | null;
14
+ exposedHeaders?: string[] | string;
15
+ credentials?: boolean;
16
+ maxAge?: number | string;
17
+ optionsSuccessStatus?: number;
18
+ preflightContinue?: boolean;
19
+ }) => (event: H3Event, next: NextFunction) => Promise<void>;
20
+ //#endregion
9
21
  //#region src/middlewares/request-logger.d.ts
10
22
  declare const requestLogger: ({
11
23
  allowInProduction
@@ -14,7 +26,7 @@ declare const requestLogger: ({
14
26
  }) => H3Middleware;
15
27
  //#endregion
16
28
  //#region src/middlewares/static-asset-handler.d.ts
17
- declare const staticAssetHandler: (publicPath?: string) => (event: H3Event) => Promise<h3.HTTPResponse | undefined> | undefined;
29
+ declare const staticAssetHandler: (publicPath?: string) => (event: H3Event) => Promise<_$h3.HTTPResponse | undefined> | undefined;
18
30
  //#endregion
19
- export { auth, requestLogger, staticAssetHandler };
31
+ export { auth, cors, requestLogger, staticAssetHandler };
20
32
  //# sourceMappingURL=index.d.ts.map
@@ -1,111 +1,2 @@
1
- import { serveStatic } from "h3";
2
- import { Hook, Logger, nodeEnv } from "@arkstack/common";
3
- import { Auth, AuthenticationException } from "@arkstack/auth";
4
- import { readFile, stat } from "node:fs/promises";
5
- import { join, resolve } from "node:path";
6
-
7
- //#region src/middlewares/auth.ts
8
- const auth = async (event, next) => {
9
- try {
10
- const token = readBearerToken(event.req.headers.get("authorization"));
11
- if (!token) throw new AuthenticationException("Unauthenticated", {
12
- req: {
13
- headers: event.req.headers,
14
- method: event.req.method,
15
- url: event.req.url,
16
- path: getEventPath(event)
17
- },
18
- status: 401
19
- });
20
- if (Hook.has("middleware:auth", "before")) Hook.get("middleware:auth", "before")?.(event);
21
- const requestSource = {
22
- headers: event.req.headers,
23
- method: event.req.method,
24
- url: event.req.url,
25
- path: getEventPath(event)
26
- };
27
- const auth = Auth.make().setRequest(requestSource);
28
- const user = await auth.authorizeToken(token);
29
- event.context.user = user;
30
- event.context.auth = auth;
31
- event.context.authUser = user;
32
- event.context.authToken = token;
33
- event.req.user = user;
34
- event.req.auth = auth;
35
- event.req.authUser = user;
36
- event.req.authToken = token;
37
- if (Hook.has("middleware:auth", "after")) Hook.get("middleware:auth", "after")?.(event);
38
- return await next();
39
- } catch (error) {
40
- if (Hook.has("middleware:auth", "error")) Hook.get("middleware:auth", "error")?.(error, event);
41
- throw error;
42
- }
43
- };
44
- const readBearerToken = (authorization) => {
45
- if (!authorization?.startsWith("Bearer ")) return null;
46
- return authorization.substring(7);
47
- };
48
- const getEventPath = (event) => event.req._url?.pathname;
49
-
50
- //#endregion
51
- //#region src/middlewares/request-logger.ts
52
- const colors = {
53
- GET: "green",
54
- POST: "blue",
55
- PUT: "yellow",
56
- DELETE: "red",
57
- PATCH: "cyan"
58
- };
59
- /**
60
- * Middleware to log incoming requests and their response times.
61
- *
62
- * @param config Configuration options for the request logger middleware.
63
- * @param config.allowInProduction If true, the logger will also log requests in production environment. Default is false.
64
- * @returns H3Middleware function
65
- */
66
- const requestLogger = ({ allowInProduction = false } = {}) => async (event, next) => {
67
- if (nodeEnv() === "prod" && !allowInProduction) return next();
68
- await next();
69
- const start = Date.now();
70
- const req = event.req;
71
- const status = event.res.status || 200;
72
- const duration = Date.now() - start;
73
- Logger.log([
74
- [`[${req.method}]`, colors[req.method] || "green"],
75
- [req.url, "cyan"],
76
- [status.toString(), status >= 500 ? "red" : status >= 400 ? "yellow" : "green"],
77
- [`- ${duration}ms`, "dim"]
78
- ], " ");
79
- };
80
-
81
- //#endregion
82
- //#region src/middlewares/static-asset-handler.ts
83
- const staticAssetHandler = (publicPath = "public") => {
84
- const rootPath = resolve(process.cwd(), publicPath);
85
- return (event) => {
86
- const { pathname } = new URL(event.req.url);
87
- if (!/\.[a-zA-Z0-9]+$/.test(pathname)) return;
88
- if (pathname.startsWith("/.") || pathname.includes("..")) return;
89
- event.res.headers.set("Cache-Control", "public, max-age=31536000, immutable");
90
- event.res.headers.set("Access-Control-Allow-Origin", "*");
91
- event.res.headers.set("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS");
92
- event.res.headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization");
93
- return serveStatic(event, {
94
- indexNames: ["/index.html"],
95
- getContents: (id) => {
96
- return readFile(join(rootPath, id.replace(/^\/+/, ""))).catch(() => null);
97
- },
98
- getMeta: async (id) => {
99
- const stats = await stat(join(rootPath, id.replace(/^\/+/, ""))).catch(() => void 0);
100
- if (stats?.isFile()) return {
101
- size: stats.size,
102
- mtime: stats.mtimeMs
103
- };
104
- }
105
- });
106
- };
107
- };
108
-
109
- //#endregion
110
- export { auth, requestLogger, staticAssetHandler };
111
- //# sourceMappingURL=index.js.map
1
+ import { i as auth, n as requestLogger, r as cors, t as staticAssetHandler } from "../middlewares-DIYzSTD5.js";
2
+ export { auth, cors, requestLogger, staticAssetHandler };
@@ -0,0 +1,316 @@
1
+ import { serveStatic } from "h3";
2
+ import { Hook, Logger, nodeEnv } from "@arkstack/common";
3
+ import { Auth, AuthenticationException } from "@arkstack/auth";
4
+ import { readFile, stat } from "node:fs/promises";
5
+ import { join, resolve } from "node:path";
6
+ //#region src/middlewares/auth.ts
7
+ const auth = async (event, next) => {
8
+ try {
9
+ const token = readBearerToken(event.req.headers.get("authorization"));
10
+ if (!token) throw new AuthenticationException("Unauthenticated", {
11
+ req: {
12
+ headers: event.req.headers,
13
+ method: event.req.method,
14
+ url: event.req.url,
15
+ path: getEventPath(event)
16
+ },
17
+ status: 401
18
+ });
19
+ if (Hook.has("middleware:auth", "before")) Hook.get("middleware:auth", "before")?.(event);
20
+ const requestSource = {
21
+ headers: event.req.headers,
22
+ method: event.req.method,
23
+ url: event.req.url,
24
+ path: getEventPath(event)
25
+ };
26
+ const auth = Auth.make().setRequest(requestSource);
27
+ const user = await auth.authorizeToken(token);
28
+ event.context.user = user;
29
+ event.context.auth = auth;
30
+ event.context.authUser = user;
31
+ event.context.authToken = token;
32
+ event.req.user = user;
33
+ event.req.auth = auth;
34
+ event.req.authUser = user;
35
+ event.req.authToken = token;
36
+ if (Hook.has("middleware:auth", "after")) Hook.get("middleware:auth", "after")?.(event);
37
+ return await next();
38
+ } catch (error) {
39
+ if (Hook.has("middleware:auth", "error")) Hook.get("middleware:auth", "error")?.(error, event);
40
+ throw error;
41
+ }
42
+ };
43
+ const readBearerToken = (authorization) => {
44
+ if (!authorization?.startsWith("Bearer ")) return null;
45
+ return authorization.substring(7);
46
+ };
47
+ const getEventPath = (event) => event.req._url?.pathname;
48
+ //#endregion
49
+ //#region src/utils/vary.ts
50
+ /*!
51
+ * vary
52
+ * Copyright(c) 2014-2017 Douglas Christopher Wilson
53
+ * MIT Licensed
54
+ */
55
+ /**
56
+ * RegExp to match field-name in RFC 7230 sec 3.2
57
+ *
58
+ * field-name = token
59
+ * token = 1*tchar
60
+ * tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
61
+ * / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
62
+ * / DIGIT / ALPHA
63
+ * ; any VCHAR, except delimiters
64
+ */
65
+ const FIELD_NAME_REGEXP = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
66
+ /**
67
+ * Append a field to a vary header.
68
+ *
69
+ * @param header
70
+ * @param field
71
+ * @return
72
+ * @public
73
+ */
74
+ const append = (header, field) => {
75
+ if (typeof header !== "string") throw new TypeError("header argument is required");
76
+ if (!field) throw new TypeError("field argument is required");
77
+ const fields = !Array.isArray(field) ? parse(String(field)) : field;
78
+ for (let j = 0; j < fields.length; j++) if (!FIELD_NAME_REGEXP.test(fields[j])) throw new TypeError("field argument contains an invalid header name");
79
+ if (header === "*") return header;
80
+ let val = header;
81
+ const vals = parse(header.toLowerCase());
82
+ if (fields.indexOf("*") !== -1 || vals.indexOf("*") !== -1) return "*";
83
+ for (let i = 0; i < fields.length; i++) {
84
+ const fld = fields[i].toLowerCase();
85
+ if (vals.indexOf(fld) === -1) {
86
+ vals.push(fld);
87
+ val = val ? val + ", " + fields[i] : fields[i];
88
+ }
89
+ }
90
+ return val;
91
+ };
92
+ /**
93
+ * Parse a vary header into an array.
94
+ *
95
+ * @param header
96
+ * @return
97
+ * @private
98
+ */
99
+ const parse = (header) => {
100
+ let end = 0;
101
+ const list = [];
102
+ let start = 0;
103
+ for (let i = 0, len = header.length; i < len; i++) switch (header.charCodeAt(i)) {
104
+ case 32:
105
+ if (start === end) start = end = i + 1;
106
+ break;
107
+ case 44:
108
+ list.push(header.substring(start, end));
109
+ start = end = i + 1;
110
+ break;
111
+ default:
112
+ end = i + 1;
113
+ break;
114
+ }
115
+ list.push(header.substring(start, end));
116
+ return list;
117
+ };
118
+ /**
119
+ * Mark that a request is varied on a header field.
120
+ *
121
+ * @param res
122
+ * @param field
123
+ * @public
124
+ */
125
+ const vary = (res, field) => {
126
+ if (!res || !res.headers.get || !res.headers.set) throw new TypeError("res argument is required");
127
+ let val = res.headers.get("Vary") || "";
128
+ const header = Array.isArray(val) ? val.join(", ") : String(val);
129
+ if (!field) return res.headers.set("Vary", "*");
130
+ if (val = append(header, field)) res.headers.set("Vary", val);
131
+ };
132
+ //#endregion
133
+ //#region src/middlewares/cors.ts
134
+ const isString = (s) => {
135
+ return typeof s === "string" || s instanceof String;
136
+ };
137
+ const isOriginAllowed = (origin, allowedOrigin) => {
138
+ if (Array.isArray(allowedOrigin)) {
139
+ for (let i = 0; i < allowedOrigin.length; ++i) if (isOriginAllowed(origin, allowedOrigin[i])) return true;
140
+ return false;
141
+ } else if (isString(allowedOrigin)) return origin === allowedOrigin;
142
+ else if (allowedOrigin instanceof RegExp) return allowedOrigin.test(origin);
143
+ else return !!allowedOrigin;
144
+ };
145
+ const configureOrigin = (options, req) => {
146
+ let isAllowed;
147
+ const requestOrigin = req.headers.get("origin") || "*", headers = [];
148
+ if (!options.origin || options.origin === "*") headers.push([{
149
+ key: "Access-Control-Allow-Origin",
150
+ value: "*"
151
+ }]);
152
+ else if (isString(options.origin)) {
153
+ headers.push([{
154
+ key: "Access-Control-Allow-Origin",
155
+ value: options.origin
156
+ }]);
157
+ headers.push([{
158
+ key: "Vary",
159
+ value: "Origin"
160
+ }]);
161
+ } else {
162
+ isAllowed = isOriginAllowed(requestOrigin, options.origin);
163
+ headers.push([{
164
+ key: "Access-Control-Allow-Origin",
165
+ value: isAllowed ? requestOrigin : false
166
+ }]);
167
+ headers.push([{
168
+ key: "Vary",
169
+ value: "Origin"
170
+ }]);
171
+ }
172
+ return headers;
173
+ };
174
+ const configureMethods = (options) => {
175
+ let methods = options.methods;
176
+ if (Array.isArray(methods)) methods = methods.join(",");
177
+ return {
178
+ key: "Access-Control-Allow-Methods",
179
+ value: methods
180
+ };
181
+ };
182
+ const configureCredentials = (options) => {
183
+ if (options.credentials === true) return {
184
+ key: "Access-Control-Allow-Credentials",
185
+ value: "true"
186
+ };
187
+ return null;
188
+ };
189
+ const configureAllowedHeaders = (options, req) => {
190
+ let allowedHeaders = options.allowedHeaders || options.headers;
191
+ const headers = [];
192
+ if (!allowedHeaders) {
193
+ allowedHeaders = req.headers.get("access-control-request-headers");
194
+ headers.push([{
195
+ key: "Vary",
196
+ value: "Access-Control-Request-Headers"
197
+ }]);
198
+ } else if (Array.isArray(allowedHeaders)) allowedHeaders = allowedHeaders.join(",");
199
+ if (allowedHeaders && allowedHeaders.length) headers.push([{
200
+ key: "Access-Control-Allow-Headers",
201
+ value: allowedHeaders
202
+ }]);
203
+ return headers;
204
+ };
205
+ function configureExposedHeaders(options) {
206
+ let headers = options.exposedHeaders;
207
+ if (!headers) return null;
208
+ else if (Array.isArray(headers)) headers = headers.join(",");
209
+ if (headers && headers.length) return {
210
+ key: "Access-Control-Expose-Headers",
211
+ value: headers
212
+ };
213
+ return null;
214
+ }
215
+ function configureMaxAge(options) {
216
+ const maxAge = (typeof options.maxAge === "number" || options.maxAge) && options.maxAge.toString();
217
+ if (maxAge && maxAge.length) return {
218
+ key: "Access-Control-Max-Age",
219
+ value: maxAge
220
+ };
221
+ return null;
222
+ }
223
+ function applyHeaders(headers, res) {
224
+ for (let i = 0, n = headers.length; i < n; i++) {
225
+ const header = headers[i];
226
+ if (header) {
227
+ if (Array.isArray(header)) applyHeaders(header, res);
228
+ else if (header.key === "Vary" && header.value) vary(res, header.value);
229
+ else if (header.value) res.headers.set(header.key, header.value);
230
+ }
231
+ }
232
+ }
233
+ const cors = (options = {}) => async (event, next) => {
234
+ const headers = [];
235
+ if ((event.req.method && event.req.method.toUpperCase && event.req.method.toUpperCase()) === "OPTIONS") {
236
+ headers.push(configureOrigin(options, event.req));
237
+ headers.push(configureCredentials(options));
238
+ headers.push(configureMethods(options));
239
+ headers.push(configureAllowedHeaders(options, event.req));
240
+ headers.push(configureMaxAge(options));
241
+ headers.push(configureExposedHeaders(options));
242
+ applyHeaders(headers, event.res);
243
+ if (options.preflightContinue) next();
244
+ else {
245
+ event.res.status = options.optionsSuccessStatus;
246
+ event.res.headers.set("Content-Length", "0");
247
+ }
248
+ } else {
249
+ headers.push(configureOrigin(options, event.req));
250
+ headers.push(configureCredentials(options));
251
+ headers.push(configureExposedHeaders(options));
252
+ applyHeaders(headers, event.res);
253
+ next();
254
+ }
255
+ };
256
+ //#endregion
257
+ //#region src/middlewares/request-logger.ts
258
+ const colors = {
259
+ GET: "green",
260
+ POST: "blue",
261
+ PUT: "yellow",
262
+ DELETE: "red",
263
+ PATCH: "cyan"
264
+ };
265
+ /**
266
+ * Middleware to log incoming requests and their response times.
267
+ *
268
+ * @param config Configuration options for the request logger middleware.
269
+ * @param config.allowInProduction If true, the logger will also log requests in production environment. Default is false.
270
+ * @returns H3Middleware function
271
+ */
272
+ const requestLogger = ({ allowInProduction = false } = {}) => async (event, next) => {
273
+ if (nodeEnv() === "prod" && !allowInProduction) return next();
274
+ await next();
275
+ const start = Date.now();
276
+ const req = event.req;
277
+ const status = event.res.status || 200;
278
+ const duration = Date.now() - start;
279
+ Logger.log([
280
+ [`[${req.method}]`, colors[req.method] || "green"],
281
+ [req.url, "cyan"],
282
+ [status.toString(), status >= 500 ? "red" : status >= 400 ? "yellow" : "green"],
283
+ [`- ${duration}ms`, "dim"]
284
+ ], " ");
285
+ };
286
+ //#endregion
287
+ //#region src/middlewares/static-asset-handler.ts
288
+ const staticAssetHandler = (publicPath = "public") => {
289
+ const rootPath = resolve(process.cwd(), publicPath);
290
+ return (event) => {
291
+ const { pathname } = new URL(event.req.url);
292
+ if (!/\.[a-zA-Z0-9]+$/.test(pathname)) return;
293
+ if (pathname.startsWith("/.") || pathname.includes("..")) return;
294
+ event.res.headers.set("Cache-Control", "public, max-age=31536000, immutable");
295
+ event.res.headers.set("Access-Control-Allow-Origin", "*");
296
+ event.res.headers.set("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS");
297
+ event.res.headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization");
298
+ return serveStatic(event, {
299
+ indexNames: ["/index.html"],
300
+ getContents: (id) => {
301
+ return readFile(join(rootPath, id.replace(/^\/+/, ""))).catch(() => null);
302
+ },
303
+ getMeta: async (id) => {
304
+ const stats = await stat(join(rootPath, id.replace(/^\/+/, ""))).catch(() => void 0);
305
+ if (stats?.isFile()) return {
306
+ size: stats.size,
307
+ mtime: stats.mtimeMs
308
+ };
309
+ }
310
+ });
311
+ };
312
+ };
313
+ //#endregion
314
+ export { auth as i, requestLogger as n, cors as r, staticAssetHandler as t };
315
+
316
+ //# sourceMappingURL=middlewares-DIYzSTD5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middlewares-DIYzSTD5.js","names":[],"sources":["../src/middlewares/auth.ts","../src/utils/vary.ts","../src/middlewares/cors.ts","../src/middlewares/request-logger.ts","../src/middlewares/static-asset-handler.ts"],"sourcesContent":["import { Auth, AuthenticationException } from '@arkstack/auth'\n\nimport type { H3Event } from 'h3'\nimport { Hook } from '@arkstack/common'\n\nexport const auth = async (event: H3Event, next: () => unknown | Promise<unknown>) => {\n try {\n const token = readBearerToken(event.req.headers.get('authorization'))\n\n if (!token) {\n throw new AuthenticationException('Unauthenticated', {\n req: {\n headers: event.req.headers,\n method: event.req.method,\n url: event.req.url,\n path: getEventPath(event),\n },\n status: 401,\n })\n }\n\n if (Hook.has('middleware:auth', 'before'))\n Hook.get('middleware:auth', 'before')?.(event)\n\n const requestSource = {\n headers: event.req.headers,\n method: event.req.method,\n url: event.req.url,\n path: getEventPath(event),\n }\n const auth = Auth.make().setRequest(requestSource)\n const user = await auth.authorizeToken(token)\n\n event.context.user = user\n event.context.auth = auth\n event.context.authUser = user\n event.context.authToken = token;\n (event.req as any).user = user;\n (event.req as any).auth = auth;\n (event.req as any).authUser = user;\n (event.req as any).authToken = token\n\n if (Hook.has('middleware:auth', 'after'))\n Hook.get('middleware:auth', 'after')?.(event)\n\n return await next()\n } catch (error) {\n if (Hook.has('middleware:auth', 'error'))\n Hook.get('middleware:auth', 'error')?.(error, event)\n\n throw error\n }\n}\n\nconst readBearerToken = (authorization: string | null) => {\n if (!authorization?.startsWith('Bearer ')) {\n return null\n }\n\n return authorization.substring(7)\n}\n\nconst getEventPath = (event: H3Event) => event.req._url?.pathname\n","/*!\n * vary\n * Copyright(c) 2014-2017 Douglas Christopher Wilson\n * MIT Licensed\n */\nimport { H3Event } from 'h3'\n\n/**\n * RegExp to match field-name in RFC 7230 sec 3.2\n *\n * field-name = token\n * token = 1*tchar\n * tchar = \"!\" / \"#\" / \"$\" / \"%\" / \"&\" / \"'\" / \"*\"\n * / \"+\" / \"-\" / \".\" / \"^\" / \"_\" / \"`\" / \"|\" / \"~\"\n * / DIGIT / ALPHA\n * ; any VCHAR, except delimiters\n */\n\nconst FIELD_NAME_REGEXP = /^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$/\n\n/**\n * Append a field to a vary header.\n *\n * @param header\n * @param field\n * @return\n * @public\n */\nexport const append = (header: string, field: string | string[]) => {\n if (typeof header !== 'string') {\n throw new TypeError('header argument is required')\n }\n\n if (!field) {\n throw new TypeError('field argument is required')\n }\n\n // get fields array\n const fields = !Array.isArray(field) ? parse(String(field)) : field\n\n // assert on invalid field names\n for (let j = 0; j < fields.length; j++) {\n if (!FIELD_NAME_REGEXP.test(fields[j])) {\n throw new TypeError('field argument contains an invalid header name')\n }\n }\n\n // existing, unspecified vary\n if (header === '*') {\n return header\n }\n\n // enumerate current values\n let val = header\n const vals = parse(header.toLowerCase())\n\n // unspecified vary\n if (fields.indexOf('*') !== -1 || vals.indexOf('*') !== -1) {\n return '*'\n }\n\n for (let i = 0; i < fields.length; i++) {\n const fld = fields[i].toLowerCase()\n\n // append value (case-preserving)\n if (vals.indexOf(fld) === -1) {\n vals.push(fld)\n val = val ? val + ', ' + fields[i] : fields[i]\n }\n }\n\n return val\n}\n\n/**\n * Parse a vary header into an array.\n *\n * @param header\n * @return\n * @private\n */\n\nexport const parse = (header: string) => {\n let end = 0\n const list = []\n let start = 0\n\n // gather tokens\n for (let i = 0, len = header.length; i < len; i++) {\n switch (header.charCodeAt(i)) {\n case 0x20 /* */:\n if (start === end) {\n start = end = i + 1\n }\n break\n case 0x2c /* , */:\n list.push(header.substring(start, end))\n start = end = i + 1\n break\n default:\n end = i + 1\n break\n }\n }\n\n // final token\n list.push(header.substring(start, end))\n\n return list\n}\n\n/**\n * Mark that a request is varied on a header field.\n *\n * @param res\n * @param field\n * @public\n */\n\nexport const vary = (res?: H3Event['res'], field?: string | string[]) => {\n if (!res || !res.headers.get || !res.headers.set) {\n throw new TypeError('res argument is required')\n }\n\n // get existing header\n let val = res.headers.get('Vary') || ''\n const header = Array.isArray(val) ? val.join(', ') : String(val)\n\n if (!field) {\n return res.headers.set('Vary', '*')\n }\n\n // set new header\n if ((val = append(header, field))) {\n res.headers.set('Vary', val)\n }\n}\n","import { H3Event } from 'h3'\nimport { NextFunction } from 'clear-router/types/h3'\nimport { vary } from '../utils/vary'\n\nconst isString = (s: any) => {\n return typeof s === 'string' || s instanceof String\n}\n\nconst isOriginAllowed = (origin: string, allowedOrigin: string | string[] | RegExp | boolean) => {\n if (Array.isArray(allowedOrigin)) {\n for (let i = 0; i < allowedOrigin.length; ++i) {\n if (isOriginAllowed(origin, allowedOrigin[i])) {\n return true\n }\n }\n\n return false\n } else if (isString(allowedOrigin)) {\n return origin === allowedOrigin\n } else if (allowedOrigin instanceof RegExp) {\n return allowedOrigin.test(origin)\n } else {\n return !!allowedOrigin\n }\n}\n\nconst configureOrigin = (\n options: { origin?: string | string[] | RegExp | boolean },\n req: H3Event['req'],\n) => {\n let isAllowed: boolean\n const requestOrigin = req.headers.get('origin') || '*',\n headers = []\n\n if (!options.origin || options.origin === '*') {\n // allow any origin\n headers.push([\n {\n key: 'Access-Control-Allow-Origin',\n value: '*',\n },\n ])\n } else if (isString(options.origin)) {\n // fixed origin\n headers.push([\n {\n key: 'Access-Control-Allow-Origin',\n value: options.origin,\n },\n ])\n headers.push([\n {\n key: 'Vary',\n value: 'Origin',\n },\n ])\n } else {\n isAllowed = isOriginAllowed(requestOrigin, options.origin)\n // reflect origin\n headers.push([\n {\n key: 'Access-Control-Allow-Origin',\n value: isAllowed ? requestOrigin : false,\n },\n ])\n headers.push([\n {\n key: 'Vary',\n value: 'Origin',\n },\n ])\n }\n\n return headers\n}\n\nconst configureMethods = (options: { methods?: string[] | string }) => {\n let methods = options.methods\n if (Array.isArray(methods)) {\n methods = methods.join(',') // .methods is an array, so turn it into a string\n }\n\n return {\n key: 'Access-Control-Allow-Methods',\n value: methods,\n }\n}\n\nconst configureCredentials = (options: { credentials?: boolean }) => {\n if (options.credentials === true) {\n return {\n key: 'Access-Control-Allow-Credentials',\n value: 'true',\n }\n }\n\n return null\n}\n\nconst configureAllowedHeaders = (\n options: { allowedHeaders?: string[] | string | null; headers?: string[] | string | null },\n req: H3Event['req'],\n) => {\n let allowedHeaders = options.allowedHeaders || options.headers\n const headers = []\n\n if (!allowedHeaders) {\n allowedHeaders = req.headers.get('access-control-request-headers') // .headers wasn't specified, so reflect the request headers\n headers.push([\n {\n key: 'Vary',\n value: 'Access-Control-Request-Headers',\n },\n ])\n } else if (Array.isArray(allowedHeaders)) {\n allowedHeaders = allowedHeaders.join(',') // .headers is an array, so turn it into a string\n }\n if (allowedHeaders && allowedHeaders.length) {\n headers.push([\n {\n key: 'Access-Control-Allow-Headers',\n value: allowedHeaders,\n },\n ])\n }\n\n return headers\n}\n\nfunction configureExposedHeaders (options: { exposedHeaders?: string[] | string }) {\n let headers = options.exposedHeaders\n if (!headers) {\n return null\n } else if (Array.isArray(headers)) {\n headers = headers.join(',') // .headers is an array, so turn it into a string\n }\n if (headers && headers.length) {\n return {\n key: 'Access-Control-Expose-Headers',\n value: headers,\n }\n }\n\n return null\n}\n\nfunction configureMaxAge (options: { maxAge?: number | string }) {\n const maxAge = (typeof options.maxAge === 'number' || options.maxAge) && options.maxAge.toString()\n if (maxAge && maxAge.length) {\n return {\n key: 'Access-Control-Max-Age',\n value: maxAge,\n }\n }\n\n return null\n}\n\nfunction applyHeaders (headers: any[], res: H3Event['res']) {\n for (let i = 0, n = headers.length; i < n; i++) {\n const header = headers[i]\n if (header) {\n if (Array.isArray(header)) {\n applyHeaders(header, res)\n } else if (header.key === 'Vary' && header.value) {\n vary(res, header.value)\n } else if (header.value) {\n res.headers.set(header.key, header.value)\n }\n }\n }\n}\n\nexport const cors =\n (\n options: {\n origin?: string | string[] | RegExp | boolean;\n methods?: string[] | string;\n allowedHeaders?: string[] | string | null;\n exposedHeaders?: string[] | string;\n credentials?: boolean;\n maxAge?: number | string;\n optionsSuccessStatus?: number;\n preflightContinue?: boolean;\n } = {},\n ) =>\n async (event: H3Event, next: NextFunction) => {\n const headers = [],\n method = event.req.method && event.req.method.toUpperCase && event.req.method.toUpperCase()\n\n if (method === 'OPTIONS') {\n // preflight\n headers.push(configureOrigin(options, event.req))\n headers.push(configureCredentials(options))\n headers.push(configureMethods(options))\n headers.push(configureAllowedHeaders(options, event.req))\n headers.push(configureMaxAge(options))\n headers.push(configureExposedHeaders(options))\n applyHeaders(headers, event.res)\n\n if (options.preflightContinue) {\n next()\n } else {\n // Safari (and potentially other browsers) need content-length 0,\n // for 204 or they just hang waiting for a body\n event.res.status = options.optionsSuccessStatus\n event.res.headers.set('Content-Length', '0')\n }\n } else {\n // actual response\n headers.push(configureOrigin(options, event.req))\n headers.push(configureCredentials(options))\n headers.push(configureExposedHeaders(options))\n applyHeaders(headers, event.res)\n next()\n }\n }\n","import { Logger, nodeEnv } from '@arkstack/common'\n\nimport { H3Middleware } from '..'\n\nconst colors: Record<string, 'green' | 'blue' | 'yellow' | 'red' | 'cyan'> = {\n GET: 'green',\n POST: 'blue',\n PUT: 'yellow',\n DELETE: 'red',\n PATCH: 'cyan',\n}\n\n/**\n * Middleware to log incoming requests and their response times.\n * \n * @param config Configuration options for the request logger middleware.\n * @param config.allowInProduction If true, the logger will also log requests in production environment. Default is false. \n * @returns H3Middleware function\n */\nexport const requestLogger = ({\n allowInProduction = false,\n}: {\n allowInProduction?: boolean\n} = {}): H3Middleware => async (event, next) => {\n if (nodeEnv() === 'prod' && !allowInProduction) return next()\n\n await next()\n\n const start = Date.now()\n const req = event.req\n const status = event.res.status || 200\n const duration = Date.now() - start\n\n Logger.log([\n [`[${req.method}]`, colors[req.method] || 'green'],\n [req.url, 'cyan'],\n [status.toString(), status >= 500 ? 'red' : status >= 400 ? 'yellow' : 'green'],\n [`- ${duration}ms`, 'dim']\n ], ' ')\n}","import { H3Event, serveStatic } from 'h3'\nimport { readFile, stat } from 'node:fs/promises'\nimport { join, resolve } from 'node:path'\n\nexport const staticAssetHandler = (publicPath: string = 'public') => {\n const rootPath = resolve(process.cwd(), publicPath)\n\n return (event: H3Event) => {\n const { pathname } = new URL(event.req.url)\n\n if (!/\\.[a-zA-Z0-9]+$/.test(pathname)) return\n if (pathname.startsWith('/.') || pathname.includes('..')) return\n\n event.res.headers.set('Cache-Control', 'public, max-age=31536000, immutable')\n event.res.headers.set('Access-Control-Allow-Origin', '*')\n event.res.headers.set('Access-Control-Allow-Methods', 'GET, HEAD, OPTIONS')\n event.res.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization')\n\n return serveStatic(event, {\n indexNames: ['/index.html'],\n getContents: (id) => {\n const relativePath = id.replace(/^\\/+/, '')\n const file = join(rootPath, relativePath)\n\n return readFile(file).catch(() => null) as never\n },\n getMeta: async (id) => {\n const relativePath = id.replace(/^\\/+/, '')\n const file = join(rootPath, relativePath)\n const stats = await stat(file).catch(() => undefined)\n\n if (stats?.isFile()) {\n return {\n size: stats.size,\n mtime: stats.mtimeMs,\n }\n }\n },\n })\n }\n}"],"mappings":";;;;;;AAKA,MAAa,OAAO,OAAO,OAAgB,SAA2C;CAClF,IAAI;EACA,MAAM,QAAQ,gBAAgB,MAAM,IAAI,QAAQ,IAAI,gBAAgB,CAAC;EAErE,IAAI,CAAC,OACD,MAAM,IAAI,wBAAwB,mBAAmB;GACjD,KAAK;IACD,SAAS,MAAM,IAAI;IACnB,QAAQ,MAAM,IAAI;IAClB,KAAK,MAAM,IAAI;IACf,MAAM,aAAa,MAAM;IAC5B;GACD,QAAQ;GACX,CAAC;EAGN,IAAI,KAAK,IAAI,mBAAmB,SAAS,EACrC,KAAK,IAAI,mBAAmB,SAAS,GAAG,MAAM;EAElD,MAAM,gBAAgB;GAClB,SAAS,MAAM,IAAI;GACnB,QAAQ,MAAM,IAAI;GAClB,KAAK,MAAM,IAAI;GACf,MAAM,aAAa,MAAM;GAC5B;EACD,MAAM,OAAO,KAAK,MAAM,CAAC,WAAW,cAAc;EAClD,MAAM,OAAO,MAAM,KAAK,eAAe,MAAM;EAE7C,MAAM,QAAQ,OAAO;EACrB,MAAM,QAAQ,OAAO;EACrB,MAAM,QAAQ,WAAW;EACzB,MAAM,QAAQ,YAAY;EAC1B,MAAO,IAAY,OAAO;EAC1B,MAAO,IAAY,OAAO;EAC1B,MAAO,IAAY,WAAW;EAC9B,MAAO,IAAY,YAAY;EAE/B,IAAI,KAAK,IAAI,mBAAmB,QAAQ,EACpC,KAAK,IAAI,mBAAmB,QAAQ,GAAG,MAAM;EAEjD,OAAO,MAAM,MAAM;UACd,OAAO;EACZ,IAAI,KAAK,IAAI,mBAAmB,QAAQ,EACpC,KAAK,IAAI,mBAAmB,QAAQ,GAAG,OAAO,MAAM;EAExD,MAAM;;;AAId,MAAM,mBAAmB,kBAAiC;CACtD,IAAI,CAAC,eAAe,WAAW,UAAU,EACrC,OAAO;CAGX,OAAO,cAAc,UAAU,EAAE;;AAGrC,MAAM,gBAAgB,UAAmB,MAAM,IAAI,MAAM;;;;;;;;;;;;;;;;;;AC5CzD,MAAM,oBAAoB;;;;;;;;;AAU1B,MAAa,UAAU,QAAgB,UAA6B;CAChE,IAAI,OAAO,WAAW,UAClB,MAAM,IAAI,UAAU,8BAA8B;CAGtD,IAAI,CAAC,OACD,MAAM,IAAI,UAAU,6BAA6B;CAIrD,MAAM,SAAS,CAAC,MAAM,QAAQ,MAAM,GAAG,MAAM,OAAO,MAAM,CAAC,GAAG;CAG9D,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAC/B,IAAI,CAAC,kBAAkB,KAAK,OAAO,GAAG,EAClC,MAAM,IAAI,UAAU,iDAAiD;CAK7E,IAAI,WAAW,KACX,OAAO;CAIX,IAAI,MAAM;CACV,MAAM,OAAO,MAAM,OAAO,aAAa,CAAC;CAGxC,IAAI,OAAO,QAAQ,IAAI,KAAK,MAAM,KAAK,QAAQ,IAAI,KAAK,IACpD,OAAO;CAGX,KAAK,IAAI,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;EACpC,MAAM,MAAM,OAAO,GAAG,aAAa;EAGnC,IAAI,KAAK,QAAQ,IAAI,KAAK,IAAI;GAC1B,KAAK,KAAK,IAAI;GACd,MAAM,MAAM,MAAM,OAAO,OAAO,KAAK,OAAO;;;CAIpD,OAAO;;;;;;;;;AAWX,MAAa,SAAS,WAAmB;CACrC,IAAI,MAAM;CACV,MAAM,OAAO,EAAE;CACf,IAAI,QAAQ;CAGZ,KAAK,IAAI,IAAI,GAAG,MAAM,OAAO,QAAQ,IAAI,KAAK,KAC1C,QAAQ,OAAO,WAAW,EAAE,EAA5B;EACI,KAAK;GACD,IAAI,UAAU,KACV,QAAQ,MAAM,IAAI;GAEtB;EACJ,KAAK;GACD,KAAK,KAAK,OAAO,UAAU,OAAO,IAAI,CAAC;GACvC,QAAQ,MAAM,IAAI;GAClB;EACJ;GACI,MAAM,IAAI;GACV;;CAKZ,KAAK,KAAK,OAAO,UAAU,OAAO,IAAI,CAAC;CAEvC,OAAO;;;;;;;;;AAWX,MAAa,QAAQ,KAAsB,UAA8B;CACrE,IAAI,CAAC,OAAO,CAAC,IAAI,QAAQ,OAAO,CAAC,IAAI,QAAQ,KACzC,MAAM,IAAI,UAAU,2BAA2B;CAInD,IAAI,MAAM,IAAI,QAAQ,IAAI,OAAO,IAAI;CACrC,MAAM,SAAS,MAAM,QAAQ,IAAI,GAAG,IAAI,KAAK,KAAK,GAAG,OAAO,IAAI;CAEhE,IAAI,CAAC,OACD,OAAO,IAAI,QAAQ,IAAI,QAAQ,IAAI;CAIvC,IAAK,MAAM,OAAO,QAAQ,MAAM,EAC5B,IAAI,QAAQ,IAAI,QAAQ,IAAI;;;;AClIpC,MAAM,YAAY,MAAW;CAC3B,OAAO,OAAO,MAAM,YAAY,aAAa;;AAG/C,MAAM,mBAAmB,QAAgB,kBAAwD;CAC/F,IAAI,MAAM,QAAQ,cAAc,EAAE;EAChC,KAAK,IAAI,IAAI,GAAG,IAAI,cAAc,QAAQ,EAAE,GAC1C,IAAI,gBAAgB,QAAQ,cAAc,GAAG,EAC3C,OAAO;EAIX,OAAO;QACF,IAAI,SAAS,cAAc,EAChC,OAAO,WAAW;MACb,IAAI,yBAAyB,QAClC,OAAO,cAAc,KAAK,OAAO;MAEjC,OAAO,CAAC,CAAC;;AAIb,MAAM,mBACJ,SACA,QACG;CACH,IAAI;CACJ,MAAM,gBAAgB,IAAI,QAAQ,IAAI,SAAS,IAAI,KACjD,UAAU,EAAE;CAEd,IAAI,CAAC,QAAQ,UAAU,QAAQ,WAAW,KAExC,QAAQ,KAAK,CACX;EACE,KAAK;EACL,OAAO;EACR,CACF,CAAC;MACG,IAAI,SAAS,QAAQ,OAAO,EAAE;EAEnC,QAAQ,KAAK,CACX;GACE,KAAK;GACL,OAAO,QAAQ;GAChB,CACF,CAAC;EACF,QAAQ,KAAK,CACX;GACE,KAAK;GACL,OAAO;GACR,CACF,CAAC;QACG;EACL,YAAY,gBAAgB,eAAe,QAAQ,OAAO;EAE1D,QAAQ,KAAK,CACX;GACE,KAAK;GACL,OAAO,YAAY,gBAAgB;GACpC,CACF,CAAC;EACF,QAAQ,KAAK,CACX;GACE,KAAK;GACL,OAAO;GACR,CACF,CAAC;;CAGJ,OAAO;;AAGT,MAAM,oBAAoB,YAA6C;CACrE,IAAI,UAAU,QAAQ;CACtB,IAAI,MAAM,QAAQ,QAAQ,EACxB,UAAU,QAAQ,KAAK,IAAI;CAG7B,OAAO;EACL,KAAK;EACL,OAAO;EACR;;AAGH,MAAM,wBAAwB,YAAuC;CACnE,IAAI,QAAQ,gBAAgB,MAC1B,OAAO;EACL,KAAK;EACL,OAAO;EACR;CAGH,OAAO;;AAGT,MAAM,2BACJ,SACA,QACG;CACH,IAAI,iBAAiB,QAAQ,kBAAkB,QAAQ;CACvD,MAAM,UAAU,EAAE;CAElB,IAAI,CAAC,gBAAgB;EACnB,iBAAiB,IAAI,QAAQ,IAAI,iCAAiC;EAClE,QAAQ,KAAK,CACX;GACE,KAAK;GACL,OAAO;GACR,CACF,CAAC;QACG,IAAI,MAAM,QAAQ,eAAe,EACtC,iBAAiB,eAAe,KAAK,IAAI;CAE3C,IAAI,kBAAkB,eAAe,QACnC,QAAQ,KAAK,CACX;EACE,KAAK;EACL,OAAO;EACR,CACF,CAAC;CAGJ,OAAO;;AAGT,SAAS,wBAAyB,SAAiD;CACjF,IAAI,UAAU,QAAQ;CACtB,IAAI,CAAC,SACH,OAAO;MACF,IAAI,MAAM,QAAQ,QAAQ,EAC/B,UAAU,QAAQ,KAAK,IAAI;CAE7B,IAAI,WAAW,QAAQ,QACrB,OAAO;EACL,KAAK;EACL,OAAO;EACR;CAGH,OAAO;;AAGT,SAAS,gBAAiB,SAAuC;CAC/D,MAAM,UAAU,OAAO,QAAQ,WAAW,YAAY,QAAQ,WAAW,QAAQ,OAAO,UAAU;CAClG,IAAI,UAAU,OAAO,QACnB,OAAO;EACL,KAAK;EACL,OAAO;EACR;CAGH,OAAO;;AAGT,SAAS,aAAc,SAAgB,KAAqB;CAC1D,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,IAAI,GAAG,KAAK;EAC9C,MAAM,SAAS,QAAQ;EACvB,IAAI;OACE,MAAM,QAAQ,OAAO,EACvB,aAAa,QAAQ,IAAI;QACpB,IAAI,OAAO,QAAQ,UAAU,OAAO,OACzC,KAAK,KAAK,OAAO,MAAM;QAClB,IAAI,OAAO,OAChB,IAAI,QAAQ,IAAI,OAAO,KAAK,OAAO,MAAM;;;;AAMjD,MAAa,QAET,UASI,EAAE,KAEN,OAAO,OAAgB,SAAuB;CAC5C,MAAM,UAAU,EAAE;CAGlB,KAFW,MAAM,IAAI,UAAU,MAAM,IAAI,OAAO,eAAe,MAAM,IAAI,OAAO,aAAa,MAE9E,WAAW;EAExB,QAAQ,KAAK,gBAAgB,SAAS,MAAM,IAAI,CAAC;EACjD,QAAQ,KAAK,qBAAqB,QAAQ,CAAC;EAC3C,QAAQ,KAAK,iBAAiB,QAAQ,CAAC;EACvC,QAAQ,KAAK,wBAAwB,SAAS,MAAM,IAAI,CAAC;EACzD,QAAQ,KAAK,gBAAgB,QAAQ,CAAC;EACtC,QAAQ,KAAK,wBAAwB,QAAQ,CAAC;EAC9C,aAAa,SAAS,MAAM,IAAI;EAEhC,IAAI,QAAQ,mBACV,MAAM;OACD;GAGL,MAAM,IAAI,SAAS,QAAQ;GAC3B,MAAM,IAAI,QAAQ,IAAI,kBAAkB,IAAI;;QAEzC;EAEL,QAAQ,KAAK,gBAAgB,SAAS,MAAM,IAAI,CAAC;EACjD,QAAQ,KAAK,qBAAqB,QAAQ,CAAC;EAC3C,QAAQ,KAAK,wBAAwB,QAAQ,CAAC;EAC9C,aAAa,SAAS,MAAM,IAAI;EAChC,MAAM;;;;;AClNd,MAAM,SAAuE;CACzE,KAAK;CACL,MAAM;CACN,KAAK;CACL,QAAQ;CACR,OAAO;CACV;;;;;;;;AASD,MAAa,iBAAiB,EAC1B,oBAAoB,UAGpB,EAAE,KAAmB,OAAO,OAAO,SAAS;CAC5C,IAAI,SAAS,KAAK,UAAU,CAAC,mBAAmB,OAAO,MAAM;CAE7D,MAAM,MAAM;CAEZ,MAAM,QAAQ,KAAK,KAAK;CACxB,MAAM,MAAM,MAAM;CAClB,MAAM,SAAS,MAAM,IAAI,UAAU;CACnC,MAAM,WAAW,KAAK,KAAK,GAAG;CAE9B,OAAO,IAAI;EACP,CAAC,IAAI,IAAI,OAAO,IAAI,OAAO,IAAI,WAAW,QAAQ;EAClD,CAAC,IAAI,KAAK,OAAO;EACjB,CAAC,OAAO,UAAU,EAAE,UAAU,MAAM,QAAQ,UAAU,MAAM,WAAW,QAAQ;EAC/E,CAAC,KAAK,SAAS,KAAK,MAAM;EAC7B,EAAE,IAAI;;;;AClCX,MAAa,sBAAsB,aAAqB,aAAa;CACjE,MAAM,WAAW,QAAQ,QAAQ,KAAK,EAAE,WAAW;CAEnD,QAAQ,UAAmB;EACvB,MAAM,EAAE,aAAa,IAAI,IAAI,MAAM,IAAI,IAAI;EAE3C,IAAI,CAAC,kBAAkB,KAAK,SAAS,EAAE;EACvC,IAAI,SAAS,WAAW,KAAK,IAAI,SAAS,SAAS,KAAK,EAAE;EAE1D,MAAM,IAAI,QAAQ,IAAI,iBAAiB,sCAAsC;EAC7E,MAAM,IAAI,QAAQ,IAAI,+BAA+B,IAAI;EACzD,MAAM,IAAI,QAAQ,IAAI,gCAAgC,qBAAqB;EAC3E,MAAM,IAAI,QAAQ,IAAI,gCAAgC,8BAA8B;EAEpF,OAAO,YAAY,OAAO;GACtB,YAAY,CAAC,cAAc;GAC3B,cAAc,OAAO;IAIjB,OAAO,SAFM,KAAK,UADG,GAAG,QAAQ,QAAQ,GACA,CAEpB,CAAC,CAAC,YAAY,KAAK;;GAE3C,SAAS,OAAO,OAAO;IAGnB,MAAM,QAAQ,MAAM,KADP,KAAK,UADG,GAAG,QAAQ,QAAQ,GACA,CACX,CAAC,CAAC,YAAY,KAAA,EAAU;IAErD,IAAI,OAAO,QAAQ,EACf,OAAO;KACH,MAAM,MAAM;KACZ,OAAO,MAAM;KAChB;;GAGZ,CAAC"}
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@arkstack/driver-h3",
3
- "version": "0.4.3",
3
+ "version": "0.5.1",
4
4
  "type": "module",
5
- "description": "H3 driver package for Arkstack providing H3-specific implementations of core Arkstack features such as routing, middleware, and database integration.",
5
+ "description": "H3 driver for Arkstack, providing H3-based runtime integration for the framework.",
6
6
  "homepage": "https://arkstack.toneflix.net",
7
7
  "repository": {
8
8
  "type": "git",
@@ -36,15 +36,15 @@
36
36
  "./package.json": "./package.json"
37
37
  },
38
38
  "dependencies": {
39
- "clear-router": "^2.5.4",
40
- "@resora/plugin-clear-router": "^1.0.3",
41
- "resora": "^1.2.0",
42
- "@arkstack/contract": "^0.4.3"
39
+ "clear-router": "^2.6.4",
40
+ "@resora/plugin-clear-router": "^1.0.14",
41
+ "resora": "^1.2.4",
42
+ "@arkstack/contract": "^0.5.1"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "h3": "2.0.1-rc.16",
46
- "@arkstack/auth": "^0.4.3",
47
- "@arkstack/common": "^0.4.3"
46
+ "@arkstack/common": "^0.5.1",
47
+ "@arkstack/auth": "^0.5.1"
48
48
  },
49
49
  "peerDependenciesMeta": {
50
50
  "@arkstack/auth": {
@@ -1,10 +1,9 @@
1
1
  import { BaseController } from '@controllers/BaseController'
2
2
  import BaseController from '@controllers/BaseController'
3
- import { HttpContext } from 'clear-router/types/h3'
4
3
  import {{ResourceName}} from '@app/http/resources/{{ResourceName}}'
5
4
  import {{CollectionResourceName}} from '@app/http/resources/{{CollectionResourceName}}'
6
5
 
7
- import { Resource } from 'resora'
6
+ import { Resource, ResourceCollection } from 'resora'
8
7
 
9
8
  /**
10
9
  * {{ControllerName}}
@@ -12,86 +11,56 @@ import { Resource } from 'resora'
12
11
  export default class {{ControllerName}} extends BaseController {
13
12
  /**
14
13
  * Get all resources
15
- *
16
- * @param req
17
- * @param res
18
14
  */
19
- index = async ({ res }: HttpContext) => {
20
- return await new Resource( { data: [] })
21
- .additional({
15
+ async index () {
16
+ return await new {{CollectionResourceName}}([]).additional({
22
17
  status: 'success',
23
18
  message: 'OK',
24
19
  code: 200,
25
- })
26
- .response(res)
27
- .setStatusCode(200)
20
+ }).response().setStatusCode(200)
28
21
  }
29
22
 
30
23
  /**
31
24
  * Get a specific resource
32
- *
33
- * @param req
34
- * @param res
35
25
  */
36
- show = async ({ res }: HttpContext) => {
37
- return await new Resource({ data: {} })
38
- .additional({
26
+ async show () {
27
+ return new {{ResourceName}}({}).additional({
39
28
  status: 'success',
40
29
  message: 'OK',
41
30
  code: 200,
42
- })
43
- .response(res)
44
- .setStatusCode(200)
31
+ }).response().setStatusCode(200)
45
32
  }
46
33
 
47
34
  /**
48
35
  * Create a resource
49
- *
50
- * @param req
51
- * @param res
52
36
  */
53
- create = async ({ res }: HttpContext) => {
54
- return await new Resource({ data: {} })
55
- .additional({
37
+ async create () {
38
+ return new {{ResourceName}}({}).additional({
56
39
  status: 'success',
57
40
  message: 'New {{Name}} created successfully',
58
41
  code: 201,
59
- })
60
- .response(res)
61
- .setStatusCode(201)
42
+ }).response().setStatusCode(201)
62
43
  }
63
44
 
64
45
  /**
65
46
  * Update a specific resource
66
- *
67
- * @param req
68
- * @param res
69
47
  */
70
- update = async ({ res }: HttpContext) => {
71
- return await new Resource({ data: {} })
72
- .additional({
48
+ async update () {
49
+ return new {{ResourceName}}({}).additional({
73
50
  status: 'success',
74
51
  message: '{{Name}} updated successfully',
75
52
  code: 202,
76
- })
77
- .response(res)
78
- .setStatusCode(202)
53
+ }).response().setStatusCode(202)
79
54
  }
80
55
 
81
56
  /**
82
57
  * Delete a specific resource
83
- *
84
- * @param req
85
- * @param res
86
58
  */
87
- destroy = async ({ res }: HttpContext) => {
88
- return await new Resource({ data: {} })
89
- .additional({
59
+ async destroy () {
60
+ return new {{ResourceName}}({}).additional({
90
61
  status: 'success',
91
62
  message: '{{Name}} deleted successfully',
92
63
  code: 202,
93
- })
94
- .response(res)
95
- .setStatusCode(202)
64
+ }).response().setStatusCode(202)
96
65
  }
97
66
  }
@@ -1,7 +1,5 @@
1
1
  import { BaseController } from '@controllers/BaseController'
2
- import { HttpContext } from 'clear-router/types/h3'
3
-
4
- import { Resource } from 'resora'
2
+ import { Resource, ResourceCollection } from 'resora'
5
3
 
6
4
  /**
7
5
  * {{ControllerName}}
@@ -9,86 +7,56 @@ import { Resource } from 'resora'
9
7
  export default class {{ControllerName}} extends BaseController {
10
8
  /**
11
9
  * Get all resources
12
- *
13
- * @param req
14
- * @param res
15
10
  */
16
- index = async ({ res }: HttpContext) => {
17
- return await new Resource({ data: [] })
18
- .additional({
11
+ async index () {
12
+ return new ResourceCollection({ data: [] }).additional({
19
13
  status: 'success',
20
14
  message: 'OK',
21
15
  code: 200,
22
- })
23
- .response(res)
24
- .setStatusCode(200)
16
+ }).response().setStatusCode(200)
25
17
  }
26
18
 
27
19
  /**
28
20
  * Get a specific resource
29
- *
30
- * @param req
31
- * @param res
32
21
  */
33
- show = async ({ res }: HttpContext) => {
34
- return await new Resource({ data: {} })
35
- .additional({
22
+ async show () {
23
+ return new Resource({ data: {} }).additional({
36
24
  status: 'success',
37
25
  message: 'OK',
38
26
  code: 200,
39
- })
40
- .response(res)
41
- .setStatusCode(200)
27
+ }).response().setStatusCode(200)
42
28
  }
43
29
 
44
30
  /**
45
31
  * Create a resource
46
- *
47
- * @param req
48
- * @param res
49
32
  */
50
- create = async ({ res }: HttpContext) => {
51
- return await new Resource({ data: {} })
52
- .additional({
33
+ async create () {
34
+ return new Resource({ data: {} }).additional({
53
35
  status: 'success',
54
36
  message: 'New {{Name}} created successfully',
55
37
  code: 201,
56
- })
57
- .response(res)
58
- .setStatusCode(201)
38
+ }).response().setStatusCode(201)
59
39
  }
60
40
 
61
41
  /**
62
42
  * Update a specific resource
63
- *
64
- * @param req
65
- * @param res
66
43
  */
67
- update = async ({ res }: HttpContext) => {
68
- return await new Resource({ data: {} })
69
- .additional({
44
+ async update () {
45
+ return new Resource({ data: {} }).additional({
70
46
  status: 'success',
71
47
  message: '{{Name}} updated successfully',
72
48
  code: 202,
73
- })
74
- .response(res)
75
- .setStatusCode(202)
49
+ }).response().setStatusCode(202)
76
50
  }
77
51
 
78
52
  /**
79
53
  * Delete a specific resource
80
- *
81
- * @param req
82
- * @param res
83
54
  */
84
- destroy = async ({ res }: HttpContext) => {
85
- return await new Resource({ data: {} })
86
- .additional({
55
+ async destroy () {
56
+ return new Resource({ data: {}} ).additional({
87
57
  status: 'success',
88
58
  message: '{{Name}} deleted successfully',
89
59
  code: 202,
90
- })
91
- .response(res)
92
- .setStatusCode(202)
60
+ }).response().setStatusCode(202)
93
61
  }
94
62
  }
@@ -1,8 +1,8 @@
1
1
  import { BaseController } from '@controllers/BaseController'
2
- import { HttpContext } from 'clear-router/types/h3'
3
- import { Resource } from 'resora'
4
- import { {{Model}} } from 'src/models/{{Model}}'
5
- import { readBody } from 'h3'
2
+ import { Bind } from 'clear-router/decorators'
3
+ import { Resource, ResourceCollection } from 'resora'
4
+ import { {{Model}} } from '@app/models/{{Model}}'
5
+ import { Request } from '@arkstack/http'
6
6
 
7
7
  /**
8
8
  * {{ControllerName}}
@@ -10,106 +10,78 @@ import { readBody } from 'h3'
10
10
  export default class {{ControllerName}} extends BaseController {
11
11
  /**
12
12
  * Get all resource from the database
13
- *
14
- * @param req
15
- * @param res
16
13
  */
17
- index = async ({ res }: HttpContext) => {
18
- const data = await {{Model}}.query().orderBy({ id: 'asc' }).get()
19
-
20
- return await new Resource({ data })
21
- .additional({
14
+ async index () {
15
+ return new ResourceCollection(await {{Model}}.query().orderBy({ id: 'asc' }).get()).additional({
22
16
  status: 'success',
23
17
  message: 'OK',
24
18
  code: 200,
25
- })
26
- .response(res)
27
- .setStatusCode(200)
19
+ }).response().setStatusCode(200)
28
20
  }
29
21
 
30
22
  /**
31
23
  * Get a specific resource from the database
32
24
  *
33
- * @param req
34
- * @param res
25
+ * @param {{Param}}
35
26
  */
36
- show = async ({ res, context }: HttpContext) => {
37
- const data = await {{Model}}.query().where({ id: String(context.params?.id) }).firstOrFail()
38
-
39
- return await new Resource({ data })
40
- .additional({
27
+ @Bind()
28
+ async show ({{Param}}: {{Model}}) {
29
+ return new Resource({{Param}}).additional({
41
30
  status: 'success',
42
31
  message: 'OK',
43
32
  code: 200,
44
- })
45
- .response(res)
46
- .setStatusCode(200)
33
+ }).response().setStatusCode(200)
47
34
  }
48
35
 
49
36
  /**
50
37
  * Create a new resource in the database
51
38
  *
52
- * The calling route must recieve a multer.RequestHandler instance
53
- *
54
- * @example router.post('/{{ModelName}}s', upload.none(), new AdminController().create)
55
- *
56
39
  * @param req
57
- * @param res
58
40
  */
59
- create = async (evt: HttpContext) => {
41
+ @Bind()
42
+ async create (req: Request) {
60
43
  const data = await {{Model}}.query().create({
61
- data: readBody(evt) as any,
44
+ data: req.body,
62
45
  })
63
46
 
64
- return await new Resource({ data })
65
- .additional({
47
+ return new Resource({ data }).additional({
66
48
  status: 'success',
67
49
  message: 'New {{ModelName}} created successfully',
68
50
  code: 201,
69
- })
70
- .response(evt.res)
71
- .setStatusCode(201)
51
+ }).response().setStatusCode(201)
72
52
  }
73
53
 
74
54
  /**
75
55
  * Update a specific resource in the database
76
56
  *
57
+ * @param {{Param}}
77
58
  * @param req
78
- * @param res
79
59
  */
80
- update = async (evt: HttpContext) => {
81
- const data = await {{Model}}.query()
82
- .where({ id: String(evt.context.params?.id) })
83
- .update({
84
- data: readBody(evt) as any,
85
- })
60
+ @Bind()
61
+ async update (req: Request, {{Param}}: {{Model}}) {
62
+ await {{Param}}.update({
63
+ data: req.body,
64
+ })
86
65
 
87
- return await new Resource({ data })
88
- .additional({
66
+ return new Resource({{Param}}).additional({
89
67
  status: 'success',
90
68
  message: '{{ModelName}} updated successfully',
91
69
  code: 202,
92
- })
93
- .response(evt.res)
94
- .setStatusCode(202)
70
+ }).response().setStatusCode(202)
95
71
  }
96
72
 
97
73
  /**
98
74
  * Delete a specific resource from the database
99
75
  *
100
- * @param req
101
- * @param res
76
+ * @param {{Param}}
102
77
  */
103
- destroy = async ({ res, context }: HttpContext) => {
104
- await {{Model}}.query().where({ id: String(context.params?.id) }).delete()
78
+ async destroy ({{Param}}: {{Model}}) {
79
+ await {{Param}}.delete()
105
80
 
106
- return await new Resource({ data: null })
107
- .additional({
81
+ return new Resource({ data: {} }).additional({
108
82
  status: 'success',
109
83
  message: '{{ModelName}} deleted successfully',
110
84
  code: 202,
111
- })
112
- .response(res)
113
- .setStatusCode(202)
85
+ }).response().setStatusCode(202)
114
86
  }
115
87
  }
@@ -1,11 +1,10 @@
1
1
  import { BaseController } from '@controllers/BaseController'
2
- import { HttpContext } from 'clear-router/types/h3'
3
2
 
4
3
  /**
5
4
  * {{ControllerName}}
6
5
  */
7
6
  export default class {{ControllerName}} extends BaseController {
8
- index = async ({ req, res }: HttpContext) => {
7
+ async index () {
9
8
  return '<p>Hello!</p>'
10
9
  }
11
10
  }
@@ -1,24 +0,0 @@
1
- import { ArkstackRouteListOptions } from "@arkstack/contract";
2
- import { H3, H3Event, HTTPError, HTTPResponse } from "h3";
3
- import { Router } from "clear-router/h3";
4
- import { H3App, Handler, HttpContext, Middleware } from "clear-router/types/h3";
5
- import { Route } from "clear-router";
6
-
7
- //#region src/error-handler.d.ts
8
- declare const defaultErrorHandler: (err: HTTPError | Error | string, event: H3Event) => HTTPResponse | {
9
- error: boolean;
10
- message: string;
11
- status: "error";
12
- code: number;
13
- errors?: unknown;
14
- stack?: string;
15
- };
16
- //#endregion
17
- //#region src/Router.d.ts
18
- declare class Router$1 extends Router {
19
- static bind(app: H3): Promise<H3App>;
20
- static list(_options: ArkstackRouteListOptions | undefined, app: H3): Promise<Route<HttpContext, Middleware, Handler>[]>;
21
- }
22
- //#endregion
23
- export { defaultErrorHandler as n, Router$1 as t };
24
- //# sourceMappingURL=Router-CmVPb5OI.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Router-CmVPb5OI.d.ts","names":[],"sources":["../src/error-handler.ts","../src/Router.ts"],"mappings":";;;;;;;cAMa,mBAAA,GAAuB,GAAA,EAAK,SAAA,GAAY,KAAA,WAAgB,KAAA,EAAO,OAAA,KAAO,YAAA;;;;;;;;;;cCMtE,QAAA,SAAe,MAAA;EAAA,OACb,IAAA,CAAM,GAAA,EAAK,EAAA,GAAK,OAAA,CAAQ,KAAA;EAAA,OAiBxB,IAAA,CACX,QAAA,EAAU,wBAAA,cAA+B,GAAA,EAAK,EAAA,GAC7C,OAAA,CAAQ,KAAA,CAAM,WAAA,EAAa,UAAA,EAAY,OAAA;AAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;KASY,YAAA,GAAe,UAAA,IAAoB,UAAA,EAAkB,MAAA;AAAA,UAEhD,eAAA;EACb,UAAA,GAAa,GAAA,EAAK,EAAA,KAAO,cAAA;EACzB,iBAAA,IAAqB,GAAA,EAAK,EAAA,EAAI,UAAA,aAAuB,cAAA;EACrD,SAAA,SAAkB,EAAA;EAClB,OAAA,IAAW,GAAA,EAAK,KAAA,WAAgB,KAAA,EAAO,OAAA;AAAA;AAAA,cAG9B,eAAA;EAIU,QAAA,EAAU,QAAA;EAH7B,MAAA;EACA,UAAA;cAEmB,QAAA,EAAU,QAAA;EAAA,IAKzB,OAAA,CAAA,GAAY,OAAA;AAAA;AAAA,cAQP,QAAA,SAAiB,iBAAA,CAAkB,EAAA,EAAI,YAAA;EAAA,SACvC,IAAA;EAAA,iBACQ,OAAA;cAOL,OAAA,EAAS,eAAA;EAUrB,SAAA,CAAA,GAAc,EAAA;EAYd,iBAAA,CAAmB,GAAA,EAAK,EAAA,EAAI,UAAA,WAAqB,cAAA;EAajD,UAAA,CAAY,GAAA,EAAK,EAAA,GAAK,cAAA;EAUtB,eAAA,CACI,GAAA,EAAK,EAAA,EACL,UAAA,EAAY,YAAA,GAAe,wBAAA,CAAyB,YAAA;EAqCxD,KAAA,CAAO,GAAA,EAAK,EAAA,EAAI,IAAA;AAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/middlewares/auth.ts","../../src/middlewares/request-logger.ts","../../src/middlewares/static-asset-handler.ts"],"mappings":";;;;;;cAKa,IAAA,GAAc,KAAA,EAAO,OAAA,EAAS,IAAA,kBAAsB,OAAA,cAAgB,OAAA;;;cCcpE,aAAA;EAAiB;AAAA;EAG1B,iBAAA;AAAA,MACK,YAAA;;;cCnBI,kBAAA,GAAsB,UAAA,eAGvB,KAAA,EAAO,OAAA,KAAO,OAAA,CAAA,EAAA,CAAA,YAAA"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/middlewares/auth.ts","../../src/middlewares/request-logger.ts","../../src/middlewares/static-asset-handler.ts"],"sourcesContent":["import { Auth, AuthenticationException } from '@arkstack/auth'\n\nimport type { H3Event } from 'h3'\nimport { Hook } from '@arkstack/common'\n\nexport const auth = async (event: H3Event, next: () => unknown | Promise<unknown>) => {\n try {\n const token = readBearerToken(event.req.headers.get('authorization'))\n\n if (!token) {\n throw new AuthenticationException('Unauthenticated', {\n req: {\n headers: event.req.headers,\n method: event.req.method,\n url: event.req.url,\n path: getEventPath(event),\n },\n status: 401,\n })\n }\n\n if (Hook.has('middleware:auth', 'before'))\n Hook.get('middleware:auth', 'before')?.(event)\n\n const requestSource = {\n headers: event.req.headers,\n method: event.req.method,\n url: event.req.url,\n path: getEventPath(event),\n }\n const auth = Auth.make().setRequest(requestSource)\n const user = await auth.authorizeToken(token)\n\n event.context.user = user\n event.context.auth = auth\n event.context.authUser = user\n event.context.authToken = token;\n (event.req as any).user = user;\n (event.req as any).auth = auth;\n (event.req as any).authUser = user;\n (event.req as any).authToken = token\n\n if (Hook.has('middleware:auth', 'after'))\n Hook.get('middleware:auth', 'after')?.(event)\n\n return await next()\n } catch (error) {\n if (Hook.has('middleware:auth', 'error'))\n Hook.get('middleware:auth', 'error')?.(error, event)\n\n throw error\n }\n}\n\nconst readBearerToken = (authorization: string | null) => {\n if (!authorization?.startsWith('Bearer ')) {\n return null\n }\n\n return authorization.substring(7)\n}\n\nconst getEventPath = (event: H3Event) => event.req._url?.pathname\n","import { Logger, nodeEnv } from '@arkstack/common'\n\nimport { H3Middleware } from '..'\n\nconst colors: Record<string, 'green' | 'blue' | 'yellow' | 'red' | 'cyan'> = {\n GET: 'green',\n POST: 'blue',\n PUT: 'yellow',\n DELETE: 'red',\n PATCH: 'cyan',\n}\n\n/**\n * Middleware to log incoming requests and their response times.\n * \n * @param config Configuration options for the request logger middleware.\n * @param config.allowInProduction If true, the logger will also log requests in production environment. Default is false. \n * @returns H3Middleware function\n */\nexport const requestLogger = ({\n allowInProduction = false,\n}: {\n allowInProduction?: boolean\n} = {}): H3Middleware => async (event, next) => {\n if (nodeEnv() === 'prod' && !allowInProduction) return next()\n\n await next()\n\n const start = Date.now()\n const req = event.req\n const status = event.res.status || 200\n const duration = Date.now() - start\n\n Logger.log([\n [`[${req.method}]`, colors[req.method] || 'green'],\n [req.url, 'cyan'],\n [status.toString(), status >= 500 ? 'red' : status >= 400 ? 'yellow' : 'green'],\n [`- ${duration}ms`, 'dim']\n ], ' ')\n}","import { H3Event, serveStatic } from 'h3'\nimport { readFile, stat } from 'node:fs/promises'\nimport { join, resolve } from 'node:path'\n\nexport const staticAssetHandler = (publicPath: string = 'public') => {\n const rootPath = resolve(process.cwd(), publicPath)\n\n return (event: H3Event) => {\n const { pathname } = new URL(event.req.url)\n\n if (!/\\.[a-zA-Z0-9]+$/.test(pathname)) return\n if (pathname.startsWith('/.') || pathname.includes('..')) return\n\n event.res.headers.set('Cache-Control', 'public, max-age=31536000, immutable')\n event.res.headers.set('Access-Control-Allow-Origin', '*')\n event.res.headers.set('Access-Control-Allow-Methods', 'GET, HEAD, OPTIONS')\n event.res.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization')\n\n return serveStatic(event, {\n indexNames: ['/index.html'],\n getContents: (id) => {\n const relativePath = id.replace(/^\\/+/, '')\n const file = join(rootPath, relativePath)\n\n return readFile(file).catch(() => null) as never\n },\n getMeta: async (id) => {\n const relativePath = id.replace(/^\\/+/, '')\n const file = join(rootPath, relativePath)\n const stats = await stat(file).catch(() => undefined)\n\n if (stats?.isFile()) {\n return {\n size: stats.size,\n mtime: stats.mtimeMs,\n }\n }\n },\n })\n }\n}"],"mappings":"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"}