hazo_auth 10.2.2 → 10.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/cli-src/lib/auth/deny_permission.server.ts +101 -0
  2. package/cli-src/lib/auth/index.ts +8 -0
  3. package/cli-src/lib/auth/with_permission_issue_capture.server.ts +222 -0
  4. package/cli-src/lib/services/find_roles_with_permission.ts +47 -0
  5. package/dist/admin-issues/permission_denied_provider.client.d.ts +14 -0
  6. package/dist/admin-issues/permission_denied_provider.client.d.ts.map +1 -0
  7. package/dist/admin-issues/permission_denied_provider.client.js +80 -0
  8. package/dist/admin-issues/plugin.client.d.ts +34 -0
  9. package/dist/admin-issues/plugin.client.d.ts.map +1 -0
  10. package/dist/admin-issues/plugin.client.js +64 -0
  11. package/dist/admin-issues/plugin.server.d.ts +59 -0
  12. package/dist/admin-issues/plugin.server.d.ts.map +1 -0
  13. package/dist/admin-issues/plugin.server.js +168 -0
  14. package/dist/admin-issues/wire.server.d.ts +23 -0
  15. package/dist/admin-issues/wire.server.d.ts.map +1 -0
  16. package/dist/admin-issues/wire.server.js +30 -0
  17. package/dist/client.d.ts +5 -0
  18. package/dist/client.d.ts.map +1 -1
  19. package/dist/client.js +6 -0
  20. package/dist/components/layouts/create_firm/index.d.ts +2 -1
  21. package/dist/components/layouts/create_firm/index.d.ts.map +1 -1
  22. package/dist/components/layouts/dev_lock/index.d.ts +1 -1
  23. package/dist/components/layouts/dev_lock/index.d.ts.map +1 -1
  24. package/dist/components/layouts/email_verification/index.d.ts +1 -1
  25. package/dist/components/layouts/email_verification/index.d.ts.map +1 -1
  26. package/dist/components/layouts/forgot_password/index.d.ts +1 -1
  27. package/dist/components/layouts/forgot_password/index.d.ts.map +1 -1
  28. package/dist/components/layouts/google_token_test/index.d.ts +1 -1
  29. package/dist/components/layouts/google_token_test/index.d.ts.map +1 -1
  30. package/dist/components/layouts/legal/legal_acceptance_gate.d.ts +1 -1
  31. package/dist/components/layouts/legal/legal_acceptance_gate.d.ts.map +1 -1
  32. package/dist/components/layouts/legal/legal_doc_checkbox_list.d.ts +1 -1
  33. package/dist/components/layouts/legal/legal_doc_checkbox_list.d.ts.map +1 -1
  34. package/dist/components/layouts/legal/legal_doc_combined_view.d.ts +1 -1
  35. package/dist/components/layouts/legal/legal_doc_combined_view.d.ts.map +1 -1
  36. package/dist/components/layouts/legal/legal_doc_drawer.d.ts +1 -1
  37. package/dist/components/layouts/legal/legal_doc_drawer.d.ts.map +1 -1
  38. package/dist/components/layouts/login/index.d.ts +1 -1
  39. package/dist/components/layouts/login/index.d.ts.map +1 -1
  40. package/dist/components/layouts/my_settings/components/connected_accounts_section.d.ts +1 -1
  41. package/dist/components/layouts/my_settings/components/connected_accounts_section.d.ts.map +1 -1
  42. package/dist/components/layouts/my_settings/components/editable_field.d.ts +1 -1
  43. package/dist/components/layouts/my_settings/components/editable_field.d.ts.map +1 -1
  44. package/dist/components/layouts/my_settings/components/password_change_dialog.d.ts +1 -1
  45. package/dist/components/layouts/my_settings/components/password_change_dialog.d.ts.map +1 -1
  46. package/dist/components/layouts/my_settings/components/profile_picture_dialog.d.ts +1 -1
  47. package/dist/components/layouts/my_settings/components/profile_picture_dialog.d.ts.map +1 -1
  48. package/dist/components/layouts/my_settings/components/profile_picture_display.d.ts +1 -1
  49. package/dist/components/layouts/my_settings/components/profile_picture_display.d.ts.map +1 -1
  50. package/dist/components/layouts/my_settings/components/profile_picture_gravatar_tab.d.ts +1 -1
  51. package/dist/components/layouts/my_settings/components/profile_picture_gravatar_tab.d.ts.map +1 -1
  52. package/dist/components/layouts/my_settings/components/profile_picture_library_tab.d.ts +1 -1
  53. package/dist/components/layouts/my_settings/components/profile_picture_library_tab.d.ts.map +1 -1
  54. package/dist/components/layouts/my_settings/components/profile_picture_upload_tab.d.ts +7 -1
  55. package/dist/components/layouts/my_settings/components/profile_picture_upload_tab.d.ts.map +1 -1
  56. package/dist/components/layouts/my_settings/components/profile_picture_upload_tab.js +46 -15
  57. package/dist/components/layouts/my_settings/components/set_password_section.d.ts +1 -1
  58. package/dist/components/layouts/my_settings/components/set_password_section.d.ts.map +1 -1
  59. package/dist/components/layouts/my_settings/index.d.ts +1 -1
  60. package/dist/components/layouts/my_settings/index.d.ts.map +1 -1
  61. package/dist/components/layouts/register/index.d.ts +1 -1
  62. package/dist/components/layouts/register/index.d.ts.map +1 -1
  63. package/dist/components/layouts/reset_password/index.d.ts +1 -1
  64. package/dist/components/layouts/reset_password/index.d.ts.map +1 -1
  65. package/dist/components/layouts/scope_management/components/branding_editor.d.ts +1 -1
  66. package/dist/components/layouts/scope_management/components/branding_editor.d.ts.map +1 -1
  67. package/dist/components/layouts/shared/components/already_logged_in_guard.d.ts +1 -1
  68. package/dist/components/layouts/shared/components/already_logged_in_guard.d.ts.map +1 -1
  69. package/dist/components/layouts/shared/components/auth_navbar.d.ts +1 -1
  70. package/dist/components/layouts/shared/components/auth_navbar.d.ts.map +1 -1
  71. package/dist/components/layouts/shared/components/auth_page_shell.d.ts +1 -1
  72. package/dist/components/layouts/shared/components/auth_page_shell.d.ts.map +1 -1
  73. package/dist/components/layouts/shared/components/facebook_sign_in_button.d.ts +1 -1
  74. package/dist/components/layouts/shared/components/facebook_sign_in_button.d.ts.map +1 -1
  75. package/dist/components/layouts/shared/components/field_error_message.d.ts +1 -1
  76. package/dist/components/layouts/shared/components/field_error_message.d.ts.map +1 -1
  77. package/dist/components/layouts/shared/components/floating_home_link.d.ts +1 -1
  78. package/dist/components/layouts/shared/components/floating_home_link.d.ts.map +1 -1
  79. package/dist/components/layouts/shared/components/form_action_buttons.d.ts +1 -1
  80. package/dist/components/layouts/shared/components/form_action_buttons.d.ts.map +1 -1
  81. package/dist/components/layouts/shared/components/form_field_wrapper.d.ts +1 -1
  82. package/dist/components/layouts/shared/components/form_field_wrapper.d.ts.map +1 -1
  83. package/dist/components/layouts/shared/components/form_header.d.ts +1 -1
  84. package/dist/components/layouts/shared/components/form_header.d.ts.map +1 -1
  85. package/dist/components/layouts/shared/components/google_icon.d.ts +1 -1
  86. package/dist/components/layouts/shared/components/google_icon.d.ts.map +1 -1
  87. package/dist/components/layouts/shared/components/google_sign_in_button.d.ts +1 -1
  88. package/dist/components/layouts/shared/components/google_sign_in_button.d.ts.map +1 -1
  89. package/dist/components/layouts/shared/components/logout_button.d.ts +1 -1
  90. package/dist/components/layouts/shared/components/logout_button.d.ts.map +1 -1
  91. package/dist/components/layouts/shared/components/oauth_divider.d.ts +1 -1
  92. package/dist/components/layouts/shared/components/oauth_divider.d.ts.map +1 -1
  93. package/dist/components/layouts/shared/components/password_field.d.ts +1 -1
  94. package/dist/components/layouts/shared/components/password_field.d.ts.map +1 -1
  95. package/dist/components/layouts/shared/components/profile_pic_menu.d.ts +1 -1
  96. package/dist/components/layouts/shared/components/profile_pic_menu.d.ts.map +1 -1
  97. package/dist/components/layouts/shared/components/profile_pic_menu_wrapper.d.ts +1 -1
  98. package/dist/components/layouts/shared/components/profile_pic_menu_wrapper.d.ts.map +1 -1
  99. package/dist/components/layouts/shared/components/profile_stamp.d.ts +1 -1
  100. package/dist/components/layouts/shared/components/profile_stamp.d.ts.map +1 -1
  101. package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts +1 -1
  102. package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts.map +1 -1
  103. package/dist/components/layouts/shared/components/standalone_layout_wrapper.d.ts +1 -1
  104. package/dist/components/layouts/shared/components/standalone_layout_wrapper.d.ts.map +1 -1
  105. package/dist/components/layouts/shared/components/two_column_auth_layout.d.ts +1 -1
  106. package/dist/components/layouts/shared/components/two_column_auth_layout.d.ts.map +1 -1
  107. package/dist/components/layouts/shared/components/unauthorized_guard.d.ts +1 -1
  108. package/dist/components/layouts/shared/components/unauthorized_guard.d.ts.map +1 -1
  109. package/dist/components/layouts/shared/components/visual_panel.d.ts +1 -1
  110. package/dist/components/layouts/shared/components/visual_panel.d.ts.map +1 -1
  111. package/dist/components/layouts/user_management/components/app_user_data_editor.d.ts +1 -1
  112. package/dist/components/layouts/user_management/components/app_user_data_editor.d.ts.map +1 -1
  113. package/dist/components/layouts/user_management/components/roles_matrix.d.ts +1 -1
  114. package/dist/components/layouts/user_management/components/roles_matrix.d.ts.map +1 -1
  115. package/dist/components/layouts/user_management/components/scope_hierarchy_tab.d.ts +1 -1
  116. package/dist/components/layouts/user_management/components/scope_hierarchy_tab.d.ts.map +1 -1
  117. package/dist/components/layouts/user_management/components/user_scopes_tab.d.ts +1 -1
  118. package/dist/components/layouts/user_management/components/user_scopes_tab.d.ts.map +1 -1
  119. package/dist/components/layouts/user_management/index.d.ts +1 -1
  120. package/dist/components/layouts/user_management/index.d.ts.map +1 -1
  121. package/dist/components/permission_denied_dialog.client.d.ts +19 -0
  122. package/dist/components/permission_denied_dialog.client.d.ts.map +1 -0
  123. package/dist/components/permission_denied_dialog.client.js +112 -0
  124. package/dist/components/ui/alert-dialog.d.ts +2 -2
  125. package/dist/components/ui/dialog.d.ts +2 -2
  126. package/dist/components/ui/dropdown-menu.d.ts +1 -1
  127. package/dist/components/ui/hazo_ui_tooltip.d.ts +1 -1
  128. package/dist/components/ui/hazo_ui_tooltip.d.ts.map +1 -1
  129. package/dist/components/ui/sheet.d.ts +2 -2
  130. package/dist/components/ui/skeleton.d.ts +1 -1
  131. package/dist/components/ui/skeleton.d.ts.map +1 -1
  132. package/dist/components/ui/sonner.d.ts +1 -1
  133. package/dist/components/ui/sonner.d.ts.map +1 -1
  134. package/dist/components/ui/tree-view.d.ts +1 -1
  135. package/dist/components/ui/tree-view.d.ts.map +1 -1
  136. package/dist/components/ui/user-type-badge.d.ts +1 -1
  137. package/dist/components/ui/user-type-badge.d.ts.map +1 -1
  138. package/dist/consent/cookie_consent_banner.d.ts +1 -1
  139. package/dist/consent/cookie_consent_banner.d.ts.map +1 -1
  140. package/dist/consent/manage_modal.d.ts +1 -1
  141. package/dist/consent/manage_modal.d.ts.map +1 -1
  142. package/dist/contexts/hazo_auth_provider.d.ts +2 -2
  143. package/dist/contexts/hazo_auth_provider.d.ts.map +1 -1
  144. package/dist/lib/auth/deny_permission.server.d.ts +18 -0
  145. package/dist/lib/auth/deny_permission.server.d.ts.map +1 -0
  146. package/dist/lib/auth/deny_permission.server.js +66 -0
  147. package/dist/lib/auth/index.d.ts +2 -0
  148. package/dist/lib/auth/index.d.ts.map +1 -1
  149. package/dist/lib/auth/index.js +2 -0
  150. package/dist/lib/auth/with_permission_issue_capture.server.d.ts +49 -0
  151. package/dist/lib/auth/with_permission_issue_capture.server.d.ts.map +1 -0
  152. package/dist/lib/auth/with_permission_issue_capture.server.js +152 -0
  153. package/dist/lib/services/find_roles_with_permission.d.ts +12 -0
  154. package/dist/lib/services/find_roles_with_permission.d.ts.map +1 -0
  155. package/dist/lib/services/find_roles_with_permission.js +38 -0
  156. package/dist/page_components/create_firm.d.ts +1 -1
  157. package/dist/page_components/create_firm.d.ts.map +1 -1
  158. package/dist/page_components/dev_lock.d.ts +1 -1
  159. package/dist/page_components/dev_lock.d.ts.map +1 -1
  160. package/dist/page_components/my_settings.d.ts +1 -1
  161. package/dist/page_components/my_settings.d.ts.map +1 -1
  162. package/dist/server-lib.d.ts +7 -0
  163. package/dist/server-lib.d.ts.map +1 -1
  164. package/dist/server-lib.js +7 -0
  165. package/dist/server_pages/forgot_password.d.ts +1 -1
  166. package/dist/server_pages/forgot_password.d.ts.map +1 -1
  167. package/dist/server_pages/forgot_password_client_wrapper.d.ts +1 -1
  168. package/dist/server_pages/forgot_password_client_wrapper.d.ts.map +1 -1
  169. package/dist/server_pages/login.d.ts +1 -1
  170. package/dist/server_pages/login.d.ts.map +1 -1
  171. package/dist/server_pages/login_client_wrapper.d.ts +1 -1
  172. package/dist/server_pages/login_client_wrapper.d.ts.map +1 -1
  173. package/dist/server_pages/my_settings.d.ts +1 -1
  174. package/dist/server_pages/my_settings.d.ts.map +1 -1
  175. package/dist/server_pages/register.d.ts +1 -1
  176. package/dist/server_pages/register.d.ts.map +1 -1
  177. package/dist/server_pages/register_client_wrapper.d.ts +1 -1
  178. package/dist/server_pages/register_client_wrapper.d.ts.map +1 -1
  179. package/dist/server_pages/reset_password.d.ts +1 -1
  180. package/dist/server_pages/reset_password.d.ts.map +1 -1
  181. package/dist/server_pages/reset_password_client_wrapper.d.ts +1 -1
  182. package/dist/server_pages/reset_password_client_wrapper.d.ts.map +1 -1
  183. package/dist/server_pages/verify_email.d.ts +1 -1
  184. package/dist/server_pages/verify_email.d.ts.map +1 -1
  185. package/dist/server_pages/verify_email_client_wrapper.d.ts +1 -1
  186. package/dist/server_pages/verify_email_client_wrapper.d.ts.map +1 -1
  187. package/dist/strings/strings_provider.d.ts +1 -1
  188. package/dist/strings/strings_provider.d.ts.map +1 -1
  189. package/dist/theme/theme_provider.d.ts +1 -1
  190. package/dist/theme/theme_provider.d.ts.map +1 -1
  191. package/package.json +19 -11
