glasswork 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/authorization/ability-middleware.d.ts +61 -0
  2. package/dist/authorization/ability-middleware.d.ts.map +1 -0
  3. package/dist/authorization/ability-middleware.js +74 -0
  4. package/dist/authorization/ability-middleware.js.map +1 -0
  5. package/dist/authorization/index.d.ts +46 -0
  6. package/dist/authorization/index.d.ts.map +1 -0
  7. package/dist/authorization/index.js +46 -0
  8. package/dist/authorization/index.js.map +1 -0
  9. package/dist/authorization/route-helpers.d.ts +106 -0
  10. package/dist/authorization/route-helpers.d.ts.map +1 -0
  11. package/dist/authorization/route-helpers.js +136 -0
  12. package/dist/authorization/route-helpers.js.map +1 -0
  13. package/dist/authorization/service-proxy.d.ts +59 -0
  14. package/dist/authorization/service-proxy.d.ts.map +1 -0
  15. package/dist/authorization/service-proxy.js +110 -0
  16. package/dist/authorization/service-proxy.js.map +1 -0
  17. package/dist/authorization/types.d.ts +58 -0
  18. package/dist/authorization/types.d.ts.map +1 -0
  19. package/dist/authorization/types.js +7 -0
  20. package/dist/authorization/types.js.map +1 -0
  21. package/dist/hooks/authorization-hook.d.ts +100 -0
  22. package/dist/hooks/authorization-hook.d.ts.map +1 -0
  23. package/dist/hooks/authorization-hook.js +93 -0
  24. package/dist/hooks/authorization-hook.js.map +1 -0
  25. package/dist/hooks/index.d.ts +54 -0
  26. package/dist/hooks/index.d.ts.map +1 -0
  27. package/dist/hooks/index.js +55 -0
  28. package/dist/hooks/index.js.map +1 -0
  29. package/dist/hooks/service-hooks.d.ts +82 -0
  30. package/dist/hooks/service-hooks.d.ts.map +1 -0
  31. package/dist/hooks/service-hooks.js +158 -0
  32. package/dist/hooks/service-hooks.js.map +1 -0
  33. package/dist/hooks/types.d.ts +151 -0
  34. package/dist/hooks/types.d.ts.map +1 -0
  35. package/dist/hooks/types.js +2 -0
  36. package/dist/hooks/types.js.map +1 -0
  37. package/dist/http/route-helpers.d.ts +45 -7
  38. package/dist/http/route-helpers.d.ts.map +1 -1
  39. package/dist/http/route-helpers.js +80 -2
  40. package/dist/http/route-helpers.js.map +1 -1
  41. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-proxy.js","sourceRoot":"","sources":["../../src/authorization/service-proxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAGxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,MAAM,UAAU,iBAAiB,CAC/B,OAAU,EACV,OAAiC;IAEjC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC;IAEtD,OAAO,IAAI,KAAK,CAAC,OAAO,EAAE;QACxB,GAAG,CAAC,MAAM,EAAE,IAAqB;YAC/B,gCAAgC;YAChC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC7B,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YACnC,CAAC;YAED,MAAM,cAAc,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAEjD,uCAAuC;YACvC,IAAI,OAAO,cAAc,KAAK,UAAU,EAAE,CAAC;gBACzC,OAAO,cAAc,CAAC;YACxB,CAAC;YAED,kDAAkD;YAClD,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;YAEhC,4DAA4D;YAC5D,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,OAAO,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACrC,CAAC;YAED,2CAA2C;YAC3C,OAAO,UAAyB,GAAG,IAAe;gBAChD,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,QAAQ,CAAC;gBAE9D,yCAAyC;gBACzC,MAAM,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;gBAEjE,iCAAiC;gBACjC,IAAI,CAAC;oBACH,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,cAAc,CACzC,MAAM,EACN,OAAO,CAAC,WAAW,EAAE,WAAW,IAAI,EAAE,CAAC,CACxC,CAAC;gBACJ,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,IAAI,cAAc,EAAE,CAAC;wBACnB,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;wBAC3B,MAAM,KAAK,CAAC,CAAC,mCAAmC;oBAClD,CAAC;oBACD,MAAM,KAAK,CAAC;gBACd,CAAC;gBAED,iDAAiD;gBACjD,OAAO,cAAc,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YAC5C,CAAC,CAAC;QACJ,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAA6B;IAC7D,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB,CAClC,OAAU,EACV,WAAgD;IAEhD,OAAO,CAAmB,WAAmB,EAAE,OAAU,EAAK,EAAE;QAC9D,MAAM,QAAQ,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;QAE1C,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,wCAAwC;YACxC,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,OAAO,iBAAiB,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC3D,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Authorization types for CASL integration.
