hazo_auth 5.2.0 → 5.3.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 +13 -0
- package/SETUP_CHECKLIST.md +46 -0
- package/cli-src/lib/auth/hazo_get_auth.server.ts +1 -1
- package/cli-src/lib/auth/index.ts +1 -1
- package/cli-src/lib/services/email_service.ts +136 -289
- package/cli-src/lib/services/email_template_manifest.ts +104 -0
- package/cli-src/lib/services/email_templates/email_verification.html +18 -0
- package/cli-src/lib/services/email_templates/email_verification.txt +9 -0
- package/cli-src/lib/services/email_templates/forgot_password.html +18 -0
- package/cli-src/lib/services/email_templates/forgot_password.txt +9 -0
- package/cli-src/lib/services/email_templates/password_changed.html +14 -0
- package/cli-src/lib/services/email_templates/password_changed.txt +9 -0
- package/dist/components/ui/button.d.ts +2 -2
- package/dist/lib/auth/hazo_get_auth.server.d.ts +6 -0
- package/dist/lib/auth/hazo_get_auth.server.d.ts.map +1 -1
- package/dist/lib/auth/hazo_get_auth.server.js +1 -1
- package/dist/lib/auth/index.d.ts +1 -1
- package/dist/lib/auth/index.d.ts.map +1 -1
- package/dist/lib/auth/index.js +1 -1
- package/dist/lib/services/email_service.d.ts +17 -4
- package/dist/lib/services/email_service.d.ts.map +1 -1
- package/dist/lib/services/email_service.js +93 -221
- package/dist/lib/services/email_template_manifest.d.ts +11 -0
- package/dist/lib/services/email_template_manifest.d.ts.map +1 -0
- package/dist/lib/services/email_template_manifest.js +95 -0
- package/dist/lib/services/email_templates/email_verification.html +18 -0
- package/dist/lib/services/email_templates/email_verification.txt +9 -0
- package/dist/lib/services/email_templates/forgot_password.html +18 -0
- package/dist/lib/services/email_templates/forgot_password.txt +9 -0
- package/dist/lib/services/email_templates/password_changed.html +14 -0
- package/dist/lib/services/email_templates/password_changed.txt +9 -0
- package/dist/server-lib.d.ts +1 -0
- package/dist/server-lib.d.ts.map +1 -1
- package/dist/server-lib.js +1 -0
- package/package.json +4 -3
- package/cli-src/assets/images/new_firm_default.jpg +0 -0
- package/cli-src/lib/auth/org_cache.ts +0 -148
- package/cli-src/lib/index.ts +0 -48
- package/cli-src/lib/services/org_service.ts +0 -965
- package/cli-src/lib/services/scope_labels_service.ts +0 -348
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
// file_description: manifest of system email templates shipped by hazo_auth
|
|
2
|
+
// section: server_only_guard
|
|
3
|
+
import "server-only";
|
|
4
|
+
|
|
5
|
+
// section: imports
|
|
6
|
+
import fs from "fs";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import { fileURLToPath } from "url";
|
|
9
|
+
import type { SystemTemplateManifest } from "hazo_notify/template_manager";
|
|
10
|
+
|
|
11
|
+
// section: constants
|
|
12
|
+
const TEMPLATE_DIR = path.resolve(
|
|
13
|
+
path.dirname(fileURLToPath(import.meta.url)),
|
|
14
|
+
"email_templates"
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const SYSTEM_CATEGORY = "Auth";
|
|
18
|
+
|
|
19
|
+
// section: helpers
|
|
20
|
+
function read_template(template_name: string, extension: "html" | "txt"): string {
|
|
21
|
+
const file_path = path.join(TEMPLATE_DIR, `${template_name}.${extension}`);
|
|
22
|
+
return fs.readFileSync(file_path, "utf-8");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// section: manifest
|
|
26
|
+
/**
|
|
27
|
+
* System email templates shipped by hazo_auth.
|
|
28
|
+
*
|
|
29
|
+
* Consumers feed this into `init_template_manager({ manifests: [...hazo_auth_template_manifest] })`
|
|
30
|
+
* at boot. hazo_notify seeds/syncs the templates into its scope-aware database.
|
|
31
|
+
* Per-scope overrides are managed through the hazo_notify admin UI.
|
|
32
|
+
*/
|
|
33
|
+
export const hazo_auth_template_manifest: SystemTemplateManifest[] = [
|
|
34
|
+
{
|
|
35
|
+
template_name: "email_verification",
|
|
36
|
+
template_label: "Email verification",
|
|
37
|
+
category: SYSTEM_CATEGORY,
|
|
38
|
+
html: read_template("email_verification", "html"),
|
|
39
|
+
text: read_template("email_verification", "txt"),
|
|
40
|
+
variables: [
|
|
41
|
+
{
|
|
42
|
+
variable_name: "user_name",
|
|
43
|
+
variable_description: "Recipient display name",
|
|
44
|
+
default_value: "",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
variable_name: "user_email",
|
|
48
|
+
variable_description: "Recipient email",
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
variable_name: "verification_url",
|
|
52
|
+
variable_description: "Verification link with embedded token",
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
variable_name: "token",
|
|
56
|
+
variable_description: "Raw verification token",
|
|
57
|
+
},
|
|
58
|
+
],
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
template_name: "forgot_password",
|
|
62
|
+
template_label: "Forgot password",
|
|
63
|
+
category: SYSTEM_CATEGORY,
|
|
64
|
+
html: read_template("forgot_password", "html"),
|
|
65
|
+
text: read_template("forgot_password", "txt"),
|
|
66
|
+
variables: [
|
|
67
|
+
{
|
|
68
|
+
variable_name: "user_name",
|
|
69
|
+
variable_description: "Recipient display name",
|
|
70
|
+
default_value: "",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
variable_name: "user_email",
|
|
74
|
+
variable_description: "Recipient email",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
variable_name: "reset_url",
|
|
78
|
+
variable_description: "Password reset link",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
variable_name: "token",
|
|
82
|
+
variable_description: "Raw reset token",
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
template_name: "password_changed",
|
|
88
|
+
template_label: "Password changed",
|
|
89
|
+
category: SYSTEM_CATEGORY,
|
|
90
|
+
html: read_template("password_changed", "html"),
|
|
91
|
+
text: read_template("password_changed", "txt"),
|
|
92
|
+
variables: [
|
|
93
|
+
{
|
|
94
|
+
variable_name: "user_name",
|
|
95
|
+
variable_description: "Recipient display name",
|
|
96
|
+
default_value: "",
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
variable_name: "user_email",
|
|
100
|
+
variable_description: "Recipient email",
|
|
101
|
+
},
|
|
102
|
+
],
|
|
103
|
+
},
|
|
104
|
+
];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>Verify Your Email</title>
|
|
6
|
+
</head>
|
|
7
|
+
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
|
8
|
+
<h1 style="color: #0f172a;">Verify Your Email Address</h1>
|
|
9
|
+
<p>Thank you for registering! Please click the link below to verify your email address:</p>
|
|
10
|
+
<p style="margin: 20px 0;">
|
|
11
|
+
<a href="{{verification_url}}" style="display: inline-block; padding: 12px 24px; background-color: #0f172a; color: #ffffff; text-decoration: none; border-radius: 4px;">Verify Email Address</a>
|
|
12
|
+
</p>
|
|
13
|
+
<p>Or copy and paste this link into your browser:</p>
|
|
14
|
+
<p style="word-break: break-all; color: #666;">{{verification_url}}</p>
|
|
15
|
+
<p>This link will expire in 48 hours.</p>
|
|
16
|
+
<p style="margin-top: 30px; color: #666; font-size: 12px;">If you didn't create an account, you can safely ignore this email.</p>
|
|
17
|
+
</body>
|
|
18
|
+
</html>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>Reset Your Password</title>
|
|
6
|
+
</head>
|
|
7
|
+
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
|
8
|
+
<h1 style="color: #0f172a;">Reset Your Password</h1>
|
|
9
|
+
<p>We received a request to reset your password. Click the link below to reset it:</p>
|
|
10
|
+
<p style="margin: 20px 0;">
|
|
11
|
+
<a href="{{reset_url}}" style="display: inline-block; padding: 12px 24px; background-color: #0f172a; color: #ffffff; text-decoration: none; border-radius: 4px;">Reset Password</a>
|
|
12
|
+
</p>
|
|
13
|
+
<p>Or copy and paste this link into your browser:</p>
|
|
14
|
+
<p style="word-break: break-all; color: #666;">{{reset_url}}</p>
|
|
15
|
+
<p>This link will expire in 10 minutes.</p>
|
|
16
|
+
<p style="margin-top: 30px; color: #666; font-size: 12px;">If you didn't request a password reset, you can safely ignore this email.</p>
|
|
17
|
+
</body>
|
|
18
|
+
</html>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html>
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<title>Password Changed</title>
|
|
6
|
+
</head>
|
|
7
|
+
<body style="font-family: Arial, sans-serif; line-height: 1.6; color: #333; max-width: 600px; margin: 0 auto; padding: 20px;">
|
|
8
|
+
<h1 style="color: #0f172a;">Password Changed Successfully</h1>
|
|
9
|
+
<p>Hello {{user_name}},</p>
|
|
10
|
+
<p>This email confirms that your password has been changed successfully.</p>
|
|
11
|
+
<p>If you did not make this change, please contact support immediately to secure your account.</p>
|
|
12
|
+
<p style="margin-top: 30px; color: #666; font-size: 12px;">This is an automated notification. Please do not reply to this email.</p>
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Password Changed Successfully
|
|
2
|
+
|
|
3
|
+
Hello {{user_name}},
|
|
4
|
+
|
|
5
|
+
This email confirms that your password has been changed successfully.
|
|
6
|
+
|
|
7
|
+
If you did not make this change, please contact support immediately to secure your account.
|
|
8
|
+
|
|
9
|
+
This is an automated notification. Please do not reply to this email.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type VariantProps } from "class-variance-authority";
|
|
3
3
|
declare const buttonVariants: (props?: ({
|
|
4
|
-
variant?: "
|
|
5
|
-
size?: "default" | "
|
|
4
|
+
variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined;
|
|
5
|
+
size?: "default" | "sm" | "lg" | "icon" | null | undefined;
|
|
6
6
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
7
7
|
export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
|
|
8
8
|
asChild?: boolean;
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import "server-only";
|
|
2
2
|
import { NextRequest } from "next/server";
|
|
3
3
|
import type { HazoAuthResult, HazoAuthOptions } from "./auth_types";
|
|
4
|
+
/**
|
|
5
|
+
* Gets client IP address from request
|
|
6
|
+
* @param request - NextRequest object
|
|
7
|
+
* @returns IP address string
|
|
8
|
+
*/
|
|
9
|
+
export declare function get_client_ip(request: NextRequest): string;
|
|
4
10
|
/**
|
|
5
11
|
* Main hazo_get_auth function for server-side use in API routes
|
|
6
12
|
* Returns user details, permissions, and checks required permissions
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hazo_get_auth.server.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/hazo_get_auth.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAGrB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK1C,OAAO,KAAK,EACV,cAAc,EAEd,eAAe,EAGhB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"hazo_get_auth.server.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/hazo_get_auth.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAGrB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK1C,OAAO,KAAK,EACV,cAAc,EAEd,eAAe,EAGhB,MAAM,cAAc,CAAC;AA6CtB;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,CAU1D;AA4SD;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,cAAc,CAAC,CAmNzB"}
|
|
@@ -44,7 +44,7 @@ function parse_app_user_data(json_string) {
|
|
|
44
44
|
* @param request - NextRequest object
|
|
45
45
|
* @returns IP address string
|
|
46
46
|
*/
|
|
47
|
-
function get_client_ip(request) {
|
|
47
|
+
export function get_client_ip(request) {
|
|
48
48
|
const forwarded = request.headers.get("x-forwarded-for");
|
|
49
49
|
if (forwarded) {
|
|
50
50
|
return forwarded.split(",")[0].trim();
|
package/dist/lib/auth/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export * from "./auth_types.js";
|
|
2
|
-
export { hazo_get_auth } from "./hazo_get_auth.server.js";
|
|
2
|
+
export { hazo_get_auth, get_client_ip } from "./hazo_get_auth.server.js";
|
|
3
3
|
export { get_authenticated_user, require_auth, is_authenticated, } from "./auth_utils.server.js";
|
|
4
4
|
export type { AuthResult, AuthUser } from "./auth_utils.server";
|
|
5
5
|
export { ensure_anon_id } from "./ensure_anon_id.server.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/index.ts"],"names":[],"mappings":"AAEA,cAAc,cAAc,CAAC;AAG7B,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/index.ts"],"names":[],"mappings":"AAEA,cAAc,cAAc,CAAC;AAG7B,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACtE,OAAO,EACL,sBAAsB,EACtB,YAAY,EACZ,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGhE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAGzD,OAAO,EACL,oBAAoB,EACpB,mBAAmB,EACnB,6BAA6B,GAC9B,MAAM,+BAA+B,CAAC;AACvC,YAAY,EACV,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EACjB,gBAAgB,EAChB,wBAAwB,GACzB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,aAAa,EACb,2BAA2B,EAC3B,mBAAmB,EACnB,uBAAuB,GACxB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAGtD,OAAO,EACL,QAAQ,EACR,gBAAgB,EAChB,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,uBAAuB,EACvB,8BAA8B,EAC9B,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGhE,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/lib/auth/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// section: type_exports
|
|
3
3
|
export * from "./auth_types.js";
|
|
4
4
|
// section: server_exports
|
|
5
|
-
export { hazo_get_auth } from "./hazo_get_auth.server.js";
|
|
5
|
+
export { hazo_get_auth, get_client_ip } from "./hazo_get_auth.server.js";
|
|
6
6
|
export { get_authenticated_user, require_auth, is_authenticated, } from "./auth_utils.server.js";
|
|
7
7
|
// section: anon_id_exports (v5.2)
|
|
8
8
|
export { ensure_anon_id } from "./ensure_anon_id.server.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { EmailerConfig } from "hazo_notify";
|
|
2
|
+
import type { HazoConnectInstance } from "hazo_notify/template_manager";
|
|
2
3
|
export type EmailOptions = {
|
|
3
4
|
to: string;
|
|
4
5
|
from: string;
|
|
@@ -21,6 +22,14 @@ export type EmailTemplateData = {
|
|
|
21
22
|
* @param config - The hazo_notify emailer configuration instance
|
|
22
23
|
*/
|
|
23
24
|
export declare function set_hazo_notify_instance(config: EmailerConfig): void;
|
|
25
|
+
/**
|
|
26
|
+
* Registers the hazo_notify-compatible hazo_connect instance used by
|
|
27
|
+
* `send_template_email`. Call this from `instrumentation.ts` with the same
|
|
28
|
+
* instance you pass to `init_template_manager({ hazo_connect_factory })`.
|
|
29
|
+
*
|
|
30
|
+
* @param instance - hazo_notify-shaped database adapter
|
|
31
|
+
*/
|
|
32
|
+
export declare function set_hazo_notify_connect(instance: HazoConnectInstance): void;
|
|
24
33
|
/**
|
|
25
34
|
* Sends an email using hazo_notify
|
|
26
35
|
* @param options - Email options (to, from, subject, html_body, text_body)
|
|
@@ -31,11 +40,15 @@ export declare function send_email(options: EmailOptions): Promise<{
|
|
|
31
40
|
error?: string;
|
|
32
41
|
}>;
|
|
33
42
|
/**
|
|
34
|
-
* Sends an email using a template
|
|
35
|
-
*
|
|
43
|
+
* Sends an email using a template, delegating rendering to hazo_notify's
|
|
44
|
+
* scope-aware template manager. Templates and per-scope overrides live in
|
|
45
|
+
* hazo_notify's database; hazo_auth ships the global defaults via
|
|
46
|
+
* `hazo_auth_template_manifest`.
|
|
47
|
+
*
|
|
48
|
+
* @param template_type - System template name (email_verification | forgot_password | password_changed)
|
|
36
49
|
* @param to - Recipient email address
|
|
37
|
-
* @param data - Template data
|
|
38
|
-
* @returns Promise that resolves
|
|
50
|
+
* @param data - Template data; `token` is auto-expanded into verification_url/reset_url
|
|
51
|
+
* @returns Promise that resolves with success status
|
|
39
52
|
*/
|
|
40
53
|
export declare function send_template_email(template_type: EmailTemplateType, to: string, data: EmailTemplateData): Promise<{
|
|
41
54
|
success: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/email_service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"email_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/email_service.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAoB,MAAM,aAAa,CAAC;AACnE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAGxE,MAAM,MAAM,YAAY,GAAG;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,iBAAiB,GAAG,oBAAoB,GAAG,kBAAkB,CAAC;AAE9F,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;CACnC,CAAC;AAiBF;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAEpE;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,IAAI,CAE3E;AA8LD;;;;GAIG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAwErG;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CACvC,aAAa,EAAE,iBAAiB,EAChC,EAAE,EAAE,MAAM,EACV,IAAI,EAAE,iBAAiB,GACtB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAyF/C"}
|