@@ -0,0 +1,101 @@
1
+ // file_description: standalone helper to return a 403 FORBIDDEN response and fire the permission-denied handler
2
+ import 'server-only';
3
+
4
+ import {
5
+ buildDenialPayloadFromRequest,
6
+ buildForbiddenResponse,
7
+ getPermissionDeniedHandler,
8
+ type PermissionDeniedPayload,
9
+ } from './with_permission_issue_capture.server.js';
10
+
11
+ export interface DenyPermissionInput {
12
+ request: Request;
13
+ /** HazoAuthResult | TenantAuthResult | any auth-like shape */
14
+ auth: any;
15
+ missing_permissions: string[];
16
+ /** Defaults to missing_permissions */
17
+ required_permissions?: string[];
18
+ permission_descriptions?: Record<string, string>;
19
+ /** Falls back to X-Hazo-Action-Label header, then permission join */
20
+ action_label?: string;
21
+ /** Falls back to default message */
22
+ user_friendly_message?: string;
23
+ /** Falls back to new URL(request.url).pathname */
24
+ api_route?: string;
25
+ }
26
+
27
+ function extractUserId(auth: any): string {
28
+ return (
29
+ auth?.user?.id ||
30
+ auth?.tenant?.user_id ||
31
+ auth?.user_id ||
32
+ ''
33
+ );
34
+ }
35
+
36
+ function extractScopeId(auth: any): string | undefined {
37
+ return (
38
+ auth?.tenant?.scope_id ??
39
+ auth?.scope_id ??
40
+ auth?.organization?.id ??
41
+ auth?.organization_id ??
42
+ undefined
43
+ );
44
+ }
45
+
46
+ export function denyPermission(input: DenyPermissionInput): Response {
47
+ const user_id = extractUserId(input.auth);
48
+ const scope_id = extractScopeId(input.auth);
49
+
50
+ const payload: PermissionDeniedPayload = buildDenialPayloadFromRequest(input.request, {
51
+ user_id,
52
+ scope_id,
53
+ missing_permissions: input.missing_permissions,
54
+ required_permissions: input.required_permissions,
55
+ permission_descriptions: input.permission_descriptions,
56
+ action_label: input.action_label,
57
+ user_friendly_message: input.user_friendly_message,
58
+ api_route: input.api_route,
59
+ });
60
+
61
+ // Fire handler best-effort — do not await, must not delay the 403
62
+ Promise.resolve(getPermissionDeniedHandler()?.(payload)).catch((e) => {
63
+ console.warn('[hazo_auth] denyPermission: permission denied handler failed', e);
64
+ });
65
+
66
+ // buildForbiddenResponse is async (dynamic import of hazo_api), but denyPermission must be
67
+ // synchronous to match the function signature. We build the fallback synchronously here
68
+ // and fire the async hazo_api path only when available. In practice, the caller immediately
69
+ // returns the Response so we use the sync fallback — consumers that need the hazo_api
70
+ // envelope can await a wrapping async function or use withPermissionIssueCapture instead.
71
+ const bodyJson = JSON.stringify({
72
+ ok: false,
73
+ error: {
74
+ code: 'FORBIDDEN',
75
+ message: payload.user_friendly_message,
76
+ details: {
77
+ missing_permissions: payload.missing_permissions,
78
+ permission_descriptions: payload.permission_descriptions,
79
+ action_label: payload.action_label,
80
+ origin_url: payload.origin_url,
81
+ user_friendly_message: payload.user_friendly_message,
82
+ },
83
+ },
84
+ });
85
+
86
+ // Kick off async hazo_api enhancement but return the sync response immediately.
87
+ // The returned Response object is the sync fallback; hazo_api is decorative for
88
+ // middleware use cases that don't need the exact envelope.
89
+ void import('hazo_api')
90
+ .then((m: any) => {
91
+ if (typeof m?.fail === 'function') {
92
+ // No-op: we already returned — this is a fire-and-forget; nothing to do with the result.
93
+ }
94
+ })
95
+ .catch(() => undefined);
96
+
97
+ return new Response(bodyJson, {
98
+ status: 403,
99
+ headers: { 'Content-Type': 'application/json' },
100
+ });
101
+ }
@@ -60,3 +60,11 @@ export { get_auth_cache, reset_auth_cache } from "./auth_cache.js";
60
60
  // section: rate_limiter_exports