3
+ *
4
+ * This file contains core types for ability configuration and middleware.
5
+ */
6
+ import type { PureAbility } from '@casl/ability';
7
+ import type { Context } from 'hono';
8
+ /**
9
+ * Base CASL ability type that applications can extend.
10
+ * This type is re-exported from @casl/ability to maintain transparency.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { createPrismaAbility } from '@casl/prisma';
15
+ * import { AbilityBuilder } from '@casl/ability';
16
+ *
17
+ * type AppAbility = PureAbility<[Action, Subject]>;
18
+ *
19
+ * function defineAbility() {
20
+ * const { can, build } = new AbilityBuilder<AppAbility>(createPrismaAbility);
21
+ * can('read', 'User');
22
+ * return build();
23
+ * }
24
+ * ```
25
+ */
26
+ export type BaseAbility = PureAbility<[string, string | object]>;
27
+ /**
28
+ * Factory function that creates an ability based on user context.
29
+ * This function receives the full Hono context, allowing access to
30
+ * user data, request information, etc.
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * const abilityFactory: AbilityFactory<AppAbility> = (c) => {
35
+ * const user = c.get('user');
36
+ * if (user.role === 'admin') {
37
+ * return new AdminAbility();
38
+ * }
39
+ * return new UserAbility(user);
40
+ * };
41
+ * ```
42
+ */
43
+ export type AbilityFactory<T extends BaseAbility = BaseAbility> = (context: Context) => T | Promise<T>;
44
+ /**
45
+ * Configuration for ability-based authorization in routes.
46
+ */
47
+ export interface AbilityConfig<T extends BaseAbility = BaseAbility> {
48
+ /**
49
+ * Factory function to create the ability from request context.
50
+ */
51
+ factory: AbilityFactory<T>;
52
+ /**
53
+ * Optional key to store the ability in context variables.
54
+ * @default 'ability'
55
+ */
56
+ contextKey?: string;
57
+ }
58
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/authorization/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEpC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;AAEjE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW,IAAI,CAChE,OAAO,EAAE,OAAO,KACb,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;AAEpB;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,WAAW,GAAG,WAAW;IAChE;;OAEG;IACH,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IAE3B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Authorization types for CASL integration.
3
+ *
4
+ * This file contains core types for ability configuration and middleware.
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/authorization/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,100 @@
1
+ import type { ServiceHook } from './types.js';
2
+ /**
3
+ * Authorization metadata for a service method.
4
+ * Defines what CASL action/subject to check before the method executes.
5
+ */
6
+ export interface AuthorizationMetadata {
7
+ /**
8
+ * CASL action (e.g., 'create', 'read', 'update', 'delete')
9
+ */
10
+ action: string;
11
+ /**
12
+ * CASL subject type (e.g., 'User', 'Post', 'Session')
13
+ */
14
+ subject: string;
15
+ /**
16
+ * Optional function to extract subject data from method arguments.
17
+ * Used for field-level and instance-level authorization.
18
+ *
19
+ * @param args - The arguments passed to the service method
20
+ * @returns The subject data to check against CASL rules
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * getSubjectData: (userId, updates) => ({ id: userId, ...updates })
25
+ * ```
26
+ */
27
+ getSubjectData?: (...args: unknown[]) => object | undefined;
28
+ }
29
+ /**
30
+ * Service hook that performs CASL authorization before method execution.
31
+ *
32
+ * This hook checks for `authorize` metadata on service methods and calls
33
+ * the CASL `authorize()` function before allowing the method to execute.
34
+ *
35
+ * **Usage:**
36
+ * 1. Define authorization metadata for your service methods
37
+ * 2. Include this hook when wrapping services
38
+ * 3. Ensure ability middleware is configured in your routes
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * import { authorizationHook, defineServiceMetadata } from 'glasswork';
43
+ *
44
+ * // Define metadata
45
+ * export const authServiceMetadata = defineServiceMetadata({
46
+ * deleteSession: {
47
+ * authorize: {
48
+ * action: 'delete',
49
+ * subject: 'Session'
50
+ * }
51
+ * },
52
+ * updateUser: {
53
+ * authorize: {
54
+ * action: 'update',
55
+ * subject: 'User',
56
+ * getSubjectData: (userId, data) => ({ id: userId, ...data })
57
+ * }
58
+ * }
59
+ * });
60
+ *
61
+ * // Use in routes
62
+ * router.delete('/session', async (c) => {
63
+ * const services = withServiceHooks(
64
+ * { authService },
65
+ * {
66
+ * hooks: [authorizationHook],
67
+ * metadata: authServiceMetadata
68
+ * },
69
+ * c
70
+ * );
71
+ *
72
+ * // This automatically checks authorization before executing
73
+ * await services.authService.deleteSession(token);
74
+ * });
75
+ * ```
76
+ */
77
+ export declare const authorizationHook: ServiceHook;
78
+ /**
79
+ * Helper to define authorization metadata for service methods.
80
+ * Provides better type inference for the authorize property.
81
+ *
82
+ * @param action - CASL action
83
+ * @param subject - CASL subject type
84
+ * @param getSubjectData - Optional function to extract subject data
85
+ * @returns Authorization metadata object
86
+ *
87
+ * @example
88
+ * ```typescript
89
+ * export const userServiceMetadata = defineServiceMetadata({
90
+ * update: {
91
+ * authorize: defineAuthorize('update', 'User', (id, data) => ({ id, ...data }))
92
+ * },
93
+ * delete: {
94
+ * authorize: defineAuthorize('delete', 'User', (id) => ({ id }))
95
+ * }
96
+ * });
97
+ * ```
98
+ */
99
+ export declare function defineAuthorize(action: string, subject: string, getSubjectData?: (...args: unknown[]) => object | undefined): AuthorizationMetadata;
100
+ //# sourceMappingURL=authorization-hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorization-hook.d.ts","sourceRoot":"","sources":["../../src/hooks/authorization-hook.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,MAAM,GAAG,SAAS,CAAC;CAC7D;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,eAAO,MAAM,iBAAiB,EAAE,WAkB/B,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,cAAc,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,MAAM,GAAG,SAAS,GAC1D,qBAAqB,CAMvB"}
@@ -0,0 +1,93 @@
1
+ import { authorize } from '../authorization/route-helpers.js';
2
+ /**
3
+ * Service hook that performs CASL authorization before method execution.
4
+ *
5
+ * This hook checks for `authorize` metadata on service methods and calls
6
+ * the CASL `authorize()` function before allowing the method to execute.
7
+ *
8
+ * **Usage:**
9
+ * 1. Define authorization metadata for your service methods
10
+ * 2. Include this hook when wrapping services
11
+ * 3. Ensure ability middleware is configured in your routes
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import { authorizationHook, defineServiceMetadata } from 'glasswork';
16
+ *
17
+ * // Define metadata
18
+ * export const authServiceMetadata = defineServiceMetadata({
19
+ * deleteSession: {
20
+ * authorize: {
21
+ * action: 'delete',
22
+ * subject: 'Session'
23
+ * }
24
+ * },
25
+ * updateUser: {
26
+ * authorize: {
27
+ * action: 'update',
28
+ * subject: 'User',
29
+ * getSubjectData: (userId, data) => ({ id: userId, ...data })
30
+ * }
31
+ * }
32
+ * });
33
+ *
34
+ * // Use in routes
35
+ * router.delete('/session', async (c) => {
36
+ * const services = withServiceHooks(
37
+ * { authService },
38
+ * {
39
+ * hooks: [authorizationHook],
40
+ * metadata: authServiceMetadata
41
+ * },
42
+ * c
43
+ * );
44
+ *
45
+ * // This automatically checks authorization before executing
46
+ * await services.authService.deleteSession(token);
47
+ * });
48
+ * ```
49
+ */
50
+ export const authorizationHook = {
51
+ before: async (context, args) => {
52
+ // Check if this method has authorization metadata
53
+ const metadata = context.metadata;
54
+ if (!metadata?.authorize) {
55
+ // No authorization required for this method
56
+ return;
57
+ }
58
+ const { action, subject, getSubjectData } = metadata.authorize;
59
+ // Extract subject data if function provided
60
+ const subjectData = getSubjectData ? getSubjectData(...args) : undefined;
61
+ // Call CASL authorize - this will throw ForbiddenError if not allowed
62
+ authorize(context.honoContext, action, subject, subjectData);
63
+ },
64
+ };
65
+ /**
66
+ * Helper to define authorization metadata for service methods.
67
+ * Provides better type inference for the authorize property.
68
+ *
69
+ * @param action - CASL action
70
+ * @param subject - CASL subject type
71
+ * @param getSubjectData - Optional function to extract subject data
72
+ * @returns Authorization metadata object
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * export const userServiceMetadata = defineServiceMetadata({
77
+ * update: {
78
+ * authorize: defineAuthorize('update', 'User', (id, data) => ({ id, ...data }))
79
+ * },
80
+ * delete: {
81
+ * authorize: defineAuthorize('delete', 'User', (id) => ({ id }))
82
+ * }
83
+ * });
84
+ * ```
85
+ */
86
+ export function defineAuthorize(action, subject, getSubjectData) {
87
+ return {
88
+ action,
89
+ subject,
90
+ getSubjectData,
91
+ };
92
+ }
93
+ //# sourceMappingURL=authorization-hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authorization-hook.js","sourceRoot":"","sources":["../../src/hooks/authorization-hook.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,mCAAmC,CAAC;AAiC9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAgB;IAC5C,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE;QAC9B,kDAAkD;QAClD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAiD,CAAC;QAE3E,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,CAAC;YACzB,4CAA4C;YAC5C,OAAO;QACT,CAAC;QAED,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,GAAG,QAAQ,CAAC,SAAS,CAAC;QAE/D,4CAA4C;QAC5C,MAAM,WAAW,GAAG,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAEzE,sEAAsE;QACtE,SAAS,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC;IAC/D,CAAC;CACF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAc,EACd,OAAe,EACf,cAA2D;IAE3D,OAAO;QACL,MAAM;QACN,OAAO;QACP,cAAc;KACf,CAAC;AACJ,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Service hooks system for wrapping service method calls with before/after/error hooks.
3
+ *
4
+ * This module provides a flexible hook system that can be used for:
5
+ * - Authorization (using CASL)
6
+ * - Audit logging
7
+ * - Metrics and tracing
8
+ * - Error handling
9
+ * - Retry logic
10
+ * - Timeouts
11
+ * - Response transformation
12
+ *
13
+ * Hooks are transparent - they wrap service methods without modifying the service
14
+ * implementation, keeping business logic clean and framework-agnostic.
15
+ *
16
+ * @module hooks
17
+ *
18
+ * @example Basic Usage
19
+ * ```typescript
20
+ * import { authorizationHook, defineServiceMetadata } from 'glasswork';
21
+ *
22
+ * // Define metadata for service methods
23
+ * export const authServiceMetadata = defineServiceMetadata({
24
+ * deleteSession: {
25
+ * authorize: {
26
+ * action: 'delete',
27
+ * subject: 'Session'
28
+ * }
29
+ * }
30
+ * });
31
+ *
32
+ * // Configure hooks globally in bootstrap
33
+ * bootstrap({
34
+ * serviceHooks: [authorizationHook],
35
+ * serviceMetadata: {
36
+ * authService: authServiceMetadata
37
+ * }
38
+ * });
39
+ *
40
+ * // In routes, service calls are automatically wrapped
41
+ * export const authRoutes = createRoutes((router, { authService }) => {
42
+ * router.delete('/session', ...route({
43
+ * handler: async ({ context }) => {
44
+ * // This automatically checks authorization before executing!
45
+ * await authService.deleteSession(token);
46
+ * }
47
+ * }));
48
+ * });
49
+ * ```
50
+ */
51
+ export { type AuthorizationMetadata, authorizationHook, defineAuthorize, } from './authorization-hook.js';
52
+ export { defineServiceMetadata, withServiceHooks, withServiceHooksMany, } from './service-hooks.js';
53
+ export type { ServiceAfterHook, ServiceBeforeHook, ServiceErrorHook, ServiceHook, ServiceHookContext, ServiceHooksConfig, ServiceMethodMetadata, ServicesRegistry, } from './types.js';
54
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAGH,OAAO,EACL,KAAK,qBAAqB,EAC1B,iBAAiB,EACjB,eAAe,GAChB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC;AAE5B,YAAY,EACV,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,GACjB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Service hooks system for wrapping service method calls with before/after/error hooks.
3
+ *
4
+ * This module provides a flexible hook system that can be used for:
5
+ * - Authorization (using CASL)
6
+ * - Audit logging
7
+ * - Metrics and tracing
8
+ * - Error handling
9
+ * - Retry logic
10
+ * - Timeouts
11
+ * - Response transformation
12
+ *
13
+ * Hooks are transparent - they wrap service methods without modifying the service
14
+ * implementation, keeping business logic clean and framework-agnostic.
15
+ *
16
+ * @module hooks
17
+ *
18
+ * @example Basic Usage
19
+ * ```typescript
20
+ * import { authorizationHook, defineServiceMetadata } from 'glasswork';
21
+ *
22
+ * // Define metadata for service methods
23
+ * export const authServiceMetadata = defineServiceMetadata({
24
+ * deleteSession: {
25
+ * authorize: {
26
+ * action: 'delete',
27
+ * subject: 'Session'
28
+ * }
29
+ * }
30
+ * });
31
+ *
32
+ * // Configure hooks globally in bootstrap
33
+ * bootstrap({
34
+ * serviceHooks: [authorizationHook],
35
+ * serviceMetadata: {
36
+ * authService: authServiceMetadata
37
+ * }
38
+ * });
39
+ *
40
+ * // In routes, service calls are automatically wrapped
41
+ * export const authRoutes = createRoutes((router, { authService }) => {
42
+ * router.delete('/session', ...route({
43
+ * handler: async ({ context }) => {
44
+ * // This automatically checks authorization before executing!
45
+ * await authService.deleteSession(token);
46
+ * }
47
+ * }));
48
+ * });
49
+ * ```
50
+ */
51
+ // Built-in hooks
52
+ export { authorizationHook, defineAuthorize, } from './authorization-hook.js';
53
+ // Hook system
54
+ export { defineServiceMetadata, withServiceHooks, withServiceHooksMany, } from './service-hooks.js';
55
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AAEH,iBAAiB;AACjB,OAAO,EAEL,iBAAiB,EACjB,eAAe,GAChB,MAAM,yBAAyB,CAAC;AAEjC,cAAc;AACd,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,oBAAoB,GACrB,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,82 @@
1
+ import type { Context } from 'hono';
2
+ import type { ServiceHooksConfig, ServiceMethodMetadata } from './types.js';
3
+ /**
4
+ * Wraps a service with hooks that run before/after/on-error for method calls.
5
+ * This creates a transparent proxy that intercepts method calls and runs hooks
6
+ * while preserving all service functionality.
7
+ *
8
+ * **Note:** Hooks only run for method calls, not property access.
9
+ *
10
+ * @param service - The service instance to wrap
11
+ * @param config - Hook configuration
12
+ * @param honoContext - The current Hono request context
13
+ * @returns Proxied service with hooks
14
+ *
15
+ * @example
16
+ * ```typescript
17
+ * const authHook: ServiceHook = {
18
+ * before: async (context) => {
19
+ * if (context.metadata?.authorize) {
20
+ * authorize(context.honoContext, ...);
21
+ * }
22
+ * }
23
+ * };
24
+ *
25
+ * const wrappedService = withServiceHooks(authService, {
26
+ * hooks: [authHook],
27
+ * metadata: {
28
+ * deleteSession: {
29
+ * authorize: { action: 'delete', subject: 'Session' }
30
+ * }
31
+ * }
32
+ * }, honoContext);
33
+ *
34
+ * // Hooks automatically run when calling methods
35
+ * await wrappedService.deleteSession(token);
36
+ * ```
37
+ */
38
+ export declare function withServiceHooks<T extends object>(service: T, config: ServiceHooksConfig, honoContext: Context): T;
39
+ /**
40
+ * Wraps multiple services with the same hooks configuration.
41
+ * Useful when you want to apply the same hooks to all services in a container.
42
+ *
43
+ * @param services - Object containing service instances
44
+ * @param config - Hook configuration (can be a function for per-service config)
45
+ * @param honoContext - The current Hono request context
46
+ * @returns Object with all services wrapped with hooks
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * const wrappedServices = withServiceHooksMany(
51
+ * { authService, userService },
52
+ * (serviceName) => ({
53
+ * hooks: [authHook, auditHook],
54
+ * metadata: serviceMetadataRegistry[serviceName],
55
+ * serviceName,
56
+ * }),
57
+ * honoContext
58
+ * );
59
+ * ```
60
+ */
61
+ export declare function withServiceHooksMany<T extends Record<string, object>>(services: T, config: ServiceHooksConfig | ((serviceName: string, service: unknown) => ServiceHooksConfig), honoContext: Context): T;
62
+ /**
63
+ * Helper to define service method metadata with better type inference.
64
+ * This is just an identity function that helps TypeScript understand the structure.
65
+ *
66
+ * @param metadata - Service method metadata mapping
67
+ * @returns The same metadata (identity function)
68
+ *
69
+ * @example
70
+ * ```typescript
71
+ * export const authServiceMetadata = defineServiceMetadata({
72
+ * deleteSession: {
73
+ * authorize: { action: 'delete', subject: 'Session' }
74
+ * },
75
+ * findById: {
76
+ * authorize: { action: 'read', subject: 'User' }
77
+ * }
78
+ * });
79
+ * ```
80
+ */
81
+ export declare function defineServiceMetadata(metadata: Record<string, ServiceMethodMetadata>): Record<string, ServiceMethodMetadata>;
82
+ //# sourceMappingURL=service-hooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-hooks.d.ts","sourceRoot":"","sources":["../../src/hooks/service-hooks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAGV,kBAAkB,EAClB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAkDpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,EAC/C,OAAO,EAAE,CAAC,EACV,MAAM,EAAE,kBAAkB,EAC1B,WAAW,EAAE,OAAO,GACnB,CAAC,CAqCH;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EACnE,QAAQ,EAAE,CAAC,EACX,MAAM,EAAE,kBAAkB,GAAG,CAAC,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,kBAAkB,CAAC,EAC5F,WAAW,EAAE,OAAO,GACnB,CAAC,CAcH;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,GAC9C,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAEvC"}
@@ -0,0 +1,158 @@
1
+ /**
2
+ * Execute a method with hooks (before/after/error).
3
+ * Extracted as a helper to reduce complexity.
4
+ */
5
+ async function executeWithHooks(hookContext, hooks,
6
+ // biome-ignore lint/suspicious/noExplicitAny: Function type requires any
7
+ originalMethod, target, args) {
8
+ try {
9
+ // Run all before hooks
10
+ for (const hook of hooks) {
11
+ if (hook.before) {
12
+ await hook.before(hookContext, args);
13
+ }
14
+ }
15
+ // Execute original method
16
+ let result = await originalMethod.apply(target, args);
17
+ // Run all after hooks (in order)
18
+ for (const hook of hooks) {
19
+ if (hook.after) {
20
+ const hookResult = await hook.after(hookContext, args, result);
21
+ // If hook returns a value, use it as the new result
22
+ if (hookResult !== undefined) {
23
+ result = hookResult;
24
+ }
25
+ }
26
+ }
27
+ return result;
28
+ }
29
+ catch (error) {
30
+ // Run all error hooks
31
+ for (const hook of hooks) {
32
+ if (hook.onError) {
33
+ await hook.onError(hookContext, args, error);
34
+ }
35
+ }
36
+ // Re-throw the error after hooks
37
+ throw error;
38
+ }
39
+ }
40
+ /**
41
+ * Wraps a service with hooks that run before/after/on-error for method calls.
42
+ * This creates a transparent proxy that intercepts method calls and runs hooks
43
+ * while preserving all service functionality.
44
+ *
45
+ * **Note:** Hooks only run for method calls, not property access.
46
+ *
47
+ * @param service - The service instance to wrap
48
+ * @param config - Hook configuration
49
+ * @param honoContext - The current Hono request context
50
+ * @returns Proxied service with hooks
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * const authHook: ServiceHook = {
55
+ * before: async (context) => {
56
+ * if (context.metadata?.authorize) {
57
+ * authorize(context.honoContext, ...);
58
+ * }
59
+ * }
60
+ * };
61
+ *
62
+ * const wrappedService = withServiceHooks(authService, {
63
+ * hooks: [authHook],
64
+ * metadata: {
65
+ * deleteSession: {
66
+ * authorize: { action: 'delete', subject: 'Session' }
67
+ * }
68
+ * }
69
+ * }, honoContext);
70
+ *
71
+ * // Hooks automatically run when calling methods
72
+ * await wrappedService.deleteSession(token);
73
+ * ```
74
+ */
75
+ export function withServiceHooks(service, config, honoContext) {
76
+ const { hooks, metadata = {}, serviceName } = config;
77
+ // Try to determine service name
78
+ const inferredServiceName = serviceName || service.constructor?.name || 'UnknownService';
79
+ return new Proxy(service, {
80
+ get(target, prop) {
81
+ // Only intercept string properties (method names)
82
+ if (typeof prop !== 'string') {
83
+ return Reflect.get(target, prop);
84
+ }
85
+ const originalValue = Reflect.get(target, prop);
86
+ // If it's not a function, return as-is
87
+ if (typeof originalValue !== 'function') {
88
+ return originalValue;
89
+ }
90
+ // Get metadata for this method
91
+ const methodMetadata = metadata[prop];
92
+ // Return wrapped function with hooks
93
+ return async function (...args) {
94
+ const hookContext = {
95
+ honoContext,
96
+ serviceName: inferredServiceName,
97
+ methodName: prop,
98
+ metadata: methodMetadata,
99
+ };
100
+ // biome-ignore lint/suspicious/noExplicitAny: originalValue is guaranteed to be a function by the check above
101
+ return executeWithHooks(hookContext, hooks, originalValue, target, args);
102
+ };
103
+ },
104
+ });
105
+ }
106
+ /**
107
+ * Wraps multiple services with the same hooks configuration.
108
+ * Useful when you want to apply the same hooks to all services in a container.
109
+ *
110
+ * @param services - Object containing service instances
111
+ * @param config - Hook configuration (can be a function for per-service config)
112
+ * @param honoContext - The current Hono request context
113
+ * @returns Object with all services wrapped with hooks
114
+ *
115
+ * @example
116
+ * ```typescript
117
+ * const wrappedServices = withServiceHooksMany(
118
+ * { authService, userService },
119
+ * (serviceName) => ({
120
+ * hooks: [authHook, auditHook],
121
+ * metadata: serviceMetadataRegistry[serviceName],
122
+ * serviceName,
123
+ * }),
124
+ * honoContext
125
+ * );
126
+ * ```
127
+ */
128
+ export function withServiceHooksMany(services, config, honoContext) {
129
+ const result = {};
130
+ for (const [serviceName, service] of Object.entries(services)) {
131
+ const serviceConfig = typeof config === 'function' ? config(serviceName, service) : config;
132
+ result[serviceName] = withServiceHooks(service, { ...serviceConfig, serviceName }, honoContext);
133
+ }
134
+ return result;
135
+ }
136
+ /**
137
+ * Helper to define service method metadata with better type inference.
138
+ * This is just an identity function that helps TypeScript understand the structure.
139
+ *
140
+ * @param metadata - Service method metadata mapping
141
+ * @returns The same metadata (identity function)
142
+ *
143
+ * @example
144
+ * ```typescript
145
+ * export const authServiceMetadata = defineServiceMetadata({
146
+ * deleteSession: {
147
+ * authorize: { action: 'delete', subject: 'Session' }
148
+ * },
149
+ * findById: {
150
+ * authorize: { action: 'read', subject: 'User' }
151
+ * }
152
+ * });
153
+ * ```
154
+ */
155
+ export function defineServiceMetadata(metadata) {
156
+ return metadata;
157
+ }
158
+ //# sourceMappingURL=service-hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-hooks.js","sourceRoot":"","sources":["../../src/hooks/service-hooks.ts"],"names":[],"mappings":"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"}