61
61
  export { get_rate_limiter, reset_rate_limiter } from "./auth_rate_limiter.js";
62
62
 
63
+ // section: permission_issue_capture_exports
64
+ export {
65
+ withPermissionIssueCapture,
66
+ setPermissionDeniedHandler,
67
+ getPermissionDeniedHandler,
68
+ } from "./with_permission_issue_capture.server.js";
69
+ export type { PermissionDeniedPayload } from "./with_permission_issue_capture.server";
70
+
@@ -0,0 +1,222 @@
1
+ // file_description: Route handler wrapper that catches PermissionError and returns a structured hazo_api fail() 403
2
+ // section: server-only-guard
3
+ import 'server-only';
4
+
5
+ // section: imports
6
+ import { type NextRequest } from 'next/server';
7
+ import { createLogger } from 'hazo_core';
8
+ import { PermissionError } from './auth_types.js';
9
+ import { hazo_get_auth } from './hazo_get_auth.server.js';
10
+
11
+ const log = createLogger('hazo_auth:permission_capture');
12
+
13
+ // section: types
14
+
15
+ export interface PermissionDeniedPayload {
16
+ user_id: string;
17
+ scope_id?: string;
18
+ missing_permissions: string[];
19
+ required_permissions: string[];
20
+ user_permissions: string[];
21
+ permission_descriptions: Record<string, string>;
22
+ user_friendly_message: string;
23
+ action_label: string;
24
+ origin_url: string;
25
+ api_route: string;
26
+ }
27
+
28
+ // section: global_callback
29
+
30
+ /**
31
+ * Global callback, set once at app boot by the consuming app.
32
+ * DI: hazo_auth does NOT import hazo_admin; the app passes createOrBumpIssue here.
33
+ */
34
+ let _onPermissionDenied: ((payload: PermissionDeniedPayload) => void | Promise<void>) | null = null;
35
+
36
+ export function setPermissionDeniedHandler(
37
+ fn: (payload: PermissionDeniedPayload) => void | Promise<void>,
38
+ ): void {
39
+ _onPermissionDenied = fn;
40
+ }
41
+
42
+ export function getPermissionDeniedHandler() {
43
+ return _onPermissionDenied;
44
+ }
45
+
46
+ // section: build_payload_helper
47
+
48
+ export interface BuildDenialPayloadParts {
49
+ user_id: string;
50
+ scope_id?: string;
51
+ missing_permissions: string[];
52
+ required_permissions?: string[];
53
+ permission_descriptions?: Record<string, string>;
54
+ action_label?: string;
55
+ user_friendly_message?: string;
56
+ api_route?: string;
57
+ user_permissions?: string[];
58
+ }
59
+
60
+ /**
61
+ * Shared helper: builds a PermissionDeniedPayload from a request + explicit parts.
62
+ * Called by both withPermissionIssueCapture and denyPermission.
63
+ */
64
+ export function buildDenialPayloadFromRequest(
65
+ request: Request,
66
+ parts: BuildDenialPayloadParts,
67
+ ): PermissionDeniedPayload {
68
+ const originUrl =
69
+ request.headers.get('x-hazo-origin-url') ||
70
+ request.headers.get('referer') ||
71
+ '';
72
+
73
+ const actionLabelFromHeader = request.headers.get('x-hazo-action-label') || '';
74
+ const descriptions = parts.permission_descriptions ?? {};
75
+
76
+ const actionLabel =
77
+ parts.action_label ||
78
+ actionLabelFromHeader ||
79
+ parts.missing_permissions.map((p) => descriptions[p] || p).join(', ');
80
+
81
+ let apiRoute = parts.api_route ?? '';
82
+ if (!apiRoute) {
83
+ try {
84
+ apiRoute = new URL(request.url).pathname;
85
+ } catch {
86
+ /* ignore */
87
+ }
88
+ }
89
+
90
+ return {
91
+ user_id: parts.user_id,
92
+ scope_id: parts.scope_id,
93
+ missing_permissions: parts.missing_permissions,
94
+ required_permissions: parts.required_permissions ?? parts.missing_permissions,
95
+ user_permissions: parts.user_permissions ?? [],
96
+ permission_descriptions: descriptions,
97
+ user_friendly_message:
98
+ parts.user_friendly_message ?? "You don't have permission to perform this action.",
99
+ action_label: actionLabel,
100
+ origin_url: originUrl,
101
+ api_route: apiRoute,
102
+ };
103
+ }
104
+
105
+ // section: response_helper
106
+
107
+ /** Builds the 403 Response, using hazo_api.fail() if available, otherwise hand-built. */
108
+ export async function buildForbiddenResponse(payload: PermissionDeniedPayload): Promise<Response> {
109
+ const apiMod = (await import('hazo_api').catch(() => null)) as {
110
+ fail?: (
111
+ code: string,
112
+ message: string,
113
+ opts?: { details?: unknown; status?: number },
114
+ ) => Response;
115
+ } | null;
116
+
117
+ if (apiMod?.fail) {
118
+ return apiMod.fail('FORBIDDEN', payload.user_friendly_message, {
119
+ status: 403,
120
+ details: {
121
+ missing_permissions: payload.missing_permissions,
122
+ user_friendly_message: payload.user_friendly_message,
123
+ permission_descriptions: payload.permission_descriptions,
124
+ action_label: payload.action_label,
125
+ origin_url: payload.origin_url,
126
+ },
127
+ });
128
+ }
129
+
130
+ return new Response(
131
+ JSON.stringify({
132
+ ok: false,
133
+ error: {
134
+ code: 'FORBIDDEN',
135
+ message: payload.user_friendly_message,
136
+ details: {
137
+ missing_permissions: payload.missing_permissions,
138
+ permission_descriptions: payload.permission_descriptions,
139
+ action_label: payload.action_label,
140
+ origin_url: payload.origin_url,
141
+ },
142
+ },
143
+ }),
144
+ { status: 403, headers: { 'Content-Type': 'application/json' } },
145
+ );
146
+ }
147
+
148
+ // section: wrapper
149
+
150
+ /**
151
+ * Wraps a Next.js route handler. On PermissionError, returns a structured
152
+ * hazo_api fail() 403 with code FORBIDDEN and fires the registered
153
+ * onPermissionDenied callback best-effort.
154
+ *
155
+ * Usage:
156
+ * export const POST = withPermissionIssueCapture(
157
+ * async (request) => { ... },
158
+ * { required_permissions: ['edit_config'] }
159
+ * );
160
+ */
161
+ export function withPermissionIssueCapture(
162
+ handler: (request: NextRequest) => Promise<Response>,
163
+ opts: { required_permissions: string[] },
164
+ ): (request: NextRequest) => Promise<Response> {
165
+ return async (request: NextRequest): Promise<Response> => {
166
+ try {
167
+ // Run hazo_get_auth with strict=true so PermissionError is thrown on denial
168
+ await hazo_get_auth(request, {
169
+ required_permissions: opts.required_permissions,
170
+ strict: true,
171
+ });
172
+
173
+ // On success, hand off to the original handler
174
+ return await handler(request);
175
+ } catch (err) {
176
+ if (err instanceof PermissionError) {
177
+ // Convert PermissionError.permission_descriptions Map → plain object
178
+ const descriptions: Record<string, string> = {};
179
+ if (err.permission_descriptions) {
180
+ err.permission_descriptions.forEach((v, k) => {
181
+ descriptions[k] = v;
182
+ });
183
+ }
184
+
185
+ // Try to extract user_id from session — best-effort, non-strict re-call
186
+ let userId = '';
187
+ try {
188
+ const lax = await hazo_get_auth(request, {
189
+ required_permissions: [],
190
+ strict: false,
191
+ });
192
+ if (lax.authenticated) {
193
+ userId = lax.user.id;
194
+ }
195
+ } catch {
196
+ /* ignore — user_id stays '' */
197
+ }
198
+
199
+ const payload = buildDenialPayloadFromRequest(request, {
200
+ user_id: userId,
201
+ missing_permissions: err.missing_permissions,
202
+ required_permissions: err.required_permissions,
203
+ user_permissions: err.user_permissions,
204
+ permission_descriptions: descriptions,
205
+ user_friendly_message: err.user_friendly_message,
206
+ });
207
+
208
+ // Fire callback best-effort (do NOT await — must not delay the 403 response)
209
+ if (_onPermissionDenied) {
210
+ Promise.resolve(_onPermissionDenied(payload)).catch((cbErr) => {
211
+ log.warn('onPermissionDenied callback failed', { error: cbErr });
212
+ });
213
+ }
214
+
215
+ return buildForbiddenResponse(payload);
216
+ }
217
+
218
+ // Re-throw non-permission errors
219
+ throw err;
220
+ }
221
+ };
222
+ }
@@ -0,0 +1,47 @@
1
+ // file_description: helper to find roles that have a given permission and are actively used in a scope
2
+ import 'server-only';
3
+
4
+ import { create_app_logger } from '../app_logger.js';
5
+
6
+ export interface RoleWithPermission {
7
+ id: string;
8
+ name: string;
9
+ }
10
+
11
+ /**
12
+ * Returns all roles that (a) have the given permission and (b) are actively
13
+ * used in the given scope (at least one user assigned to that scope via that role).
14
+ * Returns empty array if permission doesn't exist or no matching roles.
15
+ */
16
+ export async function find_roles_with_permission(
17
+ adapter: any,
18
+ scope_id: string,
19
+ permission_name: string,
20
+ ): Promise<RoleWithPermission[]> {
21
+ const logger = create_app_logger();
22
+ try {
23
+ const sql = `
24
+ SELECT DISTINCT r.id, r.name
25
+ FROM hazo_roles r
26
+ JOIN hazo_role_permissions rp ON rp.role_id = r.id
27
+ JOIN hazo_permissions p ON p.id = rp.permission_id
28
+ JOIN hazo_user_scopes us ON us.role_id = r.id AND us.scope_id = $1
29
+ WHERE p.permission_name = $2
30
+ `;
31
+ const rows: unknown = await adapter.raw(sql, [scope_id, permission_name]);
32
+ if (!Array.isArray(rows)) return [];
33
+ return rows.map((row) => {
34
+ const r = row as { id: string; name: string };
35
+ return { id: r.id, name: r.name };
36
+ });
37
+ } catch (error) {
38
+ logger.error('find_roles_with_permission_error', {
39
+ filename: 'find_roles_with_permission.ts',
40
+ line_number: 0,
41
+ error: error instanceof Error ? error.message : String(error),
42
+ scope_id,
43
+ permission_name,
44
+ });
45
+ return [];
46
+ }
47
+ }
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import { type PermissionDeniedDetails } from '../components/permission_denied_dialog.client.js';
3
+ export declare function showPermissionDeniedDialog(details: PermissionDeniedDetails, message?: string): void;
4
+ export interface PermissionDeniedProviderProps {
5
+ children?: React.ReactNode;
6
+ registerCardRenderer?: (typeKey: string, renderer: React.ComponentType<any>) => void;
7
+ }
8
+ export declare function PermissionDeniedProvider({ children, registerCardRenderer }: PermissionDeniedProviderProps): React.JSX.Element;
9
+ export declare function handlePermissionDenied(response: Response): Promise<boolean>;
10
+ export declare function fetchWithPermissionCapture(input: RequestInfo | URL, init?: RequestInit & {
11
+ originUrl?: string;
12
+ actionLabel?: string;
13
+ }): Promise<Response>;
14
+ //# sourceMappingURL=permission_denied_provider.client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permission_denied_provider.client.d.ts","sourceRoot":"","sources":["../../src/admin-issues/permission_denied_provider.client.tsx"],"names":[],"mappings":"AAGA,OAAO,KAA8B,MAAM,OAAO,CAAC;AACnD,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,kDAAkD,CAAC;AAO1D,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,uBAAuB,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAInG;AAID,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,oBAAoB,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC;CACtF;AAED,wBAAgB,wBAAwB,CAAC,EAAE,QAAQ,EAAE,oBAAoB,EAAE,EAAE,6BAA6B,qBAgCzG;AAID,wBAAsB,sBAAsB,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAmBjF;AAID,wBAAsB,0BAA0B,CAC9C,KAAK,EAAE,WAAW,GAAG,GAAG,EACxB,IAAI,CAAC,EAAE,WAAW,GAAG;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAChE,OAAO,CAAC,QAAQ,CAAC,CAcnB"}
@@ -0,0 +1,80 @@
1
+ 'use client';
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
14
+ // file_description: singleton provider + fetch helper that shows PermissionDeniedDialog on 403 responses
15
+ import { useEffect, useState } from 'react';
16
+ import { PermissionDeniedDialog, } from '../components/permission_denied_dialog.client.js';
17
+ import { AuthIssueCard } from './plugin.client.js';
18
+ // ── singleton trigger ─────────────────────────────────────────────────────────
19
+ let _showDialog = null;
20
+ export function showPermissionDeniedDialog(details, message) {
21
+ if (_showDialog) {
22
+ _showDialog(details, message);
23
+ }
24
+ }
25
+ export function PermissionDeniedProvider({ children, registerCardRenderer }) {
26
+ const [open, setOpen] = useState(false);
27
+ const [details, setDetails] = useState(null);
28
+ const [message, setMessage] = useState(undefined);
29
+ useEffect(() => {
30
+ _showDialog = (d, m) => {
31
+ setDetails(d);
32
+ setMessage(m);
33
+ setOpen(true);
34
+ };
35
+ if (registerCardRenderer) {
36
+ registerCardRenderer('auth_permission', AuthIssueCard);
37
+ }
38
+ return () => {
39
+ _showDialog = null;
40
+ };
41
+ }, [registerCardRenderer]);
42
+ return (_jsxs(_Fragment, { children: [children, _jsx(PermissionDeniedDialog, { open: open, onOpenChange: setOpen, friendlyMessage: message, technicalDetails: details !== null && details !== void 0 ? details : undefined })] }));
43
+ }
44
+ // ── handlePermissionDenied ────────────────────────────────────────────────────
45
+ export async function handlePermissionDenied(response) {
46
+ var _a, _b;
47
+ try {
48
+ const cloned = response.clone();
49
+ const body = await cloned.json();
50
+ if (((_a = body === null || body === void 0 ? void 0 : body.error) === null || _a === void 0 ? void 0 : _a.code) !== 'FORBIDDEN')
51
+ return false;
52
+ const errDetails = (_b = body.error.details) !== null && _b !== void 0 ? _b : {};
53
+ const permDetails = {
54
+ missing_permissions: errDetails.missing_permissions,
55
+ permission_descriptions: errDetails.permission_descriptions,
56
+ action_label: errDetails.action_label,
57
+ origin_url: errDetails.origin_url,
58
+ };
59
+ showPermissionDeniedDialog(permDetails, body.error.message);
60
+ return true;
61
+ }
62
+ catch (_c) {
63
+ return false;
64
+ }
65
+ }
66
+ // ── fetchWithPermissionCapture ────────────────────────────────────────────────
67
+ export async function fetchWithPermissionCapture(input, init) {
68
+ var _a;
69
+ const _b = init !== null && init !== void 0 ? init : {}, { originUrl, actionLabel } = _b, cleanInit = __rest(_b, ["originUrl", "actionLabel"]);
70
+ const headers = new Headers((_a = cleanInit.headers) !== null && _a !== void 0 ? _a : {});
71
+ if (originUrl)
72
+ headers.set('X-Hazo-Origin-Url', originUrl);
73
+ if (actionLabel)
74
+ headers.set('X-Hazo-Action-Label', actionLabel);
75
+ const response = await fetch(input, Object.assign(Object.assign({}, cleanInit), { headers }));
76
+ if (!response.ok) {
77
+ await handlePermissionDenied(response);
78
+ }
79
+ return response;
80
+ }
@@ -0,0 +1,34 @@
1
+ import React from 'react';
2
+ interface IssueCardData {
3
+ id: string;
4
+ type: string;
5
+ status: string;
6
+ subject_user_id: string;
7
+ assigned_to: string | null;
8
+ title: string;
9
+ summary: string;
10
+ payload: Record<string, unknown>;
11
+ occurrence_count: number;
12
+ first_seen_at: string;
13
+ last_seen_at: string;
14
+ resolution: string | null;
15
+ resolution_reason: string | null;
16
+ resolved_by: string | null;
17
+ resolved_at: string | null;
18
+ }
19
+ interface IssueCardRendererProps {
20
+ issue: IssueCardData;
21
+ basePath: string;
22
+ onAction?: (actionKey: string, params: Record<string, unknown>) => Promise<void>;
23
+ }
24
+ export declare function AuthIssueCard({ issue, onAction }: IssueCardRendererProps): React.JSX.Element;
25
+ /**
26
+ * Convenience registration function.
27
+ * Consumer app calls this at boot, passing hazo_admin/client's registerIssueCardRenderer.
28
+ * hazo_auth does NOT import hazo_admin (DI principle).
29
+ */
30
+ export declare function registerAuthIssueCardRenderer(opts: {
31
+ registerRenderer: (typeKey: string, renderer: React.ComponentType<IssueCardRendererProps>) => void;
32
+ }): void;
33
+ export {};
34
+ //# sourceMappingURL=plugin.client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.client.d.ts","sourceRoot":"","sources":["../../src/admin-issues/plugin.client.tsx"],"names":[],"mappings":"AACA,OAAO,KAAmB,MAAM,OAAO,CAAC;AAGxC,UAAU,aAAa;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,UAAU,sBAAsB;IAC9B,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAClF;AAED,wBAAgB,aAAa,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,sBAAsB,qBA+IxE;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE;IAClD,gBAAgB,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,aAAa,CAAC,sBAAsB,CAAC,KAAK,IAAI,CAAC;CACpG,GAAG,IAAI,CAEP"}
@@ -0,0 +1,64 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from 'react';
4
+ export function AuthIssueCard({ issue, onAction }) {
5
+ const [showGrant, setShowGrant] = useState(false);
6
+ const [showDeny, setShowDeny] = useState(false);
7
+ const [roleId, setRoleId] = useState('');
8
+ const [denyReason, setDenyReason] = useState('');
9
+ const [loading, setLoading] = useState(false);
10
+ const [error, setError] = useState(null);
11
+ const payload = issue.payload;
12
+ const missingPerms = payload.missing_permissions || [];
13
+ const descriptions = payload.permission_descriptions || {};
14
+ const actionLabel = payload.action_label || '';
15
+ const originUrl = payload.origin_url || '';
16
+ const isActive = issue.status === 'new' || issue.status === 'wip';
17
+ const handleGrant = async () => {
18
+ if (!roleId.trim()) {
19
+ setError('Please enter a role ID.');
20
+ return;
21
+ }
22
+ setLoading(true);
23
+ setError(null);
24
+ try {
25
+ await (onAction === null || onAction === void 0 ? void 0 : onAction('grant', { role_id: roleId.trim() }));
26
+ setShowGrant(false);
27
+ }
28
+ catch (e) {
29
+ const err = e;
30
+ setError((err === null || err === void 0 ? void 0 : err.message) || 'Grant failed');
31
+ }
32
+ finally {
33
+ setLoading(false);
34
+ }
35
+ };
36
+ const handleDeny = async () => {
37
+ if (!denyReason.trim()) {
38
+ setError('Please provide a reason.');
39
+ return;
40
+ }
41
+ setLoading(true);
42
+ setError(null);
43
+ try {
44
+ await (onAction === null || onAction === void 0 ? void 0 : onAction('deny', { reason: denyReason.trim() }));
45
+ setShowDeny(false);
46
+ }
47
+ catch (e) {
48
+ const err = e;
49
+ setError((err === null || err === void 0 ? void 0 : err.message) || 'Deny failed');
50
+ }
51
+ finally {
52
+ setLoading(false);
53
+ }
54
+ };
55
+ return (_jsxs("div", { className: "text-sm space-y-2", children: [_jsx("div", { className: "text-gray-700", children: issue.summary }), missingPerms.length > 0 && (_jsxs("div", { className: "text-xs text-gray-500", children: [_jsx("span", { className: "font-medium", children: "Needs: " }), missingPerms.map((p) => descriptions[p] || p).join(', ')] })), actionLabel && (_jsxs("div", { className: "text-xs text-gray-400", children: [_jsx("span", { className: "font-medium", children: "Tried to: " }), actionLabel] })), originUrl && (_jsxs("div", { className: "text-xs text-gray-400", children: [_jsx("span", { className: "font-medium", children: "From: " }), _jsx("span", { className: "font-mono", children: originUrl })] })), issue.occurrence_count > 1 && (_jsxs("div", { className: "text-xs text-amber-600 font-medium", children: ["Occurred ", issue.occurrence_count, "\u00D7 (first: ", new Date(issue.first_seen_at).toLocaleDateString(), ")"] })), isActive && onAction && (_jsxs("div", { className: "flex gap-2 pt-1", children: [_jsx("button", { onClick: () => { setShowGrant(true); setShowDeny(false); setError(null); }, className: "px-2 py-1 text-xs bg-green-600 text-white rounded hover:bg-green-700", children: "Grant" }), _jsx("button", { onClick: () => { setShowDeny(true); setShowGrant(false); setError(null); }, className: "px-2 py-1 text-xs bg-red-600 text-white rounded hover:bg-red-700", children: "Deny" })] })), showGrant && (_jsxs("div", { className: "mt-2 p-2 border rounded bg-green-50 space-y-2", children: [_jsx("div", { className: "text-xs font-medium text-green-800", children: "Grant access \u2014 enter the role ID to assign:" }), _jsx("input", { type: "text", value: roleId, onChange: (e) => setRoleId(e.target.value), placeholder: "Role ID (UUID)", className: "w-full text-xs border rounded px-2 py-1" }), error && _jsx("div", { className: "text-xs text-red-600", children: error }), _jsxs("div", { className: "flex gap-2", children: [_jsx("button", { onClick: handleGrant, disabled: loading, className: "px-2 py-1 text-xs bg-green-600 text-white rounded disabled:opacity-50", children: loading ? 'Granting…' : 'Confirm Grant' }), _jsx("button", { onClick: () => setShowGrant(false), className: "px-2 py-1 text-xs border rounded", children: "Cancel" })] })] })), showDeny && (_jsxs("div", { className: "mt-2 p-2 border rounded bg-red-50 space-y-2", children: [_jsx("div", { className: "text-xs font-medium text-red-800", children: "Deny request \u2014 provide a reason:" }), _jsx("textarea", { value: denyReason, onChange: (e) => setDenyReason(e.target.value), placeholder: "Reason for denial", rows: 2, className: "w-full text-xs border rounded px-2 py-1" }), error && _jsx("div", { className: "text-xs text-red-600", children: error }), _jsxs("div", { className: "flex gap-2", children: [_jsx("button", { onClick: handleDeny, disabled: loading, className: "px-2 py-1 text-xs bg-red-600 text-white rounded disabled:opacity-50", children: loading ? 'Denying…' : 'Confirm Deny' }), _jsx("button", { onClick: () => setShowDeny(false), className: "px-2 py-1 text-xs border rounded", children: "Cancel" })] })] })), issue.resolution && (_jsxs("div", { className: `text-xs mt-1 ${issue.resolution === 'granted' ? 'text-green-700' : 'text-red-700'}`, children: [issue.resolution === 'granted' ? '✓ Granted' : '✗ Denied', issue.resolution_reason && `: ${issue.resolution_reason}`] }))] }));
56
+ }
57
+ /**
58
+ * Convenience registration function.
59
+ * Consumer app calls this at boot, passing hazo_admin/client's registerIssueCardRenderer.
60
+ * hazo_auth does NOT import hazo_admin (DI principle).
61
+ */
62
+ export function registerAuthIssueCardRenderer(opts) {
63
+ opts.registerRenderer('auth_permission', AuthIssueCard);
64
+ }
@@ -0,0 +1,59 @@
1
+ import 'server-only';
2
+ interface LocalIssueRecord {
3
+ id: string;
4
+ scope_id: string;
5
+ type: string;
6
+ subject_user_id: string;
7
+ assigned_to: string | null;
8
+ payload: Record<string, unknown>;
9
+ resolution: string | null;
10
+ [key: string]: unknown;
11
+ }
12
+ interface LocalIssueActionCtx {
13
+ getHazoConnect: () => Promise<any> | any;
14
+ actorUserId: string;
15
+ actorPermissions: string[];
16
+ }
17
+ interface LocalIssueActionResult {
18
+ success: boolean;
19
+ message?: string;
20
+ data?: Record<string, unknown>;
21
+ }
22
+ interface LocalNotifyPayload {
23
+ subject: string;
24
+ body: string;
25
+ deep_link?: string;
26
+ payload?: Record<string, unknown>;
27
+ }
28
+ interface LocalIssueActionDef {
29
+ key: string;
30
+ label: string;
31
+ requiredPermission: string;
32
+ run(issue: LocalIssueRecord, params: Record<string, unknown>, ctx: LocalIssueActionCtx): Promise<LocalIssueActionResult>;
33
+ }
34
+ interface LocalIssueTypeDef {
35
+ typeKey: string;
36
+ label: string;
37
+ buildDescriptor(payload: Record<string, unknown>): {
38
+ title: string;
39
+ summary: string;
40
+ };
41
+ resolveRecipients(issue: LocalIssueRecord, ctx: LocalIssueActionCtx): Promise<{
42
+ user_ids: string[];
43
+ scope_id: string;
44
+ }>;
45
+ actions: LocalIssueActionDef[];
46
+ buildResolutionNotice(issue: LocalIssueRecord, actionKey: string, result: LocalIssueActionResult): LocalNotifyPayload;
47
+ }
48
+ export declare const authIssueTypeDef: LocalIssueTypeDef;
49
+ /**
50
+ * Convenience registration function.
51
+ * The app calls this at boot, passing hazo_admin's registerIssueType.
52
+ * hazo_auth does NOT import hazo_admin (DI principle).
53
+ */
54
+ export declare function registerAuthIssuePlugin(opts: {
55
+ registerType: (def: any) => void;
56
+ getHazoConnect?: () => Promise<any> | any;
57
+ }): void;
58
+ export {};
59
+ //# sourceMappingURL=plugin.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.server.d.ts","sourceRoot":"","sources":["../../src/admin-issues/plugin.server.ts"],"names":[],"mappings":"AACA,OAAO,aAAa,CAAC;AASrB,UAAU,gBAAgB;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,UAAU,mBAAmB;IAC3B,cAAc,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,UAAU,sBAAsB;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,UAAU,kBAAkB;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED,UAAU,mBAAmB;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB,EAAE,MAAM,CAAC;IAC3B,GAAG,CACD,KAAK,EAAE,gBAAgB,EACvB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,GAAG,EAAE,mBAAmB,GACvB,OAAO,CAAC,sBAAsB,CAAC,CAAC;CACpC;AAED,UAAU,iBAAiB;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACtF,iBAAiB,CACf,KAAK,EAAE,gBAAgB,EACvB,GAAG,EAAE,mBAAmB,GACvB,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,qBAAqB,CACnB,KAAK,EAAE,gBAAgB,EACvB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,sBAAsB,GAC7B,kBAAkB,CAAC;CACvB;AAED,eAAO,MAAM,gBAAgB,EAAE,iBAsK9B,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE;IAC5C,YAAY,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,IAAI,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;CAC3C,GAAG,IAAI,CAEP"}