diff --git a/docs/docs.go b/docs/docs.go
index 25973eb..a66077f 100644
--- a/docs/docs.go
+++ b/docs/docs.go
@@ -1522,6 +1522,58 @@ const docTemplate = `{
}
}
},
+ "/pages/bulk": {
+ "put": {
+ "description": "Update multiple pages in a single request. Each object must include \"id\". Use /pages/bulk [put].",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Pages"
+ ],
+ "summary": "Bulk update pages",
+ "parameters": [
+ {
+ "description": "Array of rol_pages update requests",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/api-service_internal_models_pages.PagesUpdateRequest"
+ }
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Updated pages",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/api-service_internal_models_pages.PagesUpdateResponse"
+ }
+ }
+ },
+ "400": {
+ "description": "Bad request or validation error",
+ "schema": {
+ "$ref": "#/definitions/api-service_internal_models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal server error",
+ "schema": {
+ "$ref": "#/definitions/api-service_internal_models.ErrorResponse"
+ }
+ }
+ }
+ }
+ },
"/pages/{id}": {
"put": {
"description": "Update an existing page",
@@ -1631,7 +1683,7 @@ const docTemplate = `{
},
"/patient": {
"get": {
- "description": "Returns a paginated list of patients with optional summary statistics",
+ "description": "Get list of patients with pagination and filters, including their attachments and payment types.",
"consumes": [
"application/json"
],
@@ -1641,7 +1693,7 @@ const docTemplate = `{
"tags": [
"Patient"
],
- "summary": "Get patient with pagination and optional aggregation",
+ "summary": "Get Patients List",
"parameters": [
{
"type": "integer",
@@ -1657,24 +1709,24 @@ const docTemplate = `{
"name": "offset",
"in": "query"
},
+ {
+ "type": "string",
+ "description": "Filter by active status (true/false)",
+ "name": "active",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "Search in medical_record_number, name, or phone_number",
+ "name": "search",
+ "in": "query"
+ },
{
"type": "boolean",
"default": false,
"description": "Include aggregation summary",
"name": "include_summary",
"in": "query"
- },
- {
- "type": "string",
- "description": "Filter by status",
- "name": "status",
- "in": "query"
- },
- {
- "type": "string",
- "description": "Search in multiple fields",
- "name": "search",
- "in": "query"
}
],
"responses": {
@@ -1697,9 +1749,11 @@ const docTemplate = `{
}
}
}
- },
+ }
+ },
+ "/patient/detail": {
"post": {
- "description": "Creates a new patient record",
+ "description": "Retrieves a single patient record by its ID, including attachments and payment types.",
"consumes": [
"application/json"
],
@@ -1709,21 +1763,21 @@ const docTemplate = `{
"tags": [
"Patient"
],
- "summary": "Create patient",
+ "summary": "Get Patient by ID",
"parameters": [
{
- "description": "Patient creation request",
+ "description": "Patient post request",
"name": "request",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/api-service_internal_models_patient.PatientCreateRequest"
+ "$ref": "#/definitions/api-service_internal_models_patient.PatientPostRequest"
}
}
],
"responses": {
- "201": {
- "description": "Patient created successfully",
+ "200": {
+ "description": "Patient details retrieved successfully",
"schema": {
"$ref": "#/definitions/api-service_internal_models_patient.PatientCreateResponse"
}
@@ -1734,107 +1788,6 @@ const docTemplate = `{
"$ref": "#/definitions/api-service_internal_models.ErrorResponse"
}
},
- "500": {
- "description": "Internal server error",
- "schema": {
- "$ref": "#/definitions/api-service_internal_models.ErrorResponse"
- }
- }
- }
- }
- },
- "/patient/{id}": {
- "put": {
- "description": "Updates an existing patient record",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "Patient"
- ],
- "summary": "Update patient",
- "parameters": [
- {
- "type": "string",
- "description": "Medical Record Number",
- "name": "id",
- "in": "path",
- "required": true
- },
- {
- "description": "Patient update request",
- "name": "request",
- "in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/api-service_internal_models_patient.PatientUpdateRequest"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Patient updated successfully",
- "schema": {
- "$ref": "#/definitions/api-service_internal_models_patient.PatientUpdateResponse"
- }
- },
- "400": {
- "description": "Bad request or validation error",
- "schema": {
- "$ref": "#/definitions/api-service_internal_models.ErrorResponse"
- }
- },
- "404": {
- "description": "Patient not found",
- "schema": {
- "$ref": "#/definitions/api-service_internal_models.ErrorResponse"
- }
- },
- "500": {
- "description": "Internal server error",
- "schema": {
- "$ref": "#/definitions/api-service_internal_models.ErrorResponse"
- }
- }
- }
- },
- "delete": {
- "description": "Soft deletes a patient by setting status to 'deleted'",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "Patient"
- ],
- "summary": "Delete patient",
- "parameters": [
- {
- "type": "string",
- "description": "Medical Record Number",
- "name": "id",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "200": {
- "description": "Patient deleted successfully",
- "schema": {
- "$ref": "#/definitions/api-service_internal_models_patient.PatientDeleteResponse"
- }
- },
- "400": {
- "description": "Invalid ID format",
- "schema": {
- "$ref": "#/definitions/api-service_internal_models.ErrorResponse"
- }
- },
"404": {
"description": "Patient not found",
"schema": {
@@ -2292,11 +2245,6 @@ const docTemplate = `{
},
"api-service_internal_models_component.ComponentUpdateRequest": {
"type": "object",
- "required": [
- "directory",
- "fk_rol_pages_id",
- "name"
- ],
"properties": {
"active": {
"type": "boolean"
@@ -2320,7 +2268,8 @@ const docTemplate = `{
"minLength": 1
},
"sort": {
- "type": "integer"
+ "type": "integer",
+ "minimum": 1
}
}
},
@@ -2381,6 +2330,71 @@ const docTemplate = `{
}
}
},
+ "api-service_internal_models_pages.ComponentCreateRequest": {
+ "type": "object",
+ "required": [
+ "directory",
+ "name"
+ ],
+ "properties": {
+ "active": {
+ "type": "boolean"
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "directory": {
+ "type": "string",
+ "maxLength": 255,
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 100,
+ "minLength": 1
+ },
+ "sort": {
+ "type": "integer"
+ }
+ }
+ },
+ "api-service_internal_models_pages.ComponentUpdateRequest": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "active": {
+ "type": "boolean"
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "directory": {
+ "type": "string",
+ "maxLength": 255,
+ "minLength": 1
+ },
+ "fk_rol_pages_id": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "id": {
+ "type": "integer"
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 100,
+ "minLength": 1
+ },
+ "sort": {
+ "type": "integer",
+ "minimum": 1
+ }
+ }
+ },
"api-service_internal_models_pages.PagesCreateRequest": {
"type": "object",
"required": [
@@ -2390,9 +2404,15 @@ const docTemplate = `{
"active": {
"type": "boolean"
},
+ "components": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/api-service_internal_models_pages.ComponentCreateRequest"
+ }
+ },
"icon": {
"type": "string",
- "maxLength": 20,
+ "maxLength": 100,
"minLength": 1
},
"id": {
@@ -2411,6 +2431,12 @@ const docTemplate = `{
"type": "integer",
"minimum": 1
},
+ "permissions": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/api-service_internal_models_pages.PermissionCreateRequest"
+ }
+ },
"sort": {
"type": "integer"
},
@@ -2468,21 +2494,29 @@ const docTemplate = `{
},
"api-service_internal_models_pages.PagesUpdateRequest": {
"type": "object",
- "required": [
- "name"
- ],
"properties": {
"active": {
"type": "boolean"
},
+ "components": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/api-service_internal_models_pages.ComponentUpdateRequest"
+ }
+ },
"icon": {
"type": "string",
- "maxLength": 20,
+ "maxLength": 100,
"minLength": 1
},
- "level": {
+ "id": {
+ "description": "used when updating via JSON array (bulk)",
"type": "integer"
},
+ "level": {
+ "type": "integer",
+ "minimum": 1
+ },
"name": {
"description": "Status string ` + "`" + `json:\"status\" validate:\"required,oneof=draft active inactive\"` + "`" + `",
"type": "string",
@@ -2493,8 +2527,15 @@ const docTemplate = `{
"type": "integer",
"minimum": 1
},
+ "permissions": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/api-service_internal_models_pages.PermissionUpdateRequest"
+ }
+ },
"sort": {
- "type": "integer"
+ "type": "integer",
+ "minimum": 1
},
"url": {
"type": "string",
@@ -2514,6 +2555,86 @@ const docTemplate = `{
}
}
},
+ "api-service_internal_models_pages.PermissionCreateRequest": {
+ "type": "object",
+ "properties": {
+ "active": {
+ "type": "boolean"
+ },
+ "create": {
+ "type": "boolean"
+ },
+ "delete": {
+ "type": "boolean"
+ },
+ "disable": {
+ "type": "boolean"
+ },
+ "group_keycloak": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "read": {
+ "type": "boolean"
+ },
+ "role_keycloak": {
+ "description": "FkRolPagesID *int64 ` + "`" + `json:\"fk_rol_pages_id\" validate:\"omitempty,\"` + "`" + `",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "update": {
+ "type": "boolean"
+ }
+ }
+ },
+ "api-service_internal_models_pages.PermissionUpdateRequest": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "active": {
+ "type": "boolean"
+ },
+ "create": {
+ "type": "boolean"
+ },
+ "delete": {
+ "type": "boolean"
+ },
+ "disable": {
+ "type": "boolean"
+ },
+ "fk_rol_pages_id": {
+ "type": "integer"
+ },
+ "group_keycloak": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "id": {
+ "type": "integer"
+ },
+ "read": {
+ "type": "boolean"
+ },
+ "role_keycloak": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "update": {
+ "type": "boolean"
+ }
+ }
+ },
"api-service_internal_models_pages.Rol_component": {
"type": "object",
"properties": {
@@ -2954,6 +3075,12 @@ const docTemplate = `{
"address": {
"$ref": "#/definitions/sql.NullString"
},
+ "attachments": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/api-service_internal_models_patient.PatientAttachment"
+ }
+ },
"birth_date": {
"$ref": "#/definitions/sql.NullTime"
},
@@ -2993,78 +3120,37 @@ const docTemplate = `{
"name": {
"$ref": "#/definitions/sql.NullString"
},
+ "payment_types": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/api-service_internal_models_patient.PatientPaymentType"
+ }
+ },
"phone_number": {
"$ref": "#/definitions/sql.NullString"
}
}
},
- "api-service_internal_models_patient.PatientCreateRequest": {
+ "api-service_internal_models_patient.PatientAttachment": {
"type": "object",
"properties": {
"active": {
- "type": "boolean"
+ "$ref": "#/definitions/sql.NullBool"
},
- "address": {
- "type": "string",
- "maxLength": 255,
- "minLength": 1
+ "directory": {
+ "$ref": "#/definitions/sql.NullString"
},
- "birth_date": {
- "type": "string"
+ "file_name": {
+ "$ref": "#/definitions/sql.NullString"
},
- "ds_sd_kabupaten_kota": {
- "type": "string",
- "maxLength": 255,
- "minLength": 1
- },
- "ds_sd_kecamatan": {
- "type": "string",
- "maxLength": 255,
- "minLength": 1
- },
- "ds_sd_kelurahan": {
- "type": "string",
- "maxLength": 255,
- "minLength": 1
- },
- "ds_sd_provinsi": {
- "type": "string",
- "maxLength": 255,
- "minLength": 1
- },
- "fk_sd_kabupaten_kota_id": {
- "type": "integer"
- },
- "fk_sd_kecamatan_id": {
- "type": "integer"
- },
- "fk_sd_kelurahan_id": {
- "type": "integer"
- },
- "fk_sd_provinsi_id": {
- "type": "integer"
- },
- "gender": {
- "type": "string",
- "maxLength": 1
+ "fk_ms_patient_id": {
+ "$ref": "#/definitions/api-service_internal_models.NullableInt32"
},
"id": {
"type": "integer"
},
- "medical_record_number": {
- "type": "string",
- "maxLength": 20,
- "minLength": 1
- },
"name": {
- "type": "string",
- "maxLength": 100,
- "minLength": 1
- },
- "phone_number": {
- "type": "string",
- "maxLength": 20,
- "minLength": 1
+ "$ref": "#/definitions/sql.NullString"
}
}
},
@@ -3079,20 +3165,6 @@ const docTemplate = `{
}
}
},
- "api-service_internal_models_patient.PatientDeleteResponse": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "medical_record_number": {
- "type": "string"
- },
- "message": {
- "type": "string"
- }
- }
- },
"api-service_internal_models_patient.PatientGetResponse": {
"type": "object",
"properties": {
@@ -3113,84 +3185,39 @@ const docTemplate = `{
}
}
},
- "api-service_internal_models_patient.PatientUpdateRequest": {
+ "api-service_internal_models_patient.PatientPaymentType": {
"type": "object",
- "required": [
- "id"
- ],
"properties": {
"active": {
- "type": "boolean"
+ "$ref": "#/definitions/sql.NullBool"
},
- "address": {
- "type": "string",
- "maxLength": 255,
- "minLength": 1
+ "fk_ms_patient_id": {
+ "$ref": "#/definitions/api-service_internal_models.NullableInt32"
},
- "birth_date": {
- "type": "string"
- },
- "ds_sd_kabupaten_kota": {
- "type": "string",
- "maxLength": 255
- },
- "ds_sd_kecamatan": {
- "type": "string",
- "maxLength": 255
- },
- "ds_sd_kelurahan": {
- "type": "string",
- "maxLength": 255
- },
- "ds_sd_provinsi": {
- "type": "string",
- "maxLength": 255
- },
- "fk_sd_kabupaten_kota_id": {
- "type": "integer"
- },
- "fk_sd_kecamatan_id": {
- "type": "integer"
- },
- "fk_sd_kelurahan_id": {
- "type": "integer"
- },
- "fk_sd_provinsi_id": {
- "type": "integer"
- },
- "gender": {
- "type": "string",
- "maxLength": 1
+ "fk_ref_payment_type": {
+ "$ref": "#/definitions/api-service_internal_models.NullableInt32"
},
"id": {
- "type": "integer",
- "minimum": 1
- },
- "medical_record_number": {
- "type": "string",
- "maxLength": 20,
- "minLength": 1
+ "type": "integer"
},
"name": {
- "type": "string",
- "maxLength": 100,
- "minLength": 1
+ "$ref": "#/definitions/sql.NullString"
},
- "phone_number": {
- "type": "string",
- "maxLength": 20,
- "minLength": 1
+ "number": {
+ "$ref": "#/definitions/sql.NullString"
}
}
},
- "api-service_internal_models_patient.PatientUpdateResponse": {
+ "api-service_internal_models_patient.PatientPostRequest": {
"type": "object",
+ "required": [
+ "medical_record_number"
+ ],
"properties": {
- "data": {
- "$ref": "#/definitions/api-service_internal_models_patient.Patient"
- },
- "message": {
- "type": "string"
+ "medical_record_number": {
+ "description": "ID int64 ` + "`" + `json:\"id\" validate:\"required,min=1\"` + "`" + `",
+ "type": "string",
+ "minLength": 1
}
}
},
diff --git a/docs/swagger.json b/docs/swagger.json
index c62739c..002aa82 100644
--- a/docs/swagger.json
+++ b/docs/swagger.json
@@ -1520,6 +1520,58 @@
}
}
},
+ "/pages/bulk": {
+ "put": {
+ "description": "Update multiple pages in a single request. Each object must include \"id\". Use /pages/bulk [put].",
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "tags": [
+ "Pages"
+ ],
+ "summary": "Bulk update pages",
+ "parameters": [
+ {
+ "description": "Array of rol_pages update requests",
+ "name": "request",
+ "in": "body",
+ "required": true,
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/api-service_internal_models_pages.PagesUpdateRequest"
+ }
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Updated pages",
+ "schema": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/api-service_internal_models_pages.PagesUpdateResponse"
+ }
+ }
+ },
+ "400": {
+ "description": "Bad request or validation error",
+ "schema": {
+ "$ref": "#/definitions/api-service_internal_models.ErrorResponse"
+ }
+ },
+ "500": {
+ "description": "Internal server error",
+ "schema": {
+ "$ref": "#/definitions/api-service_internal_models.ErrorResponse"
+ }
+ }
+ }
+ }
+ },
"/pages/{id}": {
"put": {
"description": "Update an existing page",
@@ -1629,7 +1681,7 @@
},
"/patient": {
"get": {
- "description": "Returns a paginated list of patients with optional summary statistics",
+ "description": "Get list of patients with pagination and filters, including their attachments and payment types.",
"consumes": [
"application/json"
],
@@ -1639,7 +1691,7 @@
"tags": [
"Patient"
],
- "summary": "Get patient with pagination and optional aggregation",
+ "summary": "Get Patients List",
"parameters": [
{
"type": "integer",
@@ -1655,24 +1707,24 @@
"name": "offset",
"in": "query"
},
+ {
+ "type": "string",
+ "description": "Filter by active status (true/false)",
+ "name": "active",
+ "in": "query"
+ },
+ {
+ "type": "string",
+ "description": "Search in medical_record_number, name, or phone_number",
+ "name": "search",
+ "in": "query"
+ },
{
"type": "boolean",
"default": false,
"description": "Include aggregation summary",
"name": "include_summary",
"in": "query"
- },
- {
- "type": "string",
- "description": "Filter by status",
- "name": "status",
- "in": "query"
- },
- {
- "type": "string",
- "description": "Search in multiple fields",
- "name": "search",
- "in": "query"
}
],
"responses": {
@@ -1695,9 +1747,11 @@
}
}
}
- },
+ }
+ },
+ "/patient/detail": {
"post": {
- "description": "Creates a new patient record",
+ "description": "Retrieves a single patient record by its ID, including attachments and payment types.",
"consumes": [
"application/json"
],
@@ -1707,21 +1761,21 @@
"tags": [
"Patient"
],
- "summary": "Create patient",
+ "summary": "Get Patient by ID",
"parameters": [
{
- "description": "Patient creation request",
+ "description": "Patient post request",
"name": "request",
"in": "body",
"required": true,
"schema": {
- "$ref": "#/definitions/api-service_internal_models_patient.PatientCreateRequest"
+ "$ref": "#/definitions/api-service_internal_models_patient.PatientPostRequest"
}
}
],
"responses": {
- "201": {
- "description": "Patient created successfully",
+ "200": {
+ "description": "Patient details retrieved successfully",
"schema": {
"$ref": "#/definitions/api-service_internal_models_patient.PatientCreateResponse"
}
@@ -1732,107 +1786,6 @@
"$ref": "#/definitions/api-service_internal_models.ErrorResponse"
}
},
- "500": {
- "description": "Internal server error",
- "schema": {
- "$ref": "#/definitions/api-service_internal_models.ErrorResponse"
- }
- }
- }
- }
- },
- "/patient/{id}": {
- "put": {
- "description": "Updates an existing patient record",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "Patient"
- ],
- "summary": "Update patient",
- "parameters": [
- {
- "type": "string",
- "description": "Medical Record Number",
- "name": "id",
- "in": "path",
- "required": true
- },
- {
- "description": "Patient update request",
- "name": "request",
- "in": "body",
- "required": true,
- "schema": {
- "$ref": "#/definitions/api-service_internal_models_patient.PatientUpdateRequest"
- }
- }
- ],
- "responses": {
- "200": {
- "description": "Patient updated successfully",
- "schema": {
- "$ref": "#/definitions/api-service_internal_models_patient.PatientUpdateResponse"
- }
- },
- "400": {
- "description": "Bad request or validation error",
- "schema": {
- "$ref": "#/definitions/api-service_internal_models.ErrorResponse"
- }
- },
- "404": {
- "description": "Patient not found",
- "schema": {
- "$ref": "#/definitions/api-service_internal_models.ErrorResponse"
- }
- },
- "500": {
- "description": "Internal server error",
- "schema": {
- "$ref": "#/definitions/api-service_internal_models.ErrorResponse"
- }
- }
- }
- },
- "delete": {
- "description": "Soft deletes a patient by setting status to 'deleted'",
- "consumes": [
- "application/json"
- ],
- "produces": [
- "application/json"
- ],
- "tags": [
- "Patient"
- ],
- "summary": "Delete patient",
- "parameters": [
- {
- "type": "string",
- "description": "Medical Record Number",
- "name": "id",
- "in": "path",
- "required": true
- }
- ],
- "responses": {
- "200": {
- "description": "Patient deleted successfully",
- "schema": {
- "$ref": "#/definitions/api-service_internal_models_patient.PatientDeleteResponse"
- }
- },
- "400": {
- "description": "Invalid ID format",
- "schema": {
- "$ref": "#/definitions/api-service_internal_models.ErrorResponse"
- }
- },
"404": {
"description": "Patient not found",
"schema": {
@@ -2290,11 +2243,6 @@
},
"api-service_internal_models_component.ComponentUpdateRequest": {
"type": "object",
- "required": [
- "directory",
- "fk_rol_pages_id",
- "name"
- ],
"properties": {
"active": {
"type": "boolean"
@@ -2318,7 +2266,8 @@
"minLength": 1
},
"sort": {
- "type": "integer"
+ "type": "integer",
+ "minimum": 1
}
}
},
@@ -2379,6 +2328,71 @@
}
}
},
+ "api-service_internal_models_pages.ComponentCreateRequest": {
+ "type": "object",
+ "required": [
+ "directory",
+ "name"
+ ],
+ "properties": {
+ "active": {
+ "type": "boolean"
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "directory": {
+ "type": "string",
+ "maxLength": 255,
+ "minLength": 1
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 100,
+ "minLength": 1
+ },
+ "sort": {
+ "type": "integer"
+ }
+ }
+ },
+ "api-service_internal_models_pages.ComponentUpdateRequest": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "active": {
+ "type": "boolean"
+ },
+ "description": {
+ "type": "string",
+ "maxLength": 255
+ },
+ "directory": {
+ "type": "string",
+ "maxLength": 255,
+ "minLength": 1
+ },
+ "fk_rol_pages_id": {
+ "type": "integer",
+ "minimum": 1
+ },
+ "id": {
+ "type": "integer"
+ },
+ "name": {
+ "type": "string",
+ "maxLength": 100,
+ "minLength": 1
+ },
+ "sort": {
+ "type": "integer",
+ "minimum": 1
+ }
+ }
+ },
"api-service_internal_models_pages.PagesCreateRequest": {
"type": "object",
"required": [
@@ -2388,9 +2402,15 @@
"active": {
"type": "boolean"
},
+ "components": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/api-service_internal_models_pages.ComponentCreateRequest"
+ }
+ },
"icon": {
"type": "string",
- "maxLength": 20,
+ "maxLength": 100,
"minLength": 1
},
"id": {
@@ -2409,6 +2429,12 @@
"type": "integer",
"minimum": 1
},
+ "permissions": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/api-service_internal_models_pages.PermissionCreateRequest"
+ }
+ },
"sort": {
"type": "integer"
},
@@ -2466,21 +2492,29 @@
},
"api-service_internal_models_pages.PagesUpdateRequest": {
"type": "object",
- "required": [
- "name"
- ],
"properties": {
"active": {
"type": "boolean"
},
+ "components": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/api-service_internal_models_pages.ComponentUpdateRequest"
+ }
+ },
"icon": {
"type": "string",
- "maxLength": 20,
+ "maxLength": 100,
"minLength": 1
},
- "level": {
+ "id": {
+ "description": "used when updating via JSON array (bulk)",
"type": "integer"
},
+ "level": {
+ "type": "integer",
+ "minimum": 1
+ },
"name": {
"description": "Status string `json:\"status\" validate:\"required,oneof=draft active inactive\"`",
"type": "string",
@@ -2491,8 +2525,15 @@
"type": "integer",
"minimum": 1
},
+ "permissions": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/api-service_internal_models_pages.PermissionUpdateRequest"
+ }
+ },
"sort": {
- "type": "integer"
+ "type": "integer",
+ "minimum": 1
},
"url": {
"type": "string",
@@ -2512,6 +2553,86 @@
}
}
},
+ "api-service_internal_models_pages.PermissionCreateRequest": {
+ "type": "object",
+ "properties": {
+ "active": {
+ "type": "boolean"
+ },
+ "create": {
+ "type": "boolean"
+ },
+ "delete": {
+ "type": "boolean"
+ },
+ "disable": {
+ "type": "boolean"
+ },
+ "group_keycloak": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "read": {
+ "type": "boolean"
+ },
+ "role_keycloak": {
+ "description": "FkRolPagesID *int64 `json:\"fk_rol_pages_id\" validate:\"omitempty,\"`",
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "update": {
+ "type": "boolean"
+ }
+ }
+ },
+ "api-service_internal_models_pages.PermissionUpdateRequest": {
+ "type": "object",
+ "required": [
+ "id"
+ ],
+ "properties": {
+ "active": {
+ "type": "boolean"
+ },
+ "create": {
+ "type": "boolean"
+ },
+ "delete": {
+ "type": "boolean"
+ },
+ "disable": {
+ "type": "boolean"
+ },
+ "fk_rol_pages_id": {
+ "type": "integer"
+ },
+ "group_keycloak": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "id": {
+ "type": "integer"
+ },
+ "read": {
+ "type": "boolean"
+ },
+ "role_keycloak": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "update": {
+ "type": "boolean"
+ }
+ }
+ },
"api-service_internal_models_pages.Rol_component": {
"type": "object",
"properties": {
@@ -2952,6 +3073,12 @@
"address": {
"$ref": "#/definitions/sql.NullString"
},
+ "attachments": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/api-service_internal_models_patient.PatientAttachment"
+ }
+ },
"birth_date": {
"$ref": "#/definitions/sql.NullTime"
},
@@ -2991,78 +3118,37 @@
"name": {
"$ref": "#/definitions/sql.NullString"
},
+ "payment_types": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/api-service_internal_models_patient.PatientPaymentType"
+ }
+ },
"phone_number": {
"$ref": "#/definitions/sql.NullString"
}
}
},
- "api-service_internal_models_patient.PatientCreateRequest": {
+ "api-service_internal_models_patient.PatientAttachment": {
"type": "object",
"properties": {
"active": {
- "type": "boolean"
+ "$ref": "#/definitions/sql.NullBool"
},
- "address": {
- "type": "string",
- "maxLength": 255,
- "minLength": 1
+ "directory": {
+ "$ref": "#/definitions/sql.NullString"
},
- "birth_date": {
- "type": "string"
+ "file_name": {
+ "$ref": "#/definitions/sql.NullString"
},
- "ds_sd_kabupaten_kota": {
- "type": "string",
- "maxLength": 255,
- "minLength": 1
- },
- "ds_sd_kecamatan": {
- "type": "string",
- "maxLength": 255,
- "minLength": 1
- },
- "ds_sd_kelurahan": {
- "type": "string",
- "maxLength": 255,
- "minLength": 1
- },
- "ds_sd_provinsi": {
- "type": "string",
- "maxLength": 255,
- "minLength": 1
- },
- "fk_sd_kabupaten_kota_id": {
- "type": "integer"
- },
- "fk_sd_kecamatan_id": {
- "type": "integer"
- },
- "fk_sd_kelurahan_id": {
- "type": "integer"
- },
- "fk_sd_provinsi_id": {
- "type": "integer"
- },
- "gender": {
- "type": "string",
- "maxLength": 1
+ "fk_ms_patient_id": {
+ "$ref": "#/definitions/api-service_internal_models.NullableInt32"
},
"id": {
"type": "integer"
},
- "medical_record_number": {
- "type": "string",
- "maxLength": 20,
- "minLength": 1
- },
"name": {
- "type": "string",
- "maxLength": 100,
- "minLength": 1
- },
- "phone_number": {
- "type": "string",
- "maxLength": 20,
- "minLength": 1
+ "$ref": "#/definitions/sql.NullString"
}
}
},
@@ -3077,20 +3163,6 @@
}
}
},
- "api-service_internal_models_patient.PatientDeleteResponse": {
- "type": "object",
- "properties": {
- "id": {
- "type": "string"
- },
- "medical_record_number": {
- "type": "string"
- },
- "message": {
- "type": "string"
- }
- }
- },
"api-service_internal_models_patient.PatientGetResponse": {
"type": "object",
"properties": {
@@ -3111,84 +3183,39 @@
}
}
},
- "api-service_internal_models_patient.PatientUpdateRequest": {
+ "api-service_internal_models_patient.PatientPaymentType": {
"type": "object",
- "required": [
- "id"
- ],
"properties": {
"active": {
- "type": "boolean"
+ "$ref": "#/definitions/sql.NullBool"
},
- "address": {
- "type": "string",
- "maxLength": 255,
- "minLength": 1
+ "fk_ms_patient_id": {
+ "$ref": "#/definitions/api-service_internal_models.NullableInt32"
},
- "birth_date": {
- "type": "string"
- },
- "ds_sd_kabupaten_kota": {
- "type": "string",
- "maxLength": 255
- },
- "ds_sd_kecamatan": {
- "type": "string",
- "maxLength": 255
- },
- "ds_sd_kelurahan": {
- "type": "string",
- "maxLength": 255
- },
- "ds_sd_provinsi": {
- "type": "string",
- "maxLength": 255
- },
- "fk_sd_kabupaten_kota_id": {
- "type": "integer"
- },
- "fk_sd_kecamatan_id": {
- "type": "integer"
- },
- "fk_sd_kelurahan_id": {
- "type": "integer"
- },
- "fk_sd_provinsi_id": {
- "type": "integer"
- },
- "gender": {
- "type": "string",
- "maxLength": 1
+ "fk_ref_payment_type": {
+ "$ref": "#/definitions/api-service_internal_models.NullableInt32"
},
"id": {
- "type": "integer",
- "minimum": 1
- },
- "medical_record_number": {
- "type": "string",
- "maxLength": 20,
- "minLength": 1
+ "type": "integer"
},
"name": {
- "type": "string",
- "maxLength": 100,
- "minLength": 1
+ "$ref": "#/definitions/sql.NullString"
},
- "phone_number": {
- "type": "string",
- "maxLength": 20,
- "minLength": 1
+ "number": {
+ "$ref": "#/definitions/sql.NullString"
}
}
},
- "api-service_internal_models_patient.PatientUpdateResponse": {
+ "api-service_internal_models_patient.PatientPostRequest": {
"type": "object",
+ "required": [
+ "medical_record_number"
+ ],
"properties": {
- "data": {
- "$ref": "#/definitions/api-service_internal_models_patient.Patient"
- },
- "message": {
- "type": "string"
+ "medical_record_number": {
+ "description": "ID int64 `json:\"id\" validate:\"required,min=1\"`",
+ "type": "string",
+ "minLength": 1
}
}
},
diff --git a/docs/swagger.yaml b/docs/swagger.yaml
index 58b8dba..0ef4691 100644
--- a/docs/swagger.yaml
+++ b/docs/swagger.yaml
@@ -168,11 +168,8 @@ definitions:
minLength: 1
type: string
sort:
+ minimum: 1
type: integer
- required:
- - directory
- - fk_rol_pages_id
- - name
type: object
api-service_internal_models_component.ComponentUpdateResponse:
properties:
@@ -211,12 +208,63 @@ definitions:
sort:
type: integer
type: object
+ api-service_internal_models_pages.ComponentCreateRequest:
+ properties:
+ active:
+ type: boolean
+ description:
+ maxLength: 255
+ type: string
+ directory:
+ maxLength: 255
+ minLength: 1
+ type: string
+ name:
+ maxLength: 100
+ minLength: 1
+ type: string
+ sort:
+ type: integer
+ required:
+ - directory
+ - name
+ type: object
+ api-service_internal_models_pages.ComponentUpdateRequest:
+ properties:
+ active:
+ type: boolean
+ description:
+ maxLength: 255
+ type: string
+ directory:
+ maxLength: 255
+ minLength: 1
+ type: string
+ fk_rol_pages_id:
+ minimum: 1
+ type: integer
+ id:
+ type: integer
+ name:
+ maxLength: 100
+ minLength: 1
+ type: string
+ sort:
+ minimum: 1
+ type: integer
+ required:
+ - id
+ type: object
api-service_internal_models_pages.PagesCreateRequest:
properties:
active:
type: boolean
+ components:
+ items:
+ $ref: '#/definitions/api-service_internal_models_pages.ComponentCreateRequest'
+ type: array
icon:
- maxLength: 20
+ maxLength: 100
minLength: 1
type: string
id:
@@ -232,6 +280,10 @@ definitions:
parent:
minimum: 1
type: integer
+ permissions:
+ items:
+ $ref: '#/definitions/api-service_internal_models_pages.PermissionCreateRequest'
+ type: array
sort:
type: integer
url:
@@ -274,11 +326,19 @@ definitions:
properties:
active:
type: boolean
+ components:
+ items:
+ $ref: '#/definitions/api-service_internal_models_pages.ComponentUpdateRequest'
+ type: array
icon:
- maxLength: 20
+ maxLength: 100
minLength: 1
type: string
+ id:
+ description: used when updating via JSON array (bulk)
+ type: integer
level:
+ minimum: 1
type: integer
name:
description: Status string `json:"status" validate:"required,oneof=draft
@@ -289,14 +349,17 @@ definitions:
parent:
minimum: 1
type: integer
+ permissions:
+ items:
+ $ref: '#/definitions/api-service_internal_models_pages.PermissionUpdateRequest'
+ type: array
sort:
+ minimum: 1
type: integer
url:
maxLength: 100
minLength: 1
type: string
- required:
- - name
type: object
api-service_internal_models_pages.PagesUpdateResponse:
properties:
@@ -305,6 +368,59 @@ definitions:
message:
type: string
type: object
+ api-service_internal_models_pages.PermissionCreateRequest:
+ properties:
+ active:
+ type: boolean
+ create:
+ type: boolean
+ delete:
+ type: boolean
+ disable:
+ type: boolean
+ group_keycloak:
+ items:
+ type: string
+ type: array
+ read:
+ type: boolean
+ role_keycloak:
+ description: FkRolPagesID *int64 `json:"fk_rol_pages_id" validate:"omitempty,"`
+ items:
+ type: string
+ type: array
+ update:
+ type: boolean
+ type: object
+ api-service_internal_models_pages.PermissionUpdateRequest:
+ properties:
+ active:
+ type: boolean
+ create:
+ type: boolean
+ delete:
+ type: boolean
+ disable:
+ type: boolean
+ fk_rol_pages_id:
+ type: integer
+ group_keycloak:
+ items:
+ type: string
+ type: array
+ id:
+ type: integer
+ read:
+ type: boolean
+ role_keycloak:
+ items:
+ type: string
+ type: array
+ update:
+ type: boolean
+ required:
+ - id
+ type: object
api-service_internal_models_pages.Rol_component:
properties:
active:
@@ -600,6 +716,10 @@ definitions:
$ref: '#/definitions/sql.NullBool'
address:
$ref: '#/definitions/sql.NullString'
+ attachments:
+ items:
+ $ref: '#/definitions/api-service_internal_models_patient.PatientAttachment'
+ type: array
birth_date:
$ref: '#/definitions/sql.NullTime'
ds_sd_kabupaten_kota:
@@ -626,60 +746,27 @@ definitions:
$ref: '#/definitions/sql.NullString'
name:
$ref: '#/definitions/sql.NullString'
+ payment_types:
+ items:
+ $ref: '#/definitions/api-service_internal_models_patient.PatientPaymentType'
+ type: array
phone_number:
$ref: '#/definitions/sql.NullString'
type: object
- api-service_internal_models_patient.PatientCreateRequest:
+ api-service_internal_models_patient.PatientAttachment:
properties:
active:
- type: boolean
- address:
- maxLength: 255
- minLength: 1
- type: string
- birth_date:
- type: string
- ds_sd_kabupaten_kota:
- maxLength: 255
- minLength: 1
- type: string
- ds_sd_kecamatan:
- maxLength: 255
- minLength: 1
- type: string
- ds_sd_kelurahan:
- maxLength: 255
- minLength: 1
- type: string
- ds_sd_provinsi:
- maxLength: 255
- minLength: 1
- type: string
- fk_sd_kabupaten_kota_id:
- type: integer
- fk_sd_kecamatan_id:
- type: integer
- fk_sd_kelurahan_id:
- type: integer
- fk_sd_provinsi_id:
- type: integer
- gender:
- maxLength: 1
- type: string
+ $ref: '#/definitions/sql.NullBool'
+ directory:
+ $ref: '#/definitions/sql.NullString'
+ file_name:
+ $ref: '#/definitions/sql.NullString'
+ fk_ms_patient_id:
+ $ref: '#/definitions/api-service_internal_models.NullableInt32'
id:
type: integer
- medical_record_number:
- maxLength: 20
- minLength: 1
- type: string
name:
- maxLength: 100
- minLength: 1
- type: string
- phone_number:
- maxLength: 20
- minLength: 1
- type: string
+ $ref: '#/definitions/sql.NullString'
type: object
api-service_internal_models_patient.PatientCreateResponse:
properties:
@@ -688,15 +775,6 @@ definitions:
message:
type: string
type: object
- api-service_internal_models_patient.PatientDeleteResponse:
- properties:
- id:
- type: string
- medical_record_number:
- type: string
- message:
- type: string
- type: object
api-service_internal_models_patient.PatientGetResponse:
properties:
data:
@@ -710,63 +788,29 @@ definitions:
summary:
$ref: '#/definitions/api-service_internal_models.AggregateData'
type: object
- api-service_internal_models_patient.PatientUpdateRequest:
+ api-service_internal_models_patient.PatientPaymentType:
properties:
active:
- type: boolean
- address:
- maxLength: 255
- minLength: 1
- type: string
- birth_date:
- type: string
- ds_sd_kabupaten_kota:
- maxLength: 255
- type: string
- ds_sd_kecamatan:
- maxLength: 255
- type: string
- ds_sd_kelurahan:
- maxLength: 255
- type: string
- ds_sd_provinsi:
- maxLength: 255
- type: string
- fk_sd_kabupaten_kota_id:
- type: integer
- fk_sd_kecamatan_id:
- type: integer
- fk_sd_kelurahan_id:
- type: integer
- fk_sd_provinsi_id:
- type: integer
- gender:
- maxLength: 1
- type: string
+ $ref: '#/definitions/sql.NullBool'
+ fk_ms_patient_id:
+ $ref: '#/definitions/api-service_internal_models.NullableInt32'
+ fk_ref_payment_type:
+ $ref: '#/definitions/api-service_internal_models.NullableInt32'
id:
- minimum: 1
type: integer
- medical_record_number:
- maxLength: 20
- minLength: 1
- type: string
name:
- maxLength: 100
- minLength: 1
- type: string
- phone_number:
- maxLength: 20
+ $ref: '#/definitions/sql.NullString'
+ number:
+ $ref: '#/definitions/sql.NullString'
+ type: object
+ api-service_internal_models_patient.PatientPostRequest:
+ properties:
+ medical_record_number:
+ description: ID int64 `json:"id" validate:"required,min=1"`
minLength: 1
type: string
required:
- - id
- type: object
- api-service_internal_models_patient.PatientUpdateResponse:
- properties:
- data:
- $ref: '#/definitions/api-service_internal_models_patient.Patient'
- message:
- type: string
+ - medical_record_number
type: object
api-service_internal_models_permission.PermissionCreateRequest:
properties:
@@ -2200,11 +2244,47 @@ paths:
summary: Update Page
tags:
- Pages
+ /pages/bulk:
+ put:
+ consumes:
+ - application/json
+ description: Update multiple pages in a single request. Each object must include
+ "id". Use /pages/bulk [put].
+ parameters:
+ - description: Array of rol_pages update requests
+ in: body
+ name: request
+ required: true
+ schema:
+ items:
+ $ref: '#/definitions/api-service_internal_models_pages.PagesUpdateRequest'
+ type: array
+ produces:
+ - application/json
+ responses:
+ "200":
+ description: Updated pages
+ schema:
+ items:
+ $ref: '#/definitions/api-service_internal_models_pages.PagesUpdateResponse'
+ type: array
+ "400":
+ description: Bad request or validation error
+ schema:
+ $ref: '#/definitions/api-service_internal_models.ErrorResponse'
+ "500":
+ description: Internal server error
+ schema:
+ $ref: '#/definitions/api-service_internal_models.ErrorResponse'
+ summary: Bulk update pages
+ tags:
+ - Pages
/patient:
get:
consumes:
- application/json
- description: Returns a paginated list of patients with optional summary statistics
+ description: Get list of patients with pagination and filters, including their
+ attachments and payment types.
parameters:
- default: 10
description: Limit (max 100)
@@ -2216,19 +2296,19 @@ paths:
in: query
name: offset
type: integer
+ - description: Filter by active status (true/false)
+ in: query
+ name: active
+ type: string
+ - description: Search in medical_record_number, name, or phone_number
+ in: query
+ name: search
+ type: string
- default: false
description: Include aggregation summary
in: query
name: include_summary
type: boolean
- - description: Filter by status
- in: query
- name: status
- type: string
- - description: Search in multiple fields
- in: query
- name: search
- type: string
produces:
- application/json
responses:
@@ -2244,60 +2324,33 @@ paths:
description: Internal server error
schema:
$ref: '#/definitions/api-service_internal_models.ErrorResponse'
- summary: Get patient with pagination and optional aggregation
+ summary: Get Patients List
tags:
- Patient
+ /patient/detail:
post:
consumes:
- application/json
- description: Creates a new patient record
+ description: Retrieves a single patient record by its ID, including attachments
+ and payment types.
parameters:
- - description: Patient creation request
+ - description: Patient post request
in: body
name: request
required: true
schema:
- $ref: '#/definitions/api-service_internal_models_patient.PatientCreateRequest'
+ $ref: '#/definitions/api-service_internal_models_patient.PatientPostRequest'
produces:
- application/json
responses:
- "201":
- description: Patient created successfully
+ "200":
+ description: Patient details retrieved successfully
schema:
$ref: '#/definitions/api-service_internal_models_patient.PatientCreateResponse'
"400":
description: Bad request or validation error
schema:
$ref: '#/definitions/api-service_internal_models.ErrorResponse'
- "500":
- description: Internal server error
- schema:
- $ref: '#/definitions/api-service_internal_models.ErrorResponse'
- summary: Create patient
- tags:
- - Patient
- /patient/{id}:
- delete:
- consumes:
- - application/json
- description: Soft deletes a patient by setting status to 'deleted'
- parameters:
- - description: Medical Record Number
- in: path
- name: id
- required: true
- type: string
- produces:
- - application/json
- responses:
- "200":
- description: Patient deleted successfully
- schema:
- $ref: '#/definitions/api-service_internal_models_patient.PatientDeleteResponse'
- "400":
- description: Invalid ID format
- schema:
- $ref: '#/definitions/api-service_internal_models.ErrorResponse'
"404":
description: Patient not found
schema:
@@ -2306,45 +2359,7 @@ paths:
description: Internal server error
schema:
$ref: '#/definitions/api-service_internal_models.ErrorResponse'
- summary: Delete patient
- tags:
- - Patient
- put:
- consumes:
- - application/json
- description: Updates an existing patient record
- parameters:
- - description: Medical Record Number
- in: path
- name: id
- required: true
- type: string
- - description: Patient update request
- in: body
- name: request
- required: true
- schema:
- $ref: '#/definitions/api-service_internal_models_patient.PatientUpdateRequest'
- produces:
- - application/json
- responses:
- "200":
- description: Patient updated successfully
- schema:
- $ref: '#/definitions/api-service_internal_models_patient.PatientUpdateResponse'
- "400":
- description: Bad request or validation error
- schema:
- $ref: '#/definitions/api-service_internal_models.ErrorResponse'
- "404":
- description: Patient not found
- schema:
- $ref: '#/definitions/api-service_internal_models.ErrorResponse'
- "500":
- description: Internal server error
- schema:
- $ref: '#/definitions/api-service_internal_models.ErrorResponse'
- summary: Update patient
+ summary: Get Patient by ID
tags:
- Patient
/permission:
diff --git a/examples/clientsocket/.gitignore b/examples/clientsocket/.gitignore
new file mode 100644
index 0000000..4a7f73a
--- /dev/null
+++ b/examples/clientsocket/.gitignore
@@ -0,0 +1,24 @@
+# Nuxt dev/build outputs
+.output
+.data
+.nuxt
+.nitro
+.cache
+dist
+
+# Node dependencies
+node_modules
+
+# Logs
+logs
+*.log
+
+# Misc
+.DS_Store
+.fleet
+.idea
+
+# Local env files
+.env
+.env.*
+!.env.example
diff --git a/examples/clientsocket/README.md b/examples/clientsocket/README.md
new file mode 100644
index 0000000..25b5821
--- /dev/null
+++ b/examples/clientsocket/README.md
@@ -0,0 +1,75 @@
+# Nuxt Minimal Starter
+
+Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
+
+## Setup
+
+Make sure to install dependencies:
+
+```bash
+# npm
+npm install
+
+# pnpm
+pnpm install
+
+# yarn
+yarn install
+
+# bun
+bun install
+```
+
+## Development Server
+
+Start the development server on `http://localhost:3000`:
+
+```bash
+# npm
+npm run dev
+
+# pnpm
+pnpm dev
+
+# yarn
+yarn dev
+
+# bun
+bun run dev
+```
+
+## Production
+
+Build the application for production:
+
+```bash
+# npm
+npm run build
+
+# pnpm
+pnpm build
+
+# yarn
+yarn build
+
+# bun
+bun run build
+```
+
+Locally preview production build:
+
+```bash
+# npm
+npm run preview
+
+# pnpm
+pnpm preview
+
+# yarn
+yarn preview
+
+# bun
+bun run preview
+```
+
+Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
diff --git a/examples/clientsocket/app/app.vue b/examples/clientsocket/app/app.vue
new file mode 100644
index 0000000..09f935b
--- /dev/null
+++ b/examples/clientsocket/app/app.vue
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/examples/clientsocket/assets/css/main.css b/examples/clientsocket/assets/css/main.css
new file mode 100644
index 0000000..e3c5807
--- /dev/null
+++ b/examples/clientsocket/assets/css/main.css
@@ -0,0 +1,672 @@
+/* Enhanced WebSocket Client Styles */
+* {
+ box-sizing: border-box;
+}
+
+body {
+ font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
+ margin: 0;
+ padding: 20px;
+ background-color: #f5f5f5;
+ color: #333;
+}
+
+.container {
+ max-width: 1400px;
+ margin: 0 auto;
+ background: white;
+ border-radius: 12px;
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
+ padding: 24px;
+ overflow: hidden;
+}
+
+h1 {
+ color: #333;
+ text-align: center;
+ margin-bottom: 32px;
+ font-weight: 600;
+}
+
+.status-bar {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+ gap: 16px;
+ padding: 20px;
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+ color: white;
+ border-radius: 12px;
+ margin-bottom: 24px;
+}
+
+.status-item {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ font-weight: 500;
+}
+
+.status-indicator {
+ width: 12px;
+ height: 12px;
+ border-radius: 50%;
+ display: inline-block;
+}
+
+.status-connected {
+ background: #4CAF50;
+ box-shadow: 0 0 8px rgba(76, 175, 80, 0.6);
+}
+
+.status-connecting {
+ background: #FFC107;
+ animation: pulse 1.5s infinite;
+}
+
+.status-disconnected {
+ background: #F44336;
+}
+
+@keyframes pulse {
+ 0% { opacity: 1; }
+ 50% { opacity: 0.5; }
+ 100% { opacity: 1; }
+}
+
+.health-indicator {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 8px 12px;
+ border-radius: 6px;
+ font-size: 12px;
+ font-weight: bold;
+}
+
+.health-excellent {
+ background: #d4edda;
+ color: #155724;
+}
+
+.health-good {
+ background: #d1ecf1;
+ color: #0c5460;
+}
+
+.health-warning {
+ background: #fff3cd;
+ color: #856404;
+}
+
+.health-poor {
+ background: #f8d7da;
+ color: #721c24;
+}
+
+.tabs {
+ display: flex;
+ border-bottom: 2px solid #e9ecef;
+ margin-bottom: 24px;
+ overflow-x: auto;
+ background: white;
+ border-radius: 8px 8px 0 0;
+}
+
+.tab {
+ padding: 16px 24px;
+ background: transparent;
+ border: none;
+ border-bottom: 3px solid transparent;
+ cursor: pointer;
+ white-space: nowrap;
+ transition: all 0.3s ease;
+ font-weight: 500;
+ color: #666;
+}
+
+.tab:hover {
+ background: #f8f9fa;
+ color: #333;
+}
+
+.tab.active {
+ border-bottom-color: #1976d2;
+ color: #1976d2;
+ font-weight: 600;
+ background: #f8f9fa;
+}
+
+.tab-content {
+ display: none;
+ animation: fadeIn 0.3s ease;
+}
+
+.tab-content.active {
+ display: block;
+}
+
+@keyframes fadeIn {
+ from { opacity: 0; transform: translateY(10px); }
+ to { opacity: 1; transform: translateY(0); }
+}
+
+.controls {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
+ gap: 20px;
+ margin-bottom: 24px;
+ padding: 24px;
+ background: #f8f9fa;
+ border-radius: 8px;
+}
+
+.input-group {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+}
+
+.input-group label {
+ font-weight: 600;
+ color: #333;
+ margin-bottom: 8px;
+}
+
+.input-group input,
+.input-group select,
+.input-group textarea {
+ padding: 12px 16px;
+ border: 2px solid #e9ecef;
+ border-radius: 6px;
+ font-size: 14px;
+ transition: border-color 0.3s ease;
+}
+
+.input-group input:focus,
+.input-group select:focus,
+.input-group textarea:focus {
+ outline: none;
+ border-color: #1976d2;
+ box-shadow: 0 0 0 3px rgba(25, 118, 210, 0.1);
+}
+
+.checkbox-group {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ margin: 8px 0;
+}
+
+.checkbox-group input[type="checkbox"] {
+ margin: 0;
+ width: 18px;
+ height: 18px;
+}
+
+.btn {
+ padding: 12px 24px;
+ border: none;
+ border-radius: 6px;
+ cursor: pointer;
+ font-size: 14px;
+ font-weight: 600;
+ transition: all 0.3s ease;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+}
+
+.btn-primary {
+ background: #1976d2;
+ color: white;
+}
+
+.btn-primary:hover {
+ background: #1565c0;
+ transform: translateY(-1px);
+ box-shadow: 0 4px 12px rgba(25, 118, 210, 0.3);
+}
+
+.btn-secondary {
+ background: #6c757d;
+ color: white;
+}
+
+.btn-secondary:hover {
+ background: #5a6268;
+ transform: translateY(-1px);
+ box-shadow: 0 4px 12px rgba(108, 117, 125, 0.3);
+}
+
+.btn-warning {
+ background: #FFC107;
+ color: #212529;
+}
+
+.btn-warning:hover {
+ background: #e0a800;
+ transform: translateY(-1px);
+ box-shadow: 0 4px 12px rgba(255, 193, 7, 0.3);
+}
+
+.btn-info {
+ background: #17a2b8;
+ color: white;
+}
+
+.btn-info:hover {
+ background: #138496;
+ transform: translateY(-1px);
+ box-shadow: 0 4px 12px rgba(23, 162, 184, 0.3);
+}
+
+.btn-danger {
+ background: #dc3545;
+ color: white;
+}
+
+.btn-danger:hover {
+ background: #c82333;
+ transform: translateY(-1px);
+ box-shadow: 0 4px 12px rgba(220, 53, 69, 0.3);
+}
+
+.btn-success {
+ background: #28a745;
+ color: white;
+}
+
+.btn-success:hover {
+ background: #218838;
+ transform: translateY(-1px);
+ box-shadow: 0 4px 12px rgba(40, 167, 69, 0.3);
+}
+
+.messages-container {
+ height: 500px;
+ overflow-y: auto;
+ border: 2px solid #e9ecef;
+ border-radius: 8px;
+ padding: 20px;
+ background: #fafafa;
+ font-family: "SF Mono", "Monaco", "Inconsolata", "Roboto Mono", monospace;
+ font-size: 13px;
+ line-height: 1.5;
+}
+
+.messages-container::-webkit-scrollbar {
+ width: 8px;
+}
+
+.messages-container::-webkit-scrollbar-track {
+ background: #f1f1f1;
+ border-radius: 4px;
+}
+
+.messages-container::-webkit-scrollbar-thumb {
+ background: #c1c1c1;
+ border-radius: 4px;
+}
+
+.messages-container::-webkit-scrollbar-thumb:hover {
+ background: #a8a8a8;
+}
+
+.message {
+ margin-bottom: 16px;
+ padding: 16px;
+ border-radius: 8px;
+ border-left: 4px solid #1976d2;
+ background: white;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
+ animation: slideIn 0.3s ease;
+}
+
+@keyframes slideIn {
+ from { opacity: 0; transform: translateX(-20px); }
+ to { opacity: 1; transform: translateX(0); }
+}
+
+.message.error {
+ border-left-color: #dc3545;
+ background: #fff5f5;
+}
+
+.message.warning {
+ border-left-color: #FFC107;
+ background: #fffbf0;
+}
+
+.message.info {
+ border-left-color: #17a2b8;
+ background: #f0f9ff;
+}
+
+.message.success {
+ border-left-color: #28a745;
+ background: #f0fff4;
+}
+
+.message-time {
+ font-size: 11px;
+ color: #666;
+ margin-bottom: 8px;
+ font-weight: 500;
+}
+
+.message-type {
+ font-weight: 600;
+ color: #333;
+ margin-bottom: 8px;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+}
+
+.stats-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+ gap: 20px;
+ margin: 24px 0;
+}
+
+.stat-card {
+ background: white;
+ padding: 24px;
+ border-radius: 12px;
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
+ text-align: center;
+ border: 1px solid #e9ecef;
+}
+
+.stat-number {
+ font-size: 2.5em;
+ font-weight: 700;
+ color: #1976d2;
+ margin-bottom: 8px;
+}
+
+.stat-label {
+ color: #666;
+ font-size: 14px;
+ font-weight: 500;
+}
+
+.online-users {
+ max-height: 400px;
+ overflow-y: auto;
+ background: #f8f9fa;
+ border-radius: 8px;
+ padding: 20px;
+ border: 1px solid #e9ecef;
+}
+
+.online-users::-webkit-scrollbar {
+ width: 6px;
+}
+
+.online-users::-webkit-scrollbar-track {
+ background: #f1f1f1;
+}
+
+.online-users::-webkit-scrollbar-thumb {
+ background: #c1c1c1;
+ border-radius: 3px;
+}
+
+.user-item {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 12px 16px;
+ margin: 8px 0;
+ background: white;
+ border-radius: 6px;
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
+ border: 1px solid #e9ecef;
+}
+
+.user-info {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+}
+
+.user-id {
+ font-weight: 600;
+ color: #333;
+}
+
+.user-details {
+ font-size: 12px;
+ color: #666;
+}
+
+.loading-indicator {
+ display: inline-block;
+ width: 16px;
+ height: 16px;
+ border: 2px solid #f3f3f3;
+ border-top: 2px solid #1976d2;
+ border-radius: 50%;
+ animation: spin 1s linear infinite;
+ margin-left: 8px;
+}
+
+@keyframes spin {
+ 0% { transform: rotate(0deg); }
+ 100% { transform: rotate(360deg); }
+}
+
+.message-limit-warning {
+ background: #fff3cd;
+ border: 1px solid #ffeaa7;
+ padding: 16px;
+ margin: 16px 0;
+ border-radius: 6px;
+ font-size: 14px;
+ color: #856404;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+.admin-controls {
+ background: #fff3cd;
+ padding: 20px;
+ border-radius: 8px;
+ margin-bottom: 24px;
+ border: 1px solid #ffeaa7;
+}
+
+.admin-warning {
+ color: #856404;
+ font-weight: 600;
+ margin-bottom: 16px;
+ display: flex;
+ align-items: center;
+ gap: 8px;
+}
+
+pre {
+ background: #f8f9fa;
+ padding: 12px;
+ border-radius: 6px;
+ overflow-x: auto;
+ font-size: 12px;
+ border: 1px solid #e9ecef;
+ margin: 8px 0;
+}
+
+code {
+ background: #f8f9fa;
+ padding: 2px 6px;
+ border-radius: 3px;
+ font-family: "SF Mono", "Monaco", "Inconsolata", "Roboto Mono", monospace;
+ font-size: 13px;
+}
+
+.message pre {
+ white-space: pre-wrap;
+ word-break: break-word;
+}
+
+.message code {
+ display: block;
+ margin: 8px 0;
+}
+
+/* Responsive Design */
+@media (max-width: 768px) {
+ .container {
+ margin: 10px;
+ padding: 16px;
+ border-radius: 8px;
+ }
+
+ .controls {
+ grid-template-columns: 1fr;
+ padding: 16px;
+ }
+
+ .status-bar {
+ grid-template-columns: 1fr;
+ padding: 16px;
+ }
+
+ .stats-grid {
+ grid-template-columns: 1fr;
+ }
+
+ .tabs {
+ flex-wrap: wrap;
+ }
+
+ .tab {
+ padding: 12px 16px;
+ font-size: 14px;
+ }
+
+ .messages-container {
+ height: 300px;
+ font-size: 12px;
+ }
+
+ .message {
+ padding: 12px;
+ font-size: 13px;
+ }
+
+ .btn {
+ padding: 10px 16px;
+ font-size: 13px;
+ }
+}
+
+@media (max-width: 480px) {
+ .container {
+ padding: 12px;
+ }
+
+ .controls {
+ padding: 12px;
+ }
+
+ .status-bar {
+ padding: 12px;
+ }
+
+ .messages-container {
+ height: 250px;
+ padding: 12px;
+ }
+
+ .tab {
+ padding: 8px 12px;
+ font-size: 12px;
+ }
+}
+
+/* Dark mode support */
+@media (prefers-color-scheme: dark) {
+ body {
+ background-color: #121212;
+ color: #e0e0e0;
+ }
+
+ .container {
+ background: #1e1e1e;
+ border: 1px solid #333;
+ }
+
+ .controls {
+ background: #2a2a2a;
+ border: 1px solid #404040;
+ }
+
+ .message {
+ background: #2a2a2a;
+ border: 1px solid #404040;
+ }
+
+ .stat-card {
+ background: #2a2a2a;
+ border: 1px solid #404040;
+ }
+
+ .online-users {
+ background: #2a2a2a;
+ border: 1px solid #404040;
+ }
+
+ .user-item {
+ background: #333;
+ border: 1px solid #404040;
+ }
+
+ .messages-container {
+ background: #1a1a1a;
+ border-color: #404040;
+ }
+
+ pre {
+ background: #2a2a2a;
+ border-color: #404040;
+ }
+
+ code {
+ background: #333;
+ }
+}
+
+/* Accessibility improvements */
+@media (prefers-reduced-motion: reduce) {
+ * {
+ animation-duration: 0.01ms !important;
+ animation-iteration-count: 1 !important;
+ transition-duration: 0.01ms !important;
+ }
+}
+
+/* Focus styles for keyboard navigation */
+.btn:focus,
+.tab:focus,
+.input-group input:focus,
+.input-group select:focus,
+.input-group textarea:focus {
+ outline: 2px solid #1976d2;
+ outline-offset: 2px;
+}
+
+/* High contrast mode support */
+@media (prefers-contrast: high) {
+ .btn {
+ border: 2px solid currentColor;
+ }
+
+ .message {
+ border: 2px solid currentColor;
+ }
+
+ .stat-card {
+ border: 2px solid currentColor;
+ }
+}
diff --git a/examples/clientsocket/client.html b/examples/clientsocket/client.html
new file mode 100644
index 0000000..98e2b40
--- /dev/null
+++ b/examples/clientsocket/client.html
@@ -0,0 +1,2251 @@
+
+
+
+ WebSocket Test Client
+
+
+
+
+
🌐 WebSocket Test Client - Enhanced & Optimized
+
+
+
+
+
+ Status:
+ Disconnected
+
+
+
+
+ Uptime: 0s
+
+
+ Client ID:
+ Not connected
+
+
+ Reconnect: Not needed
+
+
+
+
+
+ ⚠️ Message history approaching limit. Older messages will be
+ automatically cleared.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
0
+
Messages Received
+
+
+
+
0ms
+
Connection Latency
+
+
+
0
+
Reconnection Attempts
+
+
+
+
+
+
+
+
+
+
+ ⚠️ Admin functions - Use with caution!
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 📨 Messages
+ 0 messages
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/clientsocket/components/WebSocketClient.vue b/examples/clientsocket/components/WebSocketClient.vue
new file mode 100644
index 0000000..9e35f9d
--- /dev/null
+++ b/examples/clientsocket/components/WebSocketClient.vue
@@ -0,0 +1,367 @@
+
+
+
WebSocket Client
+
+
+
+
+
+
{{ connectionStatusText }}
+
+
+ Client ID:
+ {{ connectionState?.clientId || 'Not connected' }}
+
+
+ Room:
+ {{ connectionState?.currentRoom || 'None' }}
+
+
+ Messages:
+ {{ messages?.length || 0 }}/{{ config?.maxMessages || 1000 }}
+
+
+ Uptime:
+ {{ connectionState?.uptime || '00:00:00' }}
+
+
+
Health:
+
+ {{ connectionHealthText }}
+
+
+
+
+
+
+ mdi-alert
+ Message limit approaching ({{ messages?.length || 0 }}/{{ config?.maxMessages || 1000 }})
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/clientsocket/components/tabs/AdminTab.vue b/examples/clientsocket/components/tabs/AdminTab.vue
new file mode 100644
index 0000000..eacad47
--- /dev/null
+++ b/examples/clientsocket/components/tabs/AdminTab.vue
@@ -0,0 +1,665 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Server Information
+
+
+
Server Version
+
{{ serverInfo.version }}
+
+
+
Environment
+
{{ serverInfo.environment }}
+
+
+
Node Version
+
{{ serverInfo.nodeVersion }}
+
+
+
Platform
+
{{ serverInfo.platform }}
+
+
+
Architecture
+
{{ serverInfo.architecture }}
+
+
+
CPU Cores
+
{{ serverInfo.cpuCores }}
+
+
+
Memory Usage
+
{{ formatBytes(serverInfo.memoryUsage) }}
+
+
+
Uptime
+
{{ formatUptime(serverInfo.uptime) }}
+
+
+
+
+
+
+
System Health
+
+
+
CPU Usage
+
{{ systemHealth.cpuUsage }}%
+
+
+
+
Memory Usage
+
{{ systemHealth.memoryUsage }}%
+
+
+
+
Disk Usage
+
{{ systemHealth.diskUsage }}%
+
+
+
+
Network I/O
+
{{ formatBytes(systemHealth.networkRx) }} / {{ formatBytes(systemHealth.networkTx) }}
+
+
+
Active Connections
+
{{ systemHealth.activeConnections }}
+
+
+
Error Rate
+
{{ systemHealth.errorRate }}%
+
+
+
+
+
+
+
Command History
+
+
+
+
{{ command.command }}
+
{{ formatTime(command.timestamp) }}
+
+ {{ command.success ? 'Success' : 'Error' }}
+
+
+
+
+ Parameters: {{ command.params }}
+
+
+
Result:
+
{{ JSON.stringify(command.result, null, 2) }}
+
+
+ Error: {{ command.error }}
+
+
+
+
+ No commands executed yet
+
+
+
+
+
+
+
⚠️ Security Notice
+
Admin commands can have serious consequences. Please ensure you have proper authorization and understand the impact of each command before execution.
+
+ - Server restart will disconnect all clients
+ - Database operations are irreversible
+ - Always backup before destructive operations
+ - Some commands require elevated permissions
+
+
+
+
+
+
+
+
diff --git a/examples/clientsocket/components/tabs/ConnectionTab.vue b/examples/clientsocket/components/tabs/ConnectionTab.vue
new file mode 100644
index 0000000..988e02f
--- /dev/null
+++ b/examples/clientsocket/components/tabs/ConnectionTab.vue
@@ -0,0 +1,397 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Connection Information
+
+
+ Client ID:
+ {{ connectionState.clientId }}
+
+
+ Static ID:
+ {{ connectionState.staticId || "N/A" }}
+
+
+ IP Address:
+ {{ connectionState.ipAddress || "N/A" }}
+
+
+ User ID:
+ {{ connectionState.userId }}
+
+
+ Room:
+ {{ connectionState.currentRoom }}
+
+
+ Connected At:
+ {{
+ new Date(connectionState.connectionStartTime || 0).toLocaleString()
+ }}
+
+
+ Latency:
+ {{ connectionState.connectionLatency }}ms
+
+
+ Reconnect Attempts:
+ {{ connectionState.reconnectAttempts }}
+
+
+
+
+
+
+
+
+
diff --git a/examples/clientsocket/components/tabs/DatabaseTab.vue b/examples/clientsocket/components/tabs/DatabaseTab.vue
new file mode 100644
index 0000000..6879f18
--- /dev/null
+++ b/examples/clientsocket/components/tabs/DatabaseTab.vue
@@ -0,0 +1,536 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Query History
+
+
+
+
+
{{ query.sql }}
+
+ Parameters: {{ query.params }}
+
+
+
Result:
+
{{ JSON.stringify(query.result, null, 2) }}
+
+
+ Error: {{ query.error }}
+
+
+
+
+ No queries executed yet
+
+
+
+
+
+
+
Database Statistics
+
+
+
Connected Clients
+
{{ stats.connected_clients }}
+
+
+
Unique IPs
+
{{ stats.unique_ips }}
+
+
+
Static Clients
+
{{ stats.static_clients }}
+
+
+
Active Rooms
+
{{ stats.active_rooms }}
+
+
+
Message Queue Size
+
{{ stats.message_queue_size }}
+
+
+
Queue Workers
+
{{ stats.queue_workers }}
+
+
+
Uptime
+
{{ formatUptime(stats.uptime) }}
+
+
+
Last Updated
+
{{ formatTime(stats.timestamp) }}
+
+
+
+
+
+
+
+
+
diff --git a/examples/clientsocket/components/tabs/MessagingTab.vue b/examples/clientsocket/components/tabs/MessagingTab.vue
new file mode 100644
index 0000000..5d4dd99
--- /dev/null
+++ b/examples/clientsocket/components/tabs/MessagingTab.vue
@@ -0,0 +1,602 @@
+
+
+
+
+
+
+
+ {{
+ connectionState.connectionStatus === "connected"
+ ? "Connected"
+ : connectionState.connectionStatus === "connecting"
+ ? "Connecting..."
+ : connectionState.connectionStatus === "error"
+ ? "Connection Error"
+ : "Disconnected"
+ }}
+
+
+
+ Client ID: {{ connectionState.clientId }}
+ Room: {{ connectionState.currentRoom }}
+ Latency: {{ connectionState.connectionLatency }}ms
+ Health: {{ connectionState.connectionHealth }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Online Users ({{ onlineUsers.length }})
+
+
+
+
{{ user.client_id }}
+
+ Room: {{ user.room }}
+ IP: {{ user.ip_address }}
+ Connected: {{ formatTime(user.connected_at) }}
+
+
+
+
+
+
+
+
+
+
+
+
Activity Log
+
+
+
{{ formatTime(activity.timestamp) }}
+
{{ activity.event }}
+
{{ activity.details }}
+
+
+ No activity logged yet
+
+
+
+
+
+
+
+
+
diff --git a/examples/clientsocket/components/tabs/MonitoringTab.vue b/examples/clientsocket/components/tabs/MonitoringTab.vue
new file mode 100644
index 0000000..ad12093
--- /dev/null
+++ b/examples/clientsocket/components/tabs/MonitoringTab.vue
@@ -0,0 +1,637 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Connection Health
+
+
+
Status
+
+ {{ connectionHealthText }}
+
+
+
+
Latency
+
+ {{ connectionState.connectionLatency }}ms
+
+
+
+
Messages Sent
+
{{ connectionState.messagesSent }}
+
+
+
Messages Received
+
{{ connectionState.messagesReceived }}
+
+
+
Reconnect Attempts
+
+ {{ connectionState.reconnectAttempts }}
+
+
+
+
Connection Time
+
{{ connectionState.uptime }}
+
+
+
+
+
+
+
Server Statistics
+
+
+
Connected Clients
+
{{ stats.connected_clients }}
+
+ {{ getStatChange("connected_clients") }}
+
+
+
+
Unique IPs
+
{{ stats.unique_ips }}
+
+ {{ getStatChange("unique_ips") }}
+
+
+
+
Static Clients
+
{{ stats.static_clients }}
+
+ {{ getStatChange("static_clients") }}
+
+
+
+
Active Rooms
+
{{ stats.active_rooms }}
+
+ {{ getStatChange("active_rooms") }}
+
+
+
+
Message Queue
+
{{ stats.message_queue_size }}
+
+ {{ getStatChange("message_queue_size") }}
+
+
+
+
Queue Workers
+
{{ stats.queue_workers }}
+
+ {{ getStatChange("queue_workers") }}
+
+
+
+
Server Uptime
+
{{ formatUptime(stats.uptime) }}
+
+
+
Last Updated
+
{{ formatTime(stats.timestamp) }}
+
+
+
+
+
+
+
Monitoring Data
+
+
{{ JSON.stringify(monitoringData, null, 2) }}
+
+
+
+
+
+
Notification History
+
+
+
+
+
{{ JSON.stringify(notification.payload, null, 2) }}
+
+
+
+ No notifications sent yet
+
+
+
+
+
+
+
+
+
diff --git a/examples/clientsocket/composables/note b/examples/clientsocket/composables/note
new file mode 100644
index 0000000..7478c16
--- /dev/null
+++ b/examples/clientsocket/composables/note
@@ -0,0 +1,1073 @@
+import { ref, computed, reactive, nextTick } from "vue";
+import type {
+ WebSocketMessage,
+ ConnectionState,
+ WebSocketConfig,
+ MessageHistory,
+ ConnectionStats,
+ MonitoringData,
+ ClientInfo,
+ OnlineUser,
+ ActivityLog,
+} from "../types/websocket";
+
+export const useWebSocket = () => {
+ // Check if we're in browser environment
+ const isBrowser = process.client;
+
+ const ws = ref(null);
+ const isConnected = ref(false);
+ const isConnecting = ref(false);
+ const connectionStatus = ref<
+ "disconnected" | "connecting" | "connected" | "error"
+ >("disconnected");
+
+ const connectionState = reactive({
+ isConnected: false,
+ isConnecting: false,
+ connectionStatus: "disconnected",
+ clientId: null,
+ staticId: null,
+ currentRoom: null,
+ userId: "anonymous",
+ ipAddress: null,
+ connectionStartTime: null,
+ lastPingTime: null,
+ connectionLatency: 0,
+ connectionHealth: "poor",
+ reconnectAttempts: 0,
+ messagesReceived: 0,
+ messagesSent: 0,
+ uptime: "00:00:00",
+ });
+
+ const config = reactive({
+ wsUrl: "ws://localhost:8080/api/v1/ws",
+ userId: "anonymous",
+ room: "default",
+ staticId: "",
+ useIPBasedId: false,
+ autoReconnect: true,
+ heartbeatEnabled: true,
+ maxReconnectAttempts: 10,
+ reconnectDelay: 1000,
+ maxReconnectDelay: 30000,
+ heartbeatInterval: 30000,
+ heartbeatTimeout: 5000,
+ maxMissedHeartbeats: 3,
+ maxMessages: 1000,
+ messageWarningThreshold: 800,
+ actionThrottle: 100,
+ });
+
+ const messages = ref([]);
+ const stats = ref(null);
+ const monitoringData = ref(null);
+ const onlineUsers = ref([]);
+ const activityLog = ref([]);
+
+ let reconnectTimeout: number | null = null;
+ let heartbeatInterval: number | null = null;
+ let heartbeatTimeout: number | null = null;
+ let missedHeartbeats = 0;
+ let lastHeartbeatTime = 0;
+ let messageCount = 0;
+ let connectionStartTime: number | null = null;
+ let uptimeInterval: number | null = null;
+ let isManualDisconnect = false;
+ let reconnectAttempts = 0;
+ let connectionHealth: "excellent" | "good" | "warning" | "poor" = "poor";
+
+ const updateConnectionStatus = (
+ status: "disconnected" | "connecting" | "connected" | "error"
+ ) => {
+ connectionStatus.value = status;
+ connectionState.connectionStatus = status;
+
+ switch (status) {
+ case "connected":
+ isConnected.value = true;
+ isConnecting.value = false;
+ connectionState.isConnected = true;
+ connectionState.isConnecting = false;
+ connectionState.connectionHealth = "good";
+ break;
+ case "connecting":
+ isConnected.value = false;
+ isConnecting.value = true;
+ connectionState.isConnected = false;
+ connectionState.isConnecting = true;
+ connectionState.connectionHealth = "warning";
+ break;
+ case "disconnected":
+ isConnected.value = false;
+ isConnecting.value = false;
+ connectionState.isConnected = false;
+ connectionState.isConnecting = false;
+ connectionState.connectionHealth = "poor";
+ break;
+ case "error":
+ isConnected.value = false;
+ isConnecting.value = false;
+ connectionState.isConnected = false;
+ connectionState.isConnecting = false;
+ connectionState.connectionHealth = "poor";
+ break;
+ }
+ };
+
+ const updateUptime = () => {
+ if (connectionStartTime && isConnected.value) {
+ const now = Date.now();
+ const uptime = now - connectionStartTime;
+ const seconds = Math.floor(uptime / 1000);
+ const minutes = Math.floor(seconds / 60);
+ const hours = Math.floor(minutes / 60);
+
+ connectionState.uptime = `${hours.toString().padStart(2, "0")}:${(
+ minutes % 60
+ )
+ .toString()
+ .padStart(2, "0")}:${(seconds % 60).toString().padStart(2, "0")}`;
+ } else {
+ connectionState.uptime = "00:00:00";
+ }
+ };
+
+ const startUptimeTimer = () => {
+ if (uptimeInterval) {
+ clearInterval(uptimeInterval);
+ }
+ uptimeInterval = window.setInterval(updateUptime, 1000);
+ };
+
+ const stopUptimeTimer = () => {
+ if (uptimeInterval) {
+ clearInterval(uptimeInterval);
+ uptimeInterval = null;
+ }
+ };
+
+ // Only run WebSocket logic in browser
+ if (isBrowser) {
+ // Initialize connection state
+ updateConnectionStatus("disconnected");
+ }
+
+ const addMessage = (
+ type: string,
+ data: any,
+ messageId?: string,
+ icon?: string
+ ) => {
+ if (!isBrowser) return;
+
+ const now = new Date();
+ const timeString = now.toLocaleTimeString("en-US", {
+ hour12: true,
+ hour: "numeric",
+ minute: "2-digit",
+ second: "2-digit",
+ });
+
+ // Enhanced message formatting based on type
+ let formattedData = data;
+ let displayType = type;
+
+ switch (type) {
+ case "connection_info":
+ displayType = "info";
+ formattedData = {
+ client_id: data.clientId,
+ connected_at: data.connectedAt,
+ ip_address: data.ipAddress,
+ last_ping: data.lastPingTime || "N/A",
+ room: data.room || "default",
+ static_id: data.staticId || "none",
+ user_id: data.userId || "anonymous",
+ };
+ break;
+
+ case "heartbeat":
+ displayType = "info";
+ formattedData = `❤️ Heartbeat started\nInterval: ${
+ config.heartbeatInterval / 1000
+ }s`;
+ break;
+
+ case "pong":
+ displayType = "success";
+ formattedData = `🏓 Pong received\nLatency: ${connectionState.connectionLatency}ms`;
+ break;
+
+ case "message":
+ displayType = "info";
+ formattedData = `📨 Message received\n${JSON.stringify(data, null, 2)}`;
+ break;
+
+ case "broadcast":
+ displayType = "info";
+ formattedData = `📡 Broadcast received\n${data}`;
+ break;
+
+ case "direct_message":
+ displayType = "info";
+ formattedData = `📨 Direct message from ${data.from}\n${data.message}`;
+ break;
+
+ case "room_message":
+ displayType = "info";
+ formattedData = `📢 Room message from ${data.room}\n${data.message}`;
+ break;
+
+ case "stats":
+ displayType = "info";
+ formattedData = `📊 Stats updated\n${JSON.stringify(data, null, 2)}`;
+ break;
+
+ case "monitoring":
+ displayType = "info";
+ formattedData = `📈 Monitoring data\n${JSON.stringify(data, null, 2)}`;
+ break;
+
+ case "online_users":
+ displayType = "info";
+ formattedData = `👥 Online users updated\nCount: ${
+ data.users?.length || 0
+ }`;
+ break;
+
+ case "server_info":
+ displayType = "info";
+ formattedData = `🔧 Server info\n${JSON.stringify(data, null, 2)}`;
+ break;
+
+ case "system_health":
+ displayType = "info";
+ formattedData = `💚 System health\n${JSON.stringify(data, null, 2)}`;
+ break;
+
+ default:
+ if (typeof data === "string") {
+ formattedData = data;
+ } else {
+ formattedData = JSON.stringify(data, null, 2);
+ }
+ }
+
+ const message: MessageHistory = {
+ timestamp: now,
+ type: displayType,
+ data: formattedData,
+ messageId,
+ size: JSON.stringify(data).length,
+ icon: icon || getIconForMessageType(displayType),
+ timeString: timeString,
+ };
+
+ messages.value.unshift(message);
+ messageCount++;
+
+ // Keep only the last maxMessages
+ if (messages.value.length > config.maxMessages) {
+ messages.value = messages.value.slice(0, config.maxMessages);
+ }
+
+ // Update connection state
+ connectionState.messagesReceived++;
+ };
+
+ const getIconForMessageType = (type: string): string => {
+ switch (type) {
+ case "success":
+ return "🟢";
+ case "error":
+ return "❌";
+ case "warning":
+ return "⚠️";
+ case "info":
+ return "ℹ️";
+ default:
+ return "📝";
+ }
+ };
+
+ const connectionHealthColor = computed(() => {
+ switch (connectionState.connectionHealth) {
+ case "excellent":
+ return "#4CAF50";
+ case "good":
+ return "#2196F3";
+ case "warning":
+ return "#FFC107";
+ case "poor":
+ return "#F44336";
+ default:
+ return "#9E9E9E";
+ }
+ });
+
+ const connectionHealthText = computed(() => {
+ switch (connectionState.connectionHealth) {
+ case "excellent":
+ return "Excellent";
+ case "good":
+ return "Good";
+ case "warning":
+ return "Warning";
+ case "poor":
+ return "Poor";
+ default:
+ return "Unknown";
+ }
+ });
+
+ // Admin functionality
+ const serverInfo = ref(null);
+ const systemHealth = ref(null);
+
+ const executeAdminCommand = async (command: string, params: any) => {
+ if (!isBrowser || !ws.value) throw new Error("Not connected");
+
+ const message = {
+ type: "admin_command",
+ command,
+ params,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ return { success: true, message: "Command sent successfully" };
+ };
+
+ const getServerInfo = async () => {
+ if (!isBrowser || !ws.value) throw new Error("Not connected");
+
+ const message = {
+ type: "get_server_info",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ };
+
+ const getSystemHealth = async () => {
+ if (!isBrowser || !ws.value) throw new Error("Not connected");
+
+ const message = {
+ type: "get_system_health",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ };
+
+ // Cleanup on unmount
+ const cleanup = () => {
+ if (!isBrowser) return;
+
+ disconnect();
+ if (reconnectTimeout) {
+ clearTimeout(reconnectTimeout);
+ }
+ stopHeartbeat();
+ };
+
+ // WebSocket connection methods (only available in browser)
+ const connect = () => {
+ if (!isBrowser) return;
+
+ // Prevent multiple connection attempts
+ if (isConnecting.value || isConnected.value) {
+ return;
+ }
+
+ // Clean up existing connection
+ if (ws.value) {
+ cleanupConnection();
+ }
+
+ updateConnectionStatus("connecting");
+ isManualDisconnect = false;
+ connectionStartTime = Date.now();
+ startUptimeTimer();
+
+ try {
+ // Build WebSocket URL with parameters
+ let url = config.wsUrl;
+ const params = new URLSearchParams();
+
+ if (config.userId) {
+ params.append("user_id", config.userId);
+ }
+ if (config.room) {
+ params.append("room", config.room);
+ }
+ if (config.useIPBasedId) {
+ params.append("ip_based", "true");
+ } else if (config.staticId) {
+ params.append("static_id", config.staticId);
+ }
+
+ if (params.toString()) {
+ url += "?" + params.toString();
+ }
+
+ ws.value = new WebSocket(url);
+
+ // Connection timeout
+ const connectionTimeout = setTimeout(() => {
+ if (ws.value && ws.value.readyState === WebSocket.CONNECTING) {
+ ws.value.close();
+ updateConnectionStatus("error");
+ addMessage("❌ Connection timeout after 15 seconds", "error");
+ scheduleReconnect();
+ }
+ }, 15000);
+
+ ws.value.onopen = function (event) {
+ clearTimeout(connectionTimeout);
+ updateConnectionStatus("connected");
+ reconnectAttempts = 0;
+ connectionHealth = "good";
+ connectionState.connectionStartTime = connectionStartTime;
+
+ addMessage(
+ "🟢 Connected to WebSocket server",
+ "success",
+ "Connection established successfully"
+ );
+
+ // Start heartbeat if enabled
+ if (config.heartbeatEnabled) {
+ startHeartbeat();
+ }
+ };
+
+ ws.value.onmessage = function (event) {
+ handleIncomingMessage(event);
+ };
+
+ ws.value.onclose = function (event) {
+ clearTimeout(connectionTimeout);
+ cleanupTimers();
+ updateConnectionStatus("disconnected");
+
+ const reason = getCloseReason(event.code);
+ addMessage(
+ `🔴 Disconnected: ${reason}`,
+ "error",
+ `Code: ${event.code}, Reason: ${event.reason || "Unknown"}`
+ );
+
+ // Auto-reconnect logic
+ if (!isManualDisconnect && config.autoReconnect) {
+ scheduleReconnect();
+ }
+ };
+
+ ws.value.onerror = function (error) {
+ updateConnectionStatus("error");
+ connectionHealth = "poor";
+ addMessage("❌ WebSocket Error occurred", "error", error.toString());
+ };
+ } catch (error) {
+ updateConnectionStatus("error");
+ addMessage(
+ "❌ Failed to create WebSocket connection",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ scheduleReconnect();
+ }
+ };
+
+ const disconnect = () => {
+ if (!isBrowser) return;
+
+ isManualDisconnect = true;
+ cleanupConnection();
+ updateConnectionStatus("disconnected");
+ addMessage("🔴 Manually disconnected from WebSocket", "info");
+ };
+
+ const sendMessage = (message: any) => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot send message: not connected", "error");
+ return;
+ }
+
+ try {
+ const messageData = {
+ type: "message",
+ data: message,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(messageData));
+ connectionState.messagesSent++;
+ addMessage("📤 Message sent", "info", message);
+ } catch (error) {
+ addMessage(
+ "❌ Failed to send message",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const broadcastMessage = (message: string) => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot broadcast message: not connected", "error");
+ return;
+ }
+
+ try {
+ const messageData = {
+ type: "broadcast",
+ message,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(messageData));
+ connectionState.messagesSent++;
+ addMessage("📡 Message broadcasted", "info", message);
+ } catch (error) {
+ addMessage(
+ "❌ Failed to broadcast message",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const sendDirectMessage = (clientId: string, message: string) => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot send direct message: not connected", "error");
+ return;
+ }
+
+ try {
+ const messageData = {
+ type: "direct_message",
+ clientId,
+ message,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(messageData));
+ connectionState.messagesSent++;
+ addMessage(`📨 Direct message sent to ${clientId}`, "info", message);
+ } catch (error) {
+ addMessage(
+ "❌ Failed to send direct message",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const sendRoomMessage = (room: string, message: string) => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot send room message: not connected", "error");
+ return;
+ }
+
+ try {
+ const messageData = {
+ type: "room_message",
+ room,
+ message,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(messageData));
+ connectionState.messagesSent++;
+ addMessage(`📢 Room message sent to ${room}`, "info", message);
+ } catch (error) {
+ addMessage(
+ "❌ Failed to send room message",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const getOnlineUsers = () => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot get online users: not connected", "error");
+ return;
+ }
+
+ try {
+ const message = {
+ type: "get_online_users",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ } catch (error) {
+ addMessage(
+ "❌ Failed to request online users",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const testConnection = () => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot test connection: not connected", "error");
+ return;
+ }
+
+ try {
+ const message = {
+ type: "ping",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ addMessage("🏓 Connection test sent", "info");
+ } catch (error) {
+ addMessage(
+ "❌ Failed to test connection",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const sendHeartbeat = () => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot send heartbeat: not connected", "error");
+ return;
+ }
+
+ try {
+ const message = {
+ type: "ping",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ lastHeartbeatTime = Date.now();
+ } catch (error) {
+ addMessage(
+ "❌ Failed to send heartbeat",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const executeDatabaseQuery = async (query: string) => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ throw new Error("Not connected");
+ }
+
+ try {
+ const message = {
+ type: "database_query",
+ query,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ return { success: true, message: "Database query sent successfully" };
+ } catch (error) {
+ throw new Error(
+ `Failed to execute database query: ${
+ error instanceof Error ? error.message : String(error)
+ }`
+ );
+ }
+ };
+
+ const triggerNotification = async (message: string) => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ throw new Error("Not connected");
+ }
+
+ try {
+ const notificationData = {
+ type: "notification",
+ message,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(notificationData));
+ return { success: true, message: "Notification sent successfully" };
+ } catch (error) {
+ throw new Error(
+ `Failed to trigger notification: ${
+ error instanceof Error ? error.message : String(error)
+ }`
+ );
+ }
+ };
+
+ const getStats = () => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot get stats: not connected", "error");
+ return;
+ }
+
+ try {
+ const message = {
+ type: "get_stats",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ } catch (error) {
+ addMessage(
+ "❌ Failed to request stats",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const getMonitoringData = () => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot get monitoring data: not connected", "error");
+ return;
+ }
+
+ try {
+ const message = {
+ type: "get_monitoring",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ } catch (error) {
+ addMessage(
+ "❌ Failed to request monitoring data",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const clearMessages = () => {
+ if (!isBrowser) return;
+ messages.value = [];
+ messageCount = 0;
+ };
+
+ const clearActivityLog = () => {
+ if (!isBrowser) return;
+ activityLog.value = [];
+ };
+
+ const getMessagesByType = (type: string) => {
+ return messages.value.filter((msg) => msg.type === type);
+ };
+
+ const getRecentMessages = (count: number = 10) => {
+ return messages.value.slice(0, count);
+ };
+
+ const stopHeartbeat = () => {
+ if (!isBrowser) return;
+
+ if (heartbeatInterval) {
+ clearInterval(heartbeatInterval);
+ heartbeatInterval = null;
+ }
+ if (heartbeatTimeout) {
+ clearTimeout(heartbeatTimeout);
+ heartbeatTimeout = null;
+ }
+ missedHeartbeats = 0;
+ };
+
+ const cleanupConnection = () => {
+ if (!isBrowser) return;
+
+ if (ws.value) {
+ ws.value.close();
+ ws.value = null;
+ }
+ cleanupTimers();
+ };
+
+ const cleanupTimers = () => {
+ if (!isBrowser) return;
+
+ if (reconnectTimeout) {
+ clearTimeout(reconnectTimeout);
+ reconnectTimeout = null;
+ }
+ stopHeartbeat();
+ stopUptimeTimer();
+ };
+
+ const scheduleReconnect = () => {
+ if (!isBrowser || !config.autoReconnect) return;
+
+ if (reconnectAttempts >= config.maxReconnectAttempts) {
+ addMessage("❌ Max reconnection attempts reached", "error");
+ return;
+ }
+
+ reconnectAttempts++;
+ const delay = Math.min(
+ config.reconnectDelay * Math.pow(2, reconnectAttempts - 1),
+ config.maxReconnectDelay
+ );
+
+ addMessage(
+ `🔄 Reconnecting in ${delay}ms (attempt ${reconnectAttempts}/${config.maxReconnectAttempts})`,
+ "info"
+ );
+
+ reconnectTimeout = window.setTimeout(() => {
+ connect();
+ }, delay);
+ };
+
+ const startHeartbeat = () => {
+ if (!isBrowser || !config.heartbeatEnabled) return;
+
+ stopHeartbeat();
+
+ heartbeatInterval = window.setInterval(() => {
+ if (ws.value && ws.value.readyState === WebSocket.OPEN) {
+ const heartbeatMessage = {
+ type: "ping",
+ timestamp: Date.now(),
+ };
+ ws.value.send(JSON.stringify(heartbeatMessage));
+ lastHeartbeatTime = Date.now();
+
+ // Set timeout for heartbeat response
+ heartbeatTimeout = window.setTimeout(() => {
+ missedHeartbeats++;
+ if (missedHeartbeats >= config.maxMissedHeartbeats) {
+ addMessage(
+ "❌ Heartbeat timeout - connection unhealthy",
+ "warning"
+ );
+ connectionHealth = "warning";
+ }
+ }, config.heartbeatTimeout);
+ }
+ }, config.heartbeatInterval);
+ };
+
+ const handleIncomingMessage = (event: MessageEvent) => {
+ if (!isBrowser) return;
+
+ try {
+ const data = JSON.parse(event.data);
+
+ // Handle heartbeat response
+ if (data.type === "pong") {
+ missedHeartbeats = 0;
+ connectionHealth = "excellent";
+ const latency = Date.now() - lastHeartbeatTime;
+ connectionState.connectionLatency = latency;
+ return;
+ }
+
+ // Handle connection info
+ if (data.type === "connection_info") {
+ connectionState.clientId = data.clientId;
+ connectionState.staticId = data.staticId;
+ connectionState.currentRoom = data.room;
+ connectionState.userId = data.userId;
+ connectionState.ipAddress = data.ipAddress;
+ return;
+ }
+
+ // Handle welcome message (server sends connection info in welcome message)
+ if (data.type === "welcome") {
+ console.log("Received welcome message:", data);
+
+ // Map server snake_case fields to camelCase for Vue components
+ if (data.client_id) {
+ connectionState.clientId = data.client_id;
+ console.log("Set clientId:", data.client_id);
+ }
+ if (data.static_id) {
+ connectionState.staticId = data.static_id;
+ console.log("Set staticId:", data.static_id);
+ }
+ if (data.room) {
+ connectionState.currentRoom = data.room;
+ console.log("Set currentRoom:", data.room);
+ }
+ if (data.user_id) {
+ connectionState.userId = data.user_id;
+ console.log("Set userId:", data.user_id);
+ }
+ if (data.ip_address) {
+ connectionState.ipAddress = data.ip_address;
+ console.log("Set ipAddress:", data.ip_address);
+ }
+ if (data.connected_at) {
+ connectionState.connectionStartTime = data.connected_at * 1000;
+ console.log("Set connectionStartTime:", data.connected_at * 1000);
+ }
+
+ // Force reactive update by triggering a change
+ connectionState.connectionHealth =
+ connectionState.connectionHealth === "good" ? "excellent" : "good";
+
+ console.log("Updated connectionState:", connectionState);
+ addMessage(
+ "🟢 Connection established successfully",
+ "success",
+ "Welcome message processed"
+ );
+ return;
+ }
+
+ // Handle stats
+ if (data.type === "stats") {
+ stats.value = data;
+ return;
+ }
+
+ // Handle monitoring data
+ if (data.type === "monitoring") {
+ monitoringData.value = data;
+ return;
+ }
+
+ // Handle online users
+ if (data.type === "online_users") {
+ onlineUsers.value = data.users;
+ return;
+ }
+
+ // Handle activity log
+ if (data.type === "activity") {
+ activityLog.value.unshift(data);
+ if (activityLog.value.length > 100) {
+ activityLog.value = activityLog.value.slice(0, 100);
+ }
+ return;
+ }
+
+ // Handle server info
+ if (data.type === "server_info") {
+ serverInfo.value = data;
+ return;
+ }
+
+ // Handle system health
+ if (data.type === "system_health") {
+ systemHealth.value = data;
+ return;
+ }
+
+ // Handle regular messages
+ addMessage(data.type || "message", data, data.messageId);
+ } catch (error) {
+ addMessage(
+ "❌ Failed to parse message",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const getCloseReason = (code: number): string => {
+ switch (code) {
+ case 1000:
+ return "Normal closure";
+ case 1001:
+ return "Going away";
+ case 1002:
+ return "Protocol error";
+ case 1003:
+ return "Unsupported data";
+ case 1004:
+ return "Reserved";
+ case 1005:
+ return "No status received";
+ case 1006:
+ return "Abnormal closure";
+ case 1007:
+ return "Invalid frame payload data";
+ case 1008:
+ return "Policy violation";
+ case 1009:
+ return "Message too big";
+ case 1010:
+ return "Mandatory extension";
+ case 1011:
+ return "Internal server error";
+ case 1012:
+ return "Service restart";
+ case 1013:
+ return "Try again later";
+ case 1014:
+ return "Bad gateway";
+ case 1015:
+ return "TLS handshake";
+ default:
+ return "Unknown reason";
+ }
+ };
+
+ const isMessageLimitReached = computed(() => {
+ return messages.value.length >= config.maxMessages;
+ });
+
+ const shouldShowMessageWarning = computed(() => {
+ return messages.value.length >= config.messageWarningThreshold;
+ });
+
+ return {
+ // State
+ ws,
+ isConnected,
+ isConnecting,
+ connectionStatus,
+ connectionState,
+ config,
+ messages,
+ stats,
+ monitoringData,
+ onlineUsers,
+ activityLog,
+
+ // Admin state
+ serverInfo,
+ systemHealth,
+
+ // Methods
+ connect,
+ disconnect,
+ sendMessage,
+ broadcastMessage,
+ sendDirectMessage,
+ sendRoomMessage,
+ getServerInfo,
+ getOnlineUsers,
+ testConnection,
+ sendHeartbeat,
+ executeDatabaseQuery,
+ triggerNotification,
+ getStats,
+ getMonitoringData,
+ executeAdminCommand,
+ getSystemHealth,
+ clearMessages,
+ clearActivityLog,
+ getMessagesByType,
+ getRecentMessages,
+ cleanup,
+
+ // Computed
+ isMessageLimitReached,
+ shouldShowMessageWarning,
+ connectionHealthColor,
+ connectionHealthText,
+ };
+};
diff --git a/examples/clientsocket/composables/useWebSocket.fixed b/examples/clientsocket/composables/useWebSocket.fixed
new file mode 100644
index 0000000..972b9d5
--- /dev/null
+++ b/examples/clientsocket/composables/useWebSocket.fixed
@@ -0,0 +1,1073 @@
+import { ref, computed, reactive, type Ref } from "vue";
+import type {
+ WebSocketMessage,
+ ConnectionState,
+ WebSocketConfig,
+ MessageHistory,
+ ConnectionStats,
+ MonitoringData,
+ ClientInfo,
+ OnlineUser,
+ ActivityLog,
+} from "../types/websocket";
+
+export const useWebSocket = () => {
+ // Check if we're in browser environment
+ const isBrowser = process.client;
+
+ // WebSocket connection
+ const ws: Ref = ref(null);
+
+ // Connection state - consolidated into single reactive object
+ const connectionState = reactive({
+ isConnected: false,
+ isConnecting: false,
+ connectionStatus: "disconnected",
+ clientId: null,
+ staticId: null,
+ currentRoom: null,
+ userId: "anonymous",
+ ipAddress: null,
+ connectionStartTime: null,
+ lastPingTime: null,
+ connectionLatency: 0,
+ connectionHealth: "poor",
+ reconnectAttempts: 0,
+ messagesReceived: 0,
+ messagesSent: 0,
+ uptime: "00:00:00",
+ });
+
+ // Configuration
+ const config = reactive({
+ wsUrl: "ws://localhost:8080/api/v1/ws",
+ userId: "anonymous",
+ room: "default",
+ staticId: "",
+ useIPBasedId: false,
+ autoReconnect: true,
+ heartbeatEnabled: true,
+ maxReconnectAttempts: 10,
+ reconnectDelay: 1000,
+ maxReconnectDelay: 30000,
+ heartbeatInterval: 30000,
+ heartbeatTimeout: 5000,
+ maxMissedHeartbeats: 3,
+ maxMessages: 1000,
+ messageWarningThreshold: 800,
+ actionThrottle: 100,
+ });
+
+ // Message history and data
+ const messages = ref([]);
+ const stats = ref(null);
+ const monitoringData = ref(null);
+ const onlineUsers = ref([]);
+ const activityLog = ref([]);
+
+ // Admin functionality
+ const serverInfo = ref(null);
+ const systemHealth = ref(null);
+
+ // Timer references for proper cleanup
+ let reconnectTimeout: number | null = null;
+ let heartbeatInterval: number | null = null;
+ let heartbeatTimeout: number | null = null;
+ let uptimeInterval: number | null = null;
+ let connectionStartTime: number | null = null;
+
+ // Heartbeat tracking
+ let missedHeartbeats = 0;
+ let lastHeartbeatTime = 0;
+ let isManualDisconnect = false;
+
+ // Helper function to update connection status
+ const updateConnectionStatus = (
+ status: "disconnected" | "connecting" | "connected" | "error"
+ ) => {
+ connectionState.connectionStatus = status;
+
+ switch (status) {
+ case "connected":
+ connectionState.isConnected = true;
+ connectionState.isConnecting = false;
+ connectionState.connectionHealth = "good";
+ break;
+ case "connecting":
+ connectionState.isConnected = false;
+ connectionState.isConnecting = true;
+ connectionState.connectionHealth = "warning";
+ break;
+ case "disconnected":
+ case "error":
+ connectionState.isConnected = false;
+ connectionState.isConnecting = false;
+ connectionState.connectionHealth = "poor";
+ break;
+ }
+ };
+
+ // Helper function to update uptime
+ const updateUptime = () => {
+ if (connectionStartTime && connectionState.isConnected) {
+ const now = Date.now();
+ const uptime = now - connectionStartTime;
+ const seconds = Math.floor(uptime / 1000);
+ const minutes = Math.floor(seconds / 60);
+ const hours = Math.floor(minutes / 60);
+
+ connectionState.uptime = `${hours.toString().padStart(2, "0")}:${(
+ minutes % 60
+ )
+ .toString()
+ .padStart(2, "0")}:${(seconds % 60).toString().padStart(2, "0")}`;
+ } else {
+ connectionState.uptime = "00:00:00";
+ }
+ };
+
+ // Timer management
+ const startUptimeTimer = () => {
+ if (uptimeInterval) {
+ clearInterval(uptimeInterval);
+ }
+ uptimeInterval = window.setInterval(updateUptime, 1000);
+ };
+
+ const stopUptimeTimer = () => {
+ if (uptimeInterval) {
+ clearInterval(uptimeInterval);
+ uptimeInterval = null;
+ }
+ };
+
+ // Message handling
+ const getIconForMessageType = (type: string): string => {
+ switch (type) {
+ case "success":
+ return "🟢";
+ case "error":
+ return "❌";
+ case "warning":
+ return "⚠️";
+ case "info":
+ return "ℹ️";
+ default:
+ return "📝";
+ }
+ };
+
+ const addMessage = (
+ type: string,
+ data: any,
+ messageId?: string,
+ icon?: string
+ ) => {
+ if (!isBrowser) return;
+
+ const now = new Date();
+ const timeString = now.toLocaleTimeString("en-US", {
+ hour12: true,
+ hour: "numeric",
+ minute: "2-digit",
+ second: "2-digit",
+ });
+
+ // Enhanced message formatting based on type
+ let formattedData = data;
+ let displayType = type;
+
+ switch (type) {
+ case "connection_info":
+ displayType = "info";
+ formattedData = {
+ client_id: data.clientId,
+ connected_at: data.connectedAt,
+ ip_address: data.ipAddress,
+ last_ping: data.lastPingTime || "N/A",
+ room: data.room || "default",
+ static_id: data.staticId || "none",
+ user_id: data.userId || "anonymous",
+ };
+ break;
+
+ case "heartbeat":
+ displayType = "info";
+ formattedData = `❤️ Heartbeat started\nInterval: ${
+ config.heartbeatInterval / 1000
+ }s`;
+ break;
+
+ case "pong":
+ displayType = "success";
+ formattedData = `🏓 Pong received\nLatency: ${connectionState.connectionLatency}ms`;
+ break;
+
+ case "message":
+ displayType = "info";
+ formattedData = `📨 Message received\n${JSON.stringify(data, null, 2)}`;
+ break;
+
+ case "broadcast":
+ displayType = "info";
+ formattedData = `📡 Broadcast received\n${data}`;
+ break;
+
+ case "direct_message":
+ displayType = "info";
+ formattedData = `📨 Direct message from ${data.from}\n${data.message}`;
+ break;
+
+ case "room_message":
+ displayType = "info";
+ formattedData = `📢 Room message from ${data.room}\n${data.message}`;
+ break;
+
+ case "stats":
+ displayType = "info";
+ formattedData = `📊 Stats updated\n${JSON.stringify(data, null, 2)}`;
+ break;
+
+ case "monitoring":
+ displayType = "info";
+ formattedData = `📈 Monitoring data\n${JSON.stringify(data, null, 2)}`;
+ break;
+
+ case "online_users":
+ displayType = "info";
+ formattedData = `👥 Online users updated\nCount: ${
+ data.users?.length || 0
+ }`;
+ break;
+
+ case "server_info":
+ displayType = "info";
+ formattedData = `🔧 Server info\n${JSON.stringify(data, null, 2)}`;
+ break;
+
+ case "system_health":
+ displayType = "info";
+ formattedData = `💚 System health\n${JSON.stringify(data, null, 2)}`;
+ break;
+
+ default:
+ if (typeof data === "string") {
+ formattedData = data;
+ } else {
+ formattedData = JSON.stringify(data, null, 2);
+ }
+ }
+
+ const message: MessageHistory = {
+ timestamp: now,
+ type: displayType,
+ data: formattedData,
+ messageId,
+ size: JSON.stringify(data).length,
+ icon: icon || getIconForMessageType(displayType),
+ timeString: timeString,
+ };
+
+ messages.value.unshift(message);
+
+ // Keep only the last maxMessages
+ if (messages.value.length > config.maxMessages) {
+ messages.value = messages.value.slice(0, config.maxMessages);
+ }
+
+ // Update connection state
+ connectionState.messagesReceived++;
+ };
+
+ // Computed properties
+ const connectionHealthColor = computed(() => {
+ switch (connectionState.connectionHealth) {
+ case "excellent":
+ return "#4CAF50";
+ case "good":
+ return "#2196F3";
+ case "warning":
+ return "#FFC107";
+ case "poor":
+ return "#F44336";
+ default:
+ return "#9E9E9E";
+ }
+ });
+
+ const connectionHealthText = computed(() => {
+ switch (connectionState.connectionHealth) {
+ case "excellent":
+ return "Excellent";
+ case "good":
+ return "Good";
+ case "warning":
+ return "Warning";
+ case "poor":
+ return "Poor";
+ default:
+ return "Unknown";
+ }
+ });
+
+ const isMessageLimitReached = computed(() => {
+ return messages.value.length >= config.maxMessages;
+ });
+
+ const shouldShowMessageWarning = computed(() => {
+ return messages.value.length >= config.messageWarningThreshold;
+ });
+
+ // Timer cleanup
+ const cleanupTimers = () => {
+ if (!isBrowser) return;
+
+ if (reconnectTimeout) {
+ clearTimeout(reconnectTimeout);
+ reconnectTimeout = null;
+ }
+ if (heartbeatInterval) {
+ clearInterval(heartbeatInterval);
+ heartbeatInterval = null;
+ }
+ if (heartbeatTimeout) {
+ clearTimeout(heartbeatTimeout);
+ heartbeatTimeout = null;
+ }
+ stopUptimeTimer();
+ };
+
+ // Connection cleanup
+ const cleanupConnection = () => {
+ if (!isBrowser) return;
+
+ if (ws.value) {
+ ws.value.close();
+ ws.value = null;
+ }
+ cleanupTimers();
+ };
+
+ // Get close reason description
+ const getCloseReason = (code: number): string => {
+ switch (code) {
+ case 1000:
+ return "Normal closure";
+ case 1001:
+ return "Going away";
+ case 1002:
+ return "Protocol error";
+ case 1003:
+ return "Unsupported data";
+ case 1004:
+ return "Reserved";
+ case 1005:
+ return "No status received";
+ case 1006:
+ return "Abnormal closure";
+ case 1007:
+ return "Invalid frame payload data";
+ case 1008:
+ return "Policy violation";
+ case 1009:
+ return "Message too big";
+ case 1010:
+ return "Mandatory extension";
+ case 1011:
+ return "Internal server error";
+ case 1012:
+ return "Service restart";
+ case 1013:
+ return "Try again later";
+ case 1014:
+ return "Bad gateway";
+ case 1015:
+ return "TLS handshake";
+ default:
+ return "Unknown reason";
+ }
+ };
+
+ // Heartbeat management
+ const stopHeartbeat = () => {
+ if (!isBrowser) return;
+
+ if (heartbeatInterval) {
+ clearInterval(heartbeatInterval);
+ heartbeatInterval = null;
+ }
+ if (heartbeatTimeout) {
+ clearTimeout(heartbeatTimeout);
+ heartbeatTimeout = null;
+ }
+ missedHeartbeats = 0;
+ };
+
+ const startHeartbeat = () => {
+ if (!isBrowser || !config.heartbeatEnabled) return;
+
+ stopHeartbeat();
+
+ heartbeatInterval = window.setInterval(() => {
+ if (ws.value && ws.value.readyState === WebSocket.OPEN) {
+ const heartbeatMessage = {
+ type: "ping",
+ timestamp: Date.now(),
+ };
+ ws.value.send(JSON.stringify(heartbeatMessage));
+ lastHeartbeatTime = Date.now();
+
+ // Set timeout for heartbeat response
+ heartbeatTimeout = window.setTimeout(() => {
+ missedHeartbeats++;
+ if (missedHeartbeats >= config.maxMissedHeartbeats) {
+ addMessage(
+ "❌ Heartbeat timeout - connection unhealthy",
+ "warning"
+ );
+ connectionState.connectionHealth = "warning";
+ }
+ }, config.heartbeatTimeout);
+ }
+ }, config.heartbeatInterval);
+ };
+
+ // Reconnection logic
+ const scheduleReconnect = () => {
+ if (!isBrowser || !config.autoReconnect) return;
+
+ if (connectionState.reconnectAttempts >= config.maxReconnectAttempts) {
+ addMessage("❌ Max reconnection attempts reached", "error");
+ return;
+ }
+
+ connectionState.reconnectAttempts++;
+ const delay = Math.min(
+ config.reconnectDelay *
+ Math.pow(2, connectionState.reconnectAttempts - 1),
+ config.maxReconnectDelay
+ );
+
+ addMessage(
+ `🔄 Reconnecting in ${delay}ms (attempt ${connectionState.reconnectAttempts}/${config.maxReconnectAttempts})`,
+ "info"
+ );
+
+ reconnectTimeout = window.setTimeout(() => {
+ connect();
+ }, delay);
+ };
+
+ // Message handling
+ const handleIncomingMessage = (event: MessageEvent) => {
+ if (!isBrowser) return;
+
+ try {
+ const data = JSON.parse(event.data);
+
+ // Handle heartbeat response
+ if (data.type === "pong") {
+ missedHeartbeats = 0;
+ connectionState.connectionHealth = "excellent";
+ const latency = Date.now() - lastHeartbeatTime;
+ connectionState.connectionLatency = latency;
+ return;
+ }
+
+ // Handle connection info
+ if (data.type === "connection_info") {
+ connectionState.clientId = data.clientId;
+ connectionState.staticId = data.staticId;
+ connectionState.currentRoom = data.room;
+ connectionState.userId = data.userId;
+ connectionState.ipAddress = data.ipAddress;
+ return;
+ }
+
+ // Handle welcome message (server sends connection info in welcome message)
+ if (data.type === "welcome") {
+ console.log("Received welcome message:", data);
+
+ // Map server snake_case fields to camelCase for Vue components
+ if (data.client_id) {
+ connectionState.clientId = data.client_id;
+ console.log("Set clientId:", data.client_id);
+ }
+ if (data.static_id) {
+ connectionState.staticId = data.static_id;
+ console.log("Set staticId:", data.static_id);
+ }
+ if (data.room) {
+ connectionState.currentRoom = data.room;
+ console.log("Set currentRoom:", data.room);
+ }
+ if (data.user_id) {
+ connectionState.userId = data.user_id;
+ console.log("Set userId:", data.user_id);
+ }
+ if (data.ip_address) {
+ connectionState.ipAddress = data.ip_address;
+ console.log("Set ipAddress:", data.ip_address);
+ }
+ if (data.connected_at) {
+ connectionState.connectionStartTime = data.connected_at * 1000;
+ console.log("Set connectionStartTime:", data.connected_at * 1000);
+ }
+
+ // Force reactive update by triggering a change
+ connectionState.connectionHealth =
+ connectionState.connectionHealth === "good" ? "excellent" : "good";
+
+ console.log("Updated connectionState:", connectionState);
+ addMessage(
+ "🟢 Connection established successfully",
+ "success",
+ "Welcome message processed"
+ );
+ return;
+ }
+
+ // Handle stats
+ if (data.type === "stats") {
+ stats.value = data;
+ return;
+ }
+
+ // Handle monitoring data
+ if (data.type === "monitoring") {
+ monitoringData.value = data;
+ return;
+ }
+
+ // Handle online users
+ if (data.type === "online_users") {
+ onlineUsers.value = data.users;
+ return;
+ }
+
+ // Handle activity log
+ if (data.type === "activity") {
+ activityLog.value.unshift(data);
+ if (activityLog.value.length > 100) {
+ activityLog.value = activityLog.value.slice(0, 100);
+ }
+ return;
+ }
+
+ // Handle server info
+ if (data.type === "server_info") {
+ serverInfo.value = data;
+ return;
+ }
+
+ // Handle system health
+ if (data.type === "system_health") {
+ systemHealth.value = data;
+ return;
+ }
+
+ // Handle regular messages
+ addMessage(data.type || "message", data, data.messageId);
+ } catch (error) {
+ addMessage(
+ "❌ Failed to parse message",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ // WebSocket connection methods
+ const connect = () => {
+ if (!isBrowser) return;
+
+ // Prevent multiple connection attempts
+ if (connectionState.isConnecting || connectionState.isConnected) {
+ return;
+ }
+
+ // Clean up existing connection
+ if (ws.value) {
+ cleanupConnection();
+ }
+
+ updateConnectionStatus("connecting");
+ isManualDisconnect = false;
+ connectionStartTime = Date.now();
+ startUptimeTimer();
+
+ try {
+ // Build WebSocket URL with parameters
+ let url = config.wsUrl;
+ const params = new URLSearchParams();
+
+ if (config.userId) {
+ params.append("user_id", config.userId);
+ }
+ if (config.room) {
+ params.append("room", config.room);
+ }
+ if (config.useIPBasedId) {
+ params.append("ip_based", "true");
+ } else if (config.staticId) {
+ params.append("static_id", config.staticId);
+ }
+
+ if (params.toString()) {
+ url += "?" + params.toString();
+ }
+
+ ws.value = new WebSocket(url);
+
+ // Connection timeout
+ const connectionTimeout = setTimeout(() => {
+ if (ws.value && ws.value.readyState === WebSocket.CONNECTING) {
+ ws.value.close();
+ updateConnectionStatus("error");
+ addMessage("❌ Connection timeout after 15 seconds", "error");
+ scheduleReconnect();
+ }
+ }, 15000);
+
+ ws.value.onopen = function (event) {
+ clearTimeout(connectionTimeout);
+ updateConnectionStatus("connected");
+ connectionState.reconnectAttempts = 0;
+ connectionState.connectionStartTime = connectionStartTime;
+
+ addMessage(
+ "🟢 Connected to WebSocket server",
+ "success",
+ "Connection established successfully"
+ );
+
+ // Start heartbeat if enabled
+ if (config.heartbeatEnabled) {
+ startHeartbeat();
+ }
+ };
+
+ ws.value.onmessage = function (event) {
+ handleIncomingMessage(event);
+ };
+
+ ws.value.onclose = function (event) {
+ clearTimeout(connectionTimeout);
+ cleanupTimers();
+ updateConnectionStatus("disconnected");
+
+ const reason = getCloseReason(event.code);
+ addMessage(
+ `🔴 Disconnected: ${reason}`,
+ "error",
+ `Code: ${event.code}, Reason: ${event.reason || "Unknown"}`
+ );
+
+ // Auto-reconnect logic
+ if (!isManualDisconnect && config.autoReconnect) {
+ scheduleReconnect();
+ }
+ };
+
+ ws.value.onerror = function (error) {
+ updateConnectionStatus("error");
+ addMessage("❌ WebSocket Error occurred", "error", error.toString());
+ };
+ } catch (error) {
+ updateConnectionStatus("error");
+ addMessage(
+ "❌ Failed to create WebSocket connection",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ scheduleReconnect();
+ }
+ };
+
+ const disconnect = () => {
+ if (!isBrowser) return;
+
+ isManualDisconnect = true;
+ cleanupConnection();
+ updateConnectionStatus("disconnected");
+ addMessage("🔴 Manually disconnected from WebSocket", "info");
+ };
+
+ // Message sending methods
+ const sendMessage = (message: any) => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot send message: not connected", "error");
+ return false;
+ }
+
+ try {
+ const messageData = {
+ type: "message",
+ data: message,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(messageData));
+ connectionState.messagesSent++;
+ addMessage("📤 Message sent", "info", message);
+ return true;
+ } catch (error) {
+ addMessage(
+ "❌ Failed to send message",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ return false;
+ }
+ };
+
+ const broadcastMessage = (message: string) => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot broadcast message: not connected", "error");
+ return false;
+ }
+
+ try {
+ const messageData = {
+ type: "broadcast",
+ message,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(messageData));
+ connectionState.messagesSent++;
+ addMessage("📡 Message broadcasted", "info", message);
+ return true;
+ } catch (error) {
+ addMessage(
+ "❌ Failed to broadcast message",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ return false;
+ }
+ };
+
+ const sendDirectMessage = (clientId: string, message: string) => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot send direct message: not connected", "error");
+ return false;
+ }
+
+ try {
+ const messageData = {
+ type: "direct_message",
+ clientId,
+ message,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(messageData));
+ connectionState.messagesSent++;
+ addMessage(`📨 Direct message sent to ${clientId}`, "info", message);
+ return true;
+ } catch (error) {
+ addMessage(
+ "❌ Failed to send direct message",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ return false;
+ }
+ };
+
+ const sendRoomMessage = (room: string, message: string) => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot send room message: not connected", "error");
+ return false;
+ }
+
+ try {
+ const messageData = {
+ type: "room_message",
+ room,
+ message,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(messageData));
+ connectionState.messagesSent++;
+ addMessage(`📢 Room message sent to ${room}`, "info", message);
+ return true;
+ } catch (error) {
+ addMessage(
+ "❌ Failed to send room message",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ return false;
+ }
+ };
+
+ // Admin and utility methods
+ const executeAdminCommand = async (command: string, params: any) => {
+ if (!isBrowser || !ws.value) throw new Error("Not connected");
+
+ const message = {
+ type: "admin_command",
+ command,
+ params,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ return { success: true, message: "Command sent successfully" };
+ };
+
+ const getServerInfo = async () => {
+ if (!isBrowser || !ws.value) throw new Error("Not connected");
+
+ const message = {
+ type: "get_server_info",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ };
+
+ const getSystemHealth = async () => {
+ if (!isBrowser || !ws.value) throw new Error("Not connected");
+
+ const message = {
+ type: "get_system_health",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ };
+
+ const getOnlineUsers = () => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot get online users: not connected", "error");
+ return;
+ }
+
+ try {
+ const message = {
+ type: "get_online_users",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ } catch (error) {
+ addMessage(
+ "❌ Failed to request online users",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const testConnection = () => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot test connection: not connected", "error");
+ return;
+ }
+
+ try {
+ const message = {
+ type: "ping",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ addMessage("🏓 Connection test sent", "info");
+ } catch (error) {
+ addMessage(
+ "❌ Failed to test connection",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const sendHeartbeat = () => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot send heartbeat: not connected", "error");
+ return;
+ }
+
+ try {
+ const message = {
+ type: "ping",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ lastHeartbeatTime = Date.now();
+ } catch (error) {
+ addMessage(
+ "❌ Failed to send heartbeat",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const executeDatabaseQuery = async (query: string) => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ throw new Error("Not connected");
+ }
+
+ try {
+ const message = {
+ type: "database_query",
+ query,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ return { success: true, message: "Database query sent successfully" };
+ } catch (error) {
+ throw new Error(
+ `Failed to execute database query: ${
+ error instanceof Error ? error.message : String(error)
+ }`
+ );
+ }
+ };
+
+ const triggerNotification = async (message: string) => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ throw new Error("Not connected");
+ }
+
+ try {
+ const notificationData = {
+ type: "notification",
+ message,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(notificationData));
+ return { success: true, message: "Notification sent successfully" };
+ } catch (error) {
+ throw new Error(
+ `Failed to trigger notification: ${
+ error instanceof Error ? error.message : String(error)
+ }`
+ );
+ }
+ };
+
+ const getStats = () => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot get stats: not connected", "error");
+ return;
+ }
+
+ try {
+ const message = {
+ type: "get_stats",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ } catch (error) {
+ addMessage(
+ "❌ Failed to request stats",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const getMonitoringData = () => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot get monitoring data: not connected", "error");
+ return;
+ }
+
+ try {
+ const message = {
+ type: "get_monitoring",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ } catch (error) {
+ addMessage(
+ "❌ Failed to request monitoring data",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ // Utility methods
+ const clearMessages = () => {
+ if (!isBrowser) return;
+ messages.value = [];
+ };
+
+ const clearActivityLog = () => {
+ if (!isBrowser) return;
+ activityLog.value = [];
+ };
+
+ const getMessagesByType = (type: string) => {
+ return messages.value.filter((msg) => msg.type === type);
+ };
+
+ const getRecentMessages = (count: number = 10) => {
+ return messages.value.slice(0, count);
+ };
+
+ // Cleanup on unmount
+ const cleanup = () => {
+ if (!isBrowser) return;
+
+ disconnect();
+ cleanupTimers();
+ };
+
+ return {
+ // State
+ ws,
+ connectionState,
+ config,
+ messages,
+ stats,
+ monitoringData,
+ onlineUsers,
+ activityLog,
+
+ // Admin state
+ serverInfo,
+ systemHealth,
+
+ // Methods
+ connect,
+ disconnect,
+ sendMessage,
+ broadcastMessage,
+ sendDirectMessage,
+ sendRoomMessage,
+ getServerInfo,
+ getOnlineUsers,
+ testConnection,
+ sendHeartbeat,
+ executeDatabaseQuery,
+ triggerNotification,
+ getStats,
+ getMonitoringData,
+ executeAdminCommand,
+ getSystemHealth,
+ clearMessages,
+ clearActivityLog,
+ getMessagesByType,
+ getRecentMessages,
+ cleanup,
+
+ // Computed
+ isMessageLimitReached,
+ shouldShowMessageWarning,
+ connectionHealthColor,
+ connectionHealthText,
+ };
+};
diff --git a/examples/clientsocket/composables/useWebSocket.ts b/examples/clientsocket/composables/useWebSocket.ts
new file mode 100644
index 0000000..7478c16
--- /dev/null
+++ b/examples/clientsocket/composables/useWebSocket.ts
@@ -0,0 +1,1073 @@
+import { ref, computed, reactive, nextTick } from "vue";
+import type {
+ WebSocketMessage,
+ ConnectionState,
+ WebSocketConfig,
+ MessageHistory,
+ ConnectionStats,
+ MonitoringData,
+ ClientInfo,
+ OnlineUser,
+ ActivityLog,
+} from "../types/websocket";
+
+export const useWebSocket = () => {
+ // Check if we're in browser environment
+ const isBrowser = process.client;
+
+ const ws = ref(null);
+ const isConnected = ref(false);
+ const isConnecting = ref(false);
+ const connectionStatus = ref<
+ "disconnected" | "connecting" | "connected" | "error"
+ >("disconnected");
+
+ const connectionState = reactive({
+ isConnected: false,
+ isConnecting: false,
+ connectionStatus: "disconnected",
+ clientId: null,
+ staticId: null,
+ currentRoom: null,
+ userId: "anonymous",
+ ipAddress: null,
+ connectionStartTime: null,
+ lastPingTime: null,
+ connectionLatency: 0,
+ connectionHealth: "poor",
+ reconnectAttempts: 0,
+ messagesReceived: 0,
+ messagesSent: 0,
+ uptime: "00:00:00",
+ });
+
+ const config = reactive({
+ wsUrl: "ws://localhost:8080/api/v1/ws",
+ userId: "anonymous",
+ room: "default",
+ staticId: "",
+ useIPBasedId: false,
+ autoReconnect: true,
+ heartbeatEnabled: true,
+ maxReconnectAttempts: 10,
+ reconnectDelay: 1000,
+ maxReconnectDelay: 30000,
+ heartbeatInterval: 30000,
+ heartbeatTimeout: 5000,
+ maxMissedHeartbeats: 3,
+ maxMessages: 1000,
+ messageWarningThreshold: 800,
+ actionThrottle: 100,
+ });
+
+ const messages = ref([]);
+ const stats = ref(null);
+ const monitoringData = ref(null);
+ const onlineUsers = ref([]);
+ const activityLog = ref([]);
+
+ let reconnectTimeout: number | null = null;
+ let heartbeatInterval: number | null = null;
+ let heartbeatTimeout: number | null = null;
+ let missedHeartbeats = 0;
+ let lastHeartbeatTime = 0;
+ let messageCount = 0;
+ let connectionStartTime: number | null = null;
+ let uptimeInterval: number | null = null;
+ let isManualDisconnect = false;
+ let reconnectAttempts = 0;
+ let connectionHealth: "excellent" | "good" | "warning" | "poor" = "poor";
+
+ const updateConnectionStatus = (
+ status: "disconnected" | "connecting" | "connected" | "error"
+ ) => {
+ connectionStatus.value = status;
+ connectionState.connectionStatus = status;
+
+ switch (status) {
+ case "connected":
+ isConnected.value = true;
+ isConnecting.value = false;
+ connectionState.isConnected = true;
+ connectionState.isConnecting = false;
+ connectionState.connectionHealth = "good";
+ break;
+ case "connecting":
+ isConnected.value = false;
+ isConnecting.value = true;
+ connectionState.isConnected = false;
+ connectionState.isConnecting = true;
+ connectionState.connectionHealth = "warning";
+ break;
+ case "disconnected":
+ isConnected.value = false;
+ isConnecting.value = false;
+ connectionState.isConnected = false;
+ connectionState.isConnecting = false;
+ connectionState.connectionHealth = "poor";
+ break;
+ case "error":
+ isConnected.value = false;
+ isConnecting.value = false;
+ connectionState.isConnected = false;
+ connectionState.isConnecting = false;
+ connectionState.connectionHealth = "poor";
+ break;
+ }
+ };
+
+ const updateUptime = () => {
+ if (connectionStartTime && isConnected.value) {
+ const now = Date.now();
+ const uptime = now - connectionStartTime;
+ const seconds = Math.floor(uptime / 1000);
+ const minutes = Math.floor(seconds / 60);
+ const hours = Math.floor(minutes / 60);
+
+ connectionState.uptime = `${hours.toString().padStart(2, "0")}:${(
+ minutes % 60
+ )
+ .toString()
+ .padStart(2, "0")}:${(seconds % 60).toString().padStart(2, "0")}`;
+ } else {
+ connectionState.uptime = "00:00:00";
+ }
+ };
+
+ const startUptimeTimer = () => {
+ if (uptimeInterval) {
+ clearInterval(uptimeInterval);
+ }
+ uptimeInterval = window.setInterval(updateUptime, 1000);
+ };
+
+ const stopUptimeTimer = () => {
+ if (uptimeInterval) {
+ clearInterval(uptimeInterval);
+ uptimeInterval = null;
+ }
+ };
+
+ // Only run WebSocket logic in browser
+ if (isBrowser) {
+ // Initialize connection state
+ updateConnectionStatus("disconnected");
+ }
+
+ const addMessage = (
+ type: string,
+ data: any,
+ messageId?: string,
+ icon?: string
+ ) => {
+ if (!isBrowser) return;
+
+ const now = new Date();
+ const timeString = now.toLocaleTimeString("en-US", {
+ hour12: true,
+ hour: "numeric",
+ minute: "2-digit",
+ second: "2-digit",
+ });
+
+ // Enhanced message formatting based on type
+ let formattedData = data;
+ let displayType = type;
+
+ switch (type) {
+ case "connection_info":
+ displayType = "info";
+ formattedData = {
+ client_id: data.clientId,
+ connected_at: data.connectedAt,
+ ip_address: data.ipAddress,
+ last_ping: data.lastPingTime || "N/A",
+ room: data.room || "default",
+ static_id: data.staticId || "none",
+ user_id: data.userId || "anonymous",
+ };
+ break;
+
+ case "heartbeat":
+ displayType = "info";
+ formattedData = `❤️ Heartbeat started\nInterval: ${
+ config.heartbeatInterval / 1000
+ }s`;
+ break;
+
+ case "pong":
+ displayType = "success";
+ formattedData = `🏓 Pong received\nLatency: ${connectionState.connectionLatency}ms`;
+ break;
+
+ case "message":
+ displayType = "info";
+ formattedData = `📨 Message received\n${JSON.stringify(data, null, 2)}`;
+ break;
+
+ case "broadcast":
+ displayType = "info";
+ formattedData = `📡 Broadcast received\n${data}`;
+ break;
+
+ case "direct_message":
+ displayType = "info";
+ formattedData = `📨 Direct message from ${data.from}\n${data.message}`;
+ break;
+
+ case "room_message":
+ displayType = "info";
+ formattedData = `📢 Room message from ${data.room}\n${data.message}`;
+ break;
+
+ case "stats":
+ displayType = "info";
+ formattedData = `📊 Stats updated\n${JSON.stringify(data, null, 2)}`;
+ break;
+
+ case "monitoring":
+ displayType = "info";
+ formattedData = `📈 Monitoring data\n${JSON.stringify(data, null, 2)}`;
+ break;
+
+ case "online_users":
+ displayType = "info";
+ formattedData = `👥 Online users updated\nCount: ${
+ data.users?.length || 0
+ }`;
+ break;
+
+ case "server_info":
+ displayType = "info";
+ formattedData = `🔧 Server info\n${JSON.stringify(data, null, 2)}`;
+ break;
+
+ case "system_health":
+ displayType = "info";
+ formattedData = `💚 System health\n${JSON.stringify(data, null, 2)}`;
+ break;
+
+ default:
+ if (typeof data === "string") {
+ formattedData = data;
+ } else {
+ formattedData = JSON.stringify(data, null, 2);
+ }
+ }
+
+ const message: MessageHistory = {
+ timestamp: now,
+ type: displayType,
+ data: formattedData,
+ messageId,
+ size: JSON.stringify(data).length,
+ icon: icon || getIconForMessageType(displayType),
+ timeString: timeString,
+ };
+
+ messages.value.unshift(message);
+ messageCount++;
+
+ // Keep only the last maxMessages
+ if (messages.value.length > config.maxMessages) {
+ messages.value = messages.value.slice(0, config.maxMessages);
+ }
+
+ // Update connection state
+ connectionState.messagesReceived++;
+ };
+
+ const getIconForMessageType = (type: string): string => {
+ switch (type) {
+ case "success":
+ return "🟢";
+ case "error":
+ return "❌";
+ case "warning":
+ return "⚠️";
+ case "info":
+ return "ℹ️";
+ default:
+ return "📝";
+ }
+ };
+
+ const connectionHealthColor = computed(() => {
+ switch (connectionState.connectionHealth) {
+ case "excellent":
+ return "#4CAF50";
+ case "good":
+ return "#2196F3";
+ case "warning":
+ return "#FFC107";
+ case "poor":
+ return "#F44336";
+ default:
+ return "#9E9E9E";
+ }
+ });
+
+ const connectionHealthText = computed(() => {
+ switch (connectionState.connectionHealth) {
+ case "excellent":
+ return "Excellent";
+ case "good":
+ return "Good";
+ case "warning":
+ return "Warning";
+ case "poor":
+ return "Poor";
+ default:
+ return "Unknown";
+ }
+ });
+
+ // Admin functionality
+ const serverInfo = ref(null);
+ const systemHealth = ref(null);
+
+ const executeAdminCommand = async (command: string, params: any) => {
+ if (!isBrowser || !ws.value) throw new Error("Not connected");
+
+ const message = {
+ type: "admin_command",
+ command,
+ params,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ return { success: true, message: "Command sent successfully" };
+ };
+
+ const getServerInfo = async () => {
+ if (!isBrowser || !ws.value) throw new Error("Not connected");
+
+ const message = {
+ type: "get_server_info",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ };
+
+ const getSystemHealth = async () => {
+ if (!isBrowser || !ws.value) throw new Error("Not connected");
+
+ const message = {
+ type: "get_system_health",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ };
+
+ // Cleanup on unmount
+ const cleanup = () => {
+ if (!isBrowser) return;
+
+ disconnect();
+ if (reconnectTimeout) {
+ clearTimeout(reconnectTimeout);
+ }
+ stopHeartbeat();
+ };
+
+ // WebSocket connection methods (only available in browser)
+ const connect = () => {
+ if (!isBrowser) return;
+
+ // Prevent multiple connection attempts
+ if (isConnecting.value || isConnected.value) {
+ return;
+ }
+
+ // Clean up existing connection
+ if (ws.value) {
+ cleanupConnection();
+ }
+
+ updateConnectionStatus("connecting");
+ isManualDisconnect = false;
+ connectionStartTime = Date.now();
+ startUptimeTimer();
+
+ try {
+ // Build WebSocket URL with parameters
+ let url = config.wsUrl;
+ const params = new URLSearchParams();
+
+ if (config.userId) {
+ params.append("user_id", config.userId);
+ }
+ if (config.room) {
+ params.append("room", config.room);
+ }
+ if (config.useIPBasedId) {
+ params.append("ip_based", "true");
+ } else if (config.staticId) {
+ params.append("static_id", config.staticId);
+ }
+
+ if (params.toString()) {
+ url += "?" + params.toString();
+ }
+
+ ws.value = new WebSocket(url);
+
+ // Connection timeout
+ const connectionTimeout = setTimeout(() => {
+ if (ws.value && ws.value.readyState === WebSocket.CONNECTING) {
+ ws.value.close();
+ updateConnectionStatus("error");
+ addMessage("❌ Connection timeout after 15 seconds", "error");
+ scheduleReconnect();
+ }
+ }, 15000);
+
+ ws.value.onopen = function (event) {
+ clearTimeout(connectionTimeout);
+ updateConnectionStatus("connected");
+ reconnectAttempts = 0;
+ connectionHealth = "good";
+ connectionState.connectionStartTime = connectionStartTime;
+
+ addMessage(
+ "🟢 Connected to WebSocket server",
+ "success",
+ "Connection established successfully"
+ );
+
+ // Start heartbeat if enabled
+ if (config.heartbeatEnabled) {
+ startHeartbeat();
+ }
+ };
+
+ ws.value.onmessage = function (event) {
+ handleIncomingMessage(event);
+ };
+
+ ws.value.onclose = function (event) {
+ clearTimeout(connectionTimeout);
+ cleanupTimers();
+ updateConnectionStatus("disconnected");
+
+ const reason = getCloseReason(event.code);
+ addMessage(
+ `🔴 Disconnected: ${reason}`,
+ "error",
+ `Code: ${event.code}, Reason: ${event.reason || "Unknown"}`
+ );
+
+ // Auto-reconnect logic
+ if (!isManualDisconnect && config.autoReconnect) {
+ scheduleReconnect();
+ }
+ };
+
+ ws.value.onerror = function (error) {
+ updateConnectionStatus("error");
+ connectionHealth = "poor";
+ addMessage("❌ WebSocket Error occurred", "error", error.toString());
+ };
+ } catch (error) {
+ updateConnectionStatus("error");
+ addMessage(
+ "❌ Failed to create WebSocket connection",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ scheduleReconnect();
+ }
+ };
+
+ const disconnect = () => {
+ if (!isBrowser) return;
+
+ isManualDisconnect = true;
+ cleanupConnection();
+ updateConnectionStatus("disconnected");
+ addMessage("🔴 Manually disconnected from WebSocket", "info");
+ };
+
+ const sendMessage = (message: any) => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot send message: not connected", "error");
+ return;
+ }
+
+ try {
+ const messageData = {
+ type: "message",
+ data: message,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(messageData));
+ connectionState.messagesSent++;
+ addMessage("📤 Message sent", "info", message);
+ } catch (error) {
+ addMessage(
+ "❌ Failed to send message",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const broadcastMessage = (message: string) => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot broadcast message: not connected", "error");
+ return;
+ }
+
+ try {
+ const messageData = {
+ type: "broadcast",
+ message,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(messageData));
+ connectionState.messagesSent++;
+ addMessage("📡 Message broadcasted", "info", message);
+ } catch (error) {
+ addMessage(
+ "❌ Failed to broadcast message",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const sendDirectMessage = (clientId: string, message: string) => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot send direct message: not connected", "error");
+ return;
+ }
+
+ try {
+ const messageData = {
+ type: "direct_message",
+ clientId,
+ message,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(messageData));
+ connectionState.messagesSent++;
+ addMessage(`📨 Direct message sent to ${clientId}`, "info", message);
+ } catch (error) {
+ addMessage(
+ "❌ Failed to send direct message",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const sendRoomMessage = (room: string, message: string) => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot send room message: not connected", "error");
+ return;
+ }
+
+ try {
+ const messageData = {
+ type: "room_message",
+ room,
+ message,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(messageData));
+ connectionState.messagesSent++;
+ addMessage(`📢 Room message sent to ${room}`, "info", message);
+ } catch (error) {
+ addMessage(
+ "❌ Failed to send room message",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const getOnlineUsers = () => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot get online users: not connected", "error");
+ return;
+ }
+
+ try {
+ const message = {
+ type: "get_online_users",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ } catch (error) {
+ addMessage(
+ "❌ Failed to request online users",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const testConnection = () => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot test connection: not connected", "error");
+ return;
+ }
+
+ try {
+ const message = {
+ type: "ping",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ addMessage("🏓 Connection test sent", "info");
+ } catch (error) {
+ addMessage(
+ "❌ Failed to test connection",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const sendHeartbeat = () => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot send heartbeat: not connected", "error");
+ return;
+ }
+
+ try {
+ const message = {
+ type: "ping",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ lastHeartbeatTime = Date.now();
+ } catch (error) {
+ addMessage(
+ "❌ Failed to send heartbeat",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const executeDatabaseQuery = async (query: string) => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ throw new Error("Not connected");
+ }
+
+ try {
+ const message = {
+ type: "database_query",
+ query,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ return { success: true, message: "Database query sent successfully" };
+ } catch (error) {
+ throw new Error(
+ `Failed to execute database query: ${
+ error instanceof Error ? error.message : String(error)
+ }`
+ );
+ }
+ };
+
+ const triggerNotification = async (message: string) => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ throw new Error("Not connected");
+ }
+
+ try {
+ const notificationData = {
+ type: "notification",
+ message,
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(notificationData));
+ return { success: true, message: "Notification sent successfully" };
+ } catch (error) {
+ throw new Error(
+ `Failed to trigger notification: ${
+ error instanceof Error ? error.message : String(error)
+ }`
+ );
+ }
+ };
+
+ const getStats = () => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot get stats: not connected", "error");
+ return;
+ }
+
+ try {
+ const message = {
+ type: "get_stats",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ } catch (error) {
+ addMessage(
+ "❌ Failed to request stats",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const getMonitoringData = () => {
+ if (!isBrowser || !ws.value || ws.value.readyState !== WebSocket.OPEN) {
+ addMessage("❌ Cannot get monitoring data: not connected", "error");
+ return;
+ }
+
+ try {
+ const message = {
+ type: "get_monitoring",
+ timestamp: Date.now(),
+ };
+
+ ws.value.send(JSON.stringify(message));
+ } catch (error) {
+ addMessage(
+ "❌ Failed to request monitoring data",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const clearMessages = () => {
+ if (!isBrowser) return;
+ messages.value = [];
+ messageCount = 0;
+ };
+
+ const clearActivityLog = () => {
+ if (!isBrowser) return;
+ activityLog.value = [];
+ };
+
+ const getMessagesByType = (type: string) => {
+ return messages.value.filter((msg) => msg.type === type);
+ };
+
+ const getRecentMessages = (count: number = 10) => {
+ return messages.value.slice(0, count);
+ };
+
+ const stopHeartbeat = () => {
+ if (!isBrowser) return;
+
+ if (heartbeatInterval) {
+ clearInterval(heartbeatInterval);
+ heartbeatInterval = null;
+ }
+ if (heartbeatTimeout) {
+ clearTimeout(heartbeatTimeout);
+ heartbeatTimeout = null;
+ }
+ missedHeartbeats = 0;
+ };
+
+ const cleanupConnection = () => {
+ if (!isBrowser) return;
+
+ if (ws.value) {
+ ws.value.close();
+ ws.value = null;
+ }
+ cleanupTimers();
+ };
+
+ const cleanupTimers = () => {
+ if (!isBrowser) return;
+
+ if (reconnectTimeout) {
+ clearTimeout(reconnectTimeout);
+ reconnectTimeout = null;
+ }
+ stopHeartbeat();
+ stopUptimeTimer();
+ };
+
+ const scheduleReconnect = () => {
+ if (!isBrowser || !config.autoReconnect) return;
+
+ if (reconnectAttempts >= config.maxReconnectAttempts) {
+ addMessage("❌ Max reconnection attempts reached", "error");
+ return;
+ }
+
+ reconnectAttempts++;
+ const delay = Math.min(
+ config.reconnectDelay * Math.pow(2, reconnectAttempts - 1),
+ config.maxReconnectDelay
+ );
+
+ addMessage(
+ `🔄 Reconnecting in ${delay}ms (attempt ${reconnectAttempts}/${config.maxReconnectAttempts})`,
+ "info"
+ );
+
+ reconnectTimeout = window.setTimeout(() => {
+ connect();
+ }, delay);
+ };
+
+ const startHeartbeat = () => {
+ if (!isBrowser || !config.heartbeatEnabled) return;
+
+ stopHeartbeat();
+
+ heartbeatInterval = window.setInterval(() => {
+ if (ws.value && ws.value.readyState === WebSocket.OPEN) {
+ const heartbeatMessage = {
+ type: "ping",
+ timestamp: Date.now(),
+ };
+ ws.value.send(JSON.stringify(heartbeatMessage));
+ lastHeartbeatTime = Date.now();
+
+ // Set timeout for heartbeat response
+ heartbeatTimeout = window.setTimeout(() => {
+ missedHeartbeats++;
+ if (missedHeartbeats >= config.maxMissedHeartbeats) {
+ addMessage(
+ "❌ Heartbeat timeout - connection unhealthy",
+ "warning"
+ );
+ connectionHealth = "warning";
+ }
+ }, config.heartbeatTimeout);
+ }
+ }, config.heartbeatInterval);
+ };
+
+ const handleIncomingMessage = (event: MessageEvent) => {
+ if (!isBrowser) return;
+
+ try {
+ const data = JSON.parse(event.data);
+
+ // Handle heartbeat response
+ if (data.type === "pong") {
+ missedHeartbeats = 0;
+ connectionHealth = "excellent";
+ const latency = Date.now() - lastHeartbeatTime;
+ connectionState.connectionLatency = latency;
+ return;
+ }
+
+ // Handle connection info
+ if (data.type === "connection_info") {
+ connectionState.clientId = data.clientId;
+ connectionState.staticId = data.staticId;
+ connectionState.currentRoom = data.room;
+ connectionState.userId = data.userId;
+ connectionState.ipAddress = data.ipAddress;
+ return;
+ }
+
+ // Handle welcome message (server sends connection info in welcome message)
+ if (data.type === "welcome") {
+ console.log("Received welcome message:", data);
+
+ // Map server snake_case fields to camelCase for Vue components
+ if (data.client_id) {
+ connectionState.clientId = data.client_id;
+ console.log("Set clientId:", data.client_id);
+ }
+ if (data.static_id) {
+ connectionState.staticId = data.static_id;
+ console.log("Set staticId:", data.static_id);
+ }
+ if (data.room) {
+ connectionState.currentRoom = data.room;
+ console.log("Set currentRoom:", data.room);
+ }
+ if (data.user_id) {
+ connectionState.userId = data.user_id;
+ console.log("Set userId:", data.user_id);
+ }
+ if (data.ip_address) {
+ connectionState.ipAddress = data.ip_address;
+ console.log("Set ipAddress:", data.ip_address);
+ }
+ if (data.connected_at) {
+ connectionState.connectionStartTime = data.connected_at * 1000;
+ console.log("Set connectionStartTime:", data.connected_at * 1000);
+ }
+
+ // Force reactive update by triggering a change
+ connectionState.connectionHealth =
+ connectionState.connectionHealth === "good" ? "excellent" : "good";
+
+ console.log("Updated connectionState:", connectionState);
+ addMessage(
+ "🟢 Connection established successfully",
+ "success",
+ "Welcome message processed"
+ );
+ return;
+ }
+
+ // Handle stats
+ if (data.type === "stats") {
+ stats.value = data;
+ return;
+ }
+
+ // Handle monitoring data
+ if (data.type === "monitoring") {
+ monitoringData.value = data;
+ return;
+ }
+
+ // Handle online users
+ if (data.type === "online_users") {
+ onlineUsers.value = data.users;
+ return;
+ }
+
+ // Handle activity log
+ if (data.type === "activity") {
+ activityLog.value.unshift(data);
+ if (activityLog.value.length > 100) {
+ activityLog.value = activityLog.value.slice(0, 100);
+ }
+ return;
+ }
+
+ // Handle server info
+ if (data.type === "server_info") {
+ serverInfo.value = data;
+ return;
+ }
+
+ // Handle system health
+ if (data.type === "system_health") {
+ systemHealth.value = data;
+ return;
+ }
+
+ // Handle regular messages
+ addMessage(data.type || "message", data, data.messageId);
+ } catch (error) {
+ addMessage(
+ "❌ Failed to parse message",
+ "error",
+ error instanceof Error ? error.message : String(error)
+ );
+ }
+ };
+
+ const getCloseReason = (code: number): string => {
+ switch (code) {
+ case 1000:
+ return "Normal closure";
+ case 1001:
+ return "Going away";
+ case 1002:
+ return "Protocol error";
+ case 1003:
+ return "Unsupported data";
+ case 1004:
+ return "Reserved";
+ case 1005:
+ return "No status received";
+ case 1006:
+ return "Abnormal closure";
+ case 1007:
+ return "Invalid frame payload data";
+ case 1008:
+ return "Policy violation";
+ case 1009:
+ return "Message too big";
+ case 1010:
+ return "Mandatory extension";
+ case 1011:
+ return "Internal server error";
+ case 1012:
+ return "Service restart";
+ case 1013:
+ return "Try again later";
+ case 1014:
+ return "Bad gateway";
+ case 1015:
+ return "TLS handshake";
+ default:
+ return "Unknown reason";
+ }
+ };
+
+ const isMessageLimitReached = computed(() => {
+ return messages.value.length >= config.maxMessages;
+ });
+
+ const shouldShowMessageWarning = computed(() => {
+ return messages.value.length >= config.messageWarningThreshold;
+ });
+
+ return {
+ // State
+ ws,
+ isConnected,
+ isConnecting,
+ connectionStatus,
+ connectionState,
+ config,
+ messages,
+ stats,
+ monitoringData,
+ onlineUsers,
+ activityLog,
+
+ // Admin state
+ serverInfo,
+ systemHealth,
+
+ // Methods
+ connect,
+ disconnect,
+ sendMessage,
+ broadcastMessage,
+ sendDirectMessage,
+ sendRoomMessage,
+ getServerInfo,
+ getOnlineUsers,
+ testConnection,
+ sendHeartbeat,
+ executeDatabaseQuery,
+ triggerNotification,
+ getStats,
+ getMonitoringData,
+ executeAdminCommand,
+ getSystemHealth,
+ clearMessages,
+ clearActivityLog,
+ getMessagesByType,
+ getRecentMessages,
+ cleanup,
+
+ // Computed
+ isMessageLimitReached,
+ shouldShowMessageWarning,
+ connectionHealthColor,
+ connectionHealthText,
+ };
+};
diff --git a/examples/clientsocket/composables/useWebSocket.ts.backup b/examples/clientsocket/composables/useWebSocket.ts.backup
new file mode 100644
index 0000000..e90e363
--- /dev/null
+++ b/examples/clientsocket/composables/useWebSocket.ts.backup
@@ -0,0 +1,318 @@
+import { ref, computed, reactive, nextTick } from 'vue'
+import type {
+ WebSocketMessage,
+ ConnectionState,
+ WebSocketConfig,
+ MessageHistory,
+ ConnectionStats,
+ MonitoringData,
+ ClientInfo,
+ OnlineUser,
+ ActivityLog
+} from '../types/websocket'
+
+export const useWebSocket = () => {
+ // Check if we're in browser environment
+ const isBrowser = process.client
+
+ const ws = ref(null)
+ const isConnected = ref(false)
+ const isConnecting = ref(false)
+ const connectionStatus = ref<'disconnected' | 'connecting' | 'connected' | 'error'>('disconnected')
+
+ const connectionState = reactive({
+ isConnected: false,
+ isConnecting: false,
+ connectionStatus: 'disconnected',
+ clientId: null,
+ staticId: null,
+ currentRoom: null,
+ userId: 'anonymous',
+ ipAddress: null,
+ connectionStartTime: null,
+ lastPingTime: null,
+ connectionLatency: 0,
+ connectionHealth: 'poor',
+ reconnectAttempts: 0,
+ messagesReceived: 0,
+ messagesSent: 0,
+ uptime: '00:00:00'
+ })
+
+ const config = reactive({
+ wsUrl: 'ws://localhost:8080/api/v1/ws',
+ userId: 'anonymous',
+ room: 'default',
+ staticId: '',
+ useIPBasedId: false,
+ autoReconnect: true,
+ heartbeatEnabled: true,
+ maxReconnectAttempts: 10,
+ reconnectDelay: 1000,
+ maxReconnectDelay: 30000,
+ heartbeatInterval: 30000,
+ heartbeatTimeout: 5000,
+ maxMissedHeartbeats: 3,
+ maxMessages: 1000,
+ messageWarningThreshold: 800,
+ actionThrottle: 100
+ })
+
+ const messages = ref([])
+ const stats = ref(null)
+ const monitoringData = ref(null)
+ const onlineUsers = ref([])
+ const activityLog = ref([])
+
+ let reconnectTimeout: number | null = null
+ let heartbeatInterval: number | null = null
+ let heartbeatTimeout: number | null = null
+ let missedHeartbeats = 0
+ let lastHeartbeatTime = 0
+ let messageCount = 0
+
+ // Only run WebSocket logic in browser
+ if (isBrowser) {
+ // WebSocket connection logic here
+ }
+
+ const addMessage = (type: string, data: any, messageId?: string) => {
+ if (!isBrowser) return
+
+ const message: MessageHistory = {
+ timestamp: new Date(),
+ type,
+ data,
+ messageId,
+ size: JSON.stringify(data).length
+ }
+
+ messages.value.unshift(message)
+ messageCount++
+
+ // Keep only the last maxMessages
+ if (messages.value.length > config.maxMessages) {
+ messages.value = messages.value.slice(0, config.maxMessages)
+ }
+
+ // Update connection state
+ connectionState.messagesReceived++
+ }
+
+ const connectionHealthColor = computed(() => {
+ switch (connectionState.connectionHealth) {
+ case 'excellent': return '#4CAF50'
+ case 'good': return '#2196F3'
+ case 'warning': return '#FFC107'
+ case 'poor': return '#F44336'
+ default: return '#9E9E9E'
+ }
+ })
+
+ const connectionHealthText = computed(() => {
+ switch (connectionState.connectionHealth) {
+ case 'excellent': return 'Excellent'
+ case 'good': return 'Good'
+ case 'warning': return 'Warning'
+ case 'poor': return 'Poor'
+ default: return 'Unknown'
+ }
+ })
+
+ // Admin functionality
+ const serverInfo = ref(null)
+ const systemHealth = ref(null)
+
+ const executeAdminCommand = async (command: string, params: any) => {
+ if (!isBrowser || !ws.value) throw new Error('Not connected')
+
+ const message = {
+ type: 'admin_command',
+ command,
+ params,
+ timestamp: Date.now()
+ }
+
+ ws.value.send(JSON.stringify(message))
+ return { success: true, message: 'Command sent successfully' }
+ }
+
+ const getServerInfo = async () => {
+ if (!isBrowser || !ws.value) throw new Error('Not connected')
+
+ const message = {
+ type: 'get_server_info',
+ timestamp: Date.now()
+ }
+
+ ws.value.send(JSON.stringify(message))
+ }
+
+ const getSystemHealth = async () => {
+ if (!isBrowser || !ws.value) throw new Error('Not connected')
+
+ const message = {
+ type: 'get_system_health',
+ timestamp: Date.now()
+ }
+
+ ws.value.send(JSON.stringify(message))
+ }
+
+ // Cleanup on unmount
+ const cleanup = () => {
+ if (!isBrowser) return
+
+ disconnect()
+ if (reconnectTimeout) {
+ clearTimeout(reconnectTimeout)
+ }
+ stopHeartbeat()
+ }
+
+ // WebSocket connection methods (only available in browser)
+ const connect = () => {
+ if (!isBrowser) return
+ // WebSocket connection logic
+ }
+
+ const disconnect = () => {
+ if (!isBrowser) return
+ // WebSocket disconnection logic
+ }
+
+ const sendMessage = (message: any) => {
+ if (!isBrowser || !ws.value) return
+ // Send message logic
+ }
+
+ const broadcastMessage = (message: string) => {
+ if (!isBrowser || !ws.value) return
+ // Broadcast message logic
+ }
+
+ const sendDirectMessage = (clientId: string, message: string) => {
+ if (!isBrowser || !ws.value) return
+ // Direct message logic
+ }
+
+ const sendRoomMessage = (room: string, message: string) => {
+ if (!isBrowser || !ws.value) return
+ // Room message logic
+ }
+
+ const getOnlineUsers = () => {
+ if (!isBrowser || !ws.value) return
+ // Get online users logic
+ }
+
+ const testConnection = () => {
+ if (!isBrowser || !ws.value) return
+ // Test connection logic
+ }
+
+ const sendHeartbeat = () => {
+ if (!isBrowser || !ws.value) return
+ // Send heartbeat logic
+ }
+
+ const executeDatabaseQuery = async (query: string) => {
+ if (!isBrowser || !ws.value) return
+ // Database query logic
+ }
+
+ const triggerNotification = async (message: string) => {
+ if (!isBrowser || !ws.value) return
+ // Notification logic
+ }
+
+ const getStats = () => {
+ if (!isBrowser || !ws.value) return
+ // Get stats logic
+ }
+
+ const getMonitoringData = () => {
+ if (!isBrowser || !ws.value) return
+ // Get monitoring data logic
+ }
+
+ const clearMessages = () => {
+ if (!isBrowser) return
+ messages.value = []
+ messageCount = 0
+ }
+
+ const clearActivityLog = () => {
+ if (!isBrowser) return
+ activityLog.value = []
+ }
+
+ const getMessagesByType = (type: string) => {
+ return messages.value.filter(msg => msg.type === type)
+ }
+
+ const getRecentMessages = (count: number = 10) => {
+ return messages.value.slice(0, count)
+ }
+
+ const stopHeartbeat = () => {
+ if (!isBrowser) return
+ // Stop heartbeat logic
+ }
+
+ const isMessageLimitReached = computed(() => {
+ return messages.value.length >= config.maxMessages
+ })
+
+ const shouldShowMessageWarning = computed(() => {
+ return messages.value.length >= config.messageWarningThreshold
+ })
+
+ return {
+ // State
+ ws,
+ isConnected,
+ isConnecting,
+ connectionStatus,
+ connectionState,
+ config,
+ messages,
+ stats,
+ monitoringData,
+ onlineUsers,
+ activityLog,
+
+ // Admin state
+ serverInfo,
+ systemHealth,
+
+ // Methods
+ connect,
+ disconnect,
+ sendMessage,
+ broadcastMessage,
+ sendDirectMessage,
+ sendRoomMessage,
+ getServerInfo,
+ getOnlineUsers,
+ testConnection,
+ sendHeartbeat,
+ executeDatabaseQuery,
+ triggerNotification,
+ getStats,
+ getMonitoringData,
+ executeAdminCommand,
+ getSystemHealth,
+ clearMessages,
+ clearActivityLog,
+ getMessagesByType,
+ getRecentMessages,
+ cleanup,
+
+ // Computed
+ isMessageLimitReached,
+ shouldShowMessageWarning,
+ connectionHealthColor,
+ connectionHealthText
+ }
+}
diff --git a/examples/clientsocket/nuxt.config.ts b/examples/clientsocket/nuxt.config.ts
new file mode 100644
index 0000000..dd716db
--- /dev/null
+++ b/examples/clientsocket/nuxt.config.ts
@@ -0,0 +1,22 @@
+export default defineNuxtConfig({
+ devtools: { enabled: true },
+ modules: [],
+ css: ['~/assets/css/main.css', 'vuetify/styles'],
+ build: {
+ transpile: ['vuetify']
+ },
+ runtimeConfig: {
+ public: {
+ wsUrl: 'ws://localhost:8080/api/v1/ws'
+ }
+ },
+ typescript: {
+ typeCheck: false
+ },
+ vite: {
+ define: {
+ global: 'globalThis'
+ }
+ },
+ compatibilityDate: '2024-04-03'
+})
diff --git a/examples/clientsocket/package-lock.json b/examples/clientsocket/package-lock.json
new file mode 100644
index 0000000..2723d6d
--- /dev/null
+++ b/examples/clientsocket/package-lock.json
@@ -0,0 +1,11504 @@
+{
+ "name": "nuxt3-websocket-client",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "nuxt3-websocket-client",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@mdi/font": "^7.3.67",
+ "@nuxtjs/vuetify": "^1.12.3",
+ "highlight.js": "^11.9.0",
+ "pinia": "^2.1.7",
+ "vue3-highlightjs": "^1.0.5",
+ "vuetify": "^3.4.0"
+ },
+ "devDependencies": {
+ "@nuxt/devtools": "latest",
+ "nuxt": "^3.8.0",
+ "vue": "^3.3.8",
+ "vue-router": "^4.2.5",
+ "vue-tsc": "^3.0.8"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
+ "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.27.1",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.1.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz",
+ "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz",
+ "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/generator": "^7.28.3",
+ "@babel/helper-compilation-targets": "^7.27.2",
+ "@babel/helper-module-transforms": "^7.28.3",
+ "@babel/helpers": "^7.28.4",
+ "@babel/parser": "^7.28.4",
+ "@babel/template": "^7.27.2",
+ "@babel/traverse": "^7.28.4",
+ "@babel/types": "^7.28.4",
+ "@jridgewell/remapping": "^2.3.5",
+ "convert-source-map": "^2.0.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.2.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/core/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.28.3",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz",
+ "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.28.3",
+ "@babel/types": "^7.28.2",
+ "@jridgewell/gen-mapping": "^0.3.12",
+ "@jridgewell/trace-mapping": "^0.3.28",
+ "jsesc": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-annotate-as-pure": {
+ "version": "7.27.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz",
+ "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.27.3"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
+ "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.27.2",
+ "@babel/helper-validator-option": "^7.27.1",
+ "browserslist": "^4.24.0",
+ "lru-cache": "^5.1.1",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin": {
+ "version": "7.28.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.3.tgz",
+ "integrity": "sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.27.3",
+ "@babel/helper-member-expression-to-functions": "^7.27.1",
+ "@babel/helper-optimise-call-expression": "^7.27.1",
+ "@babel/helper-replace-supers": "^7.27.1",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1",
+ "@babel/traverse": "^7.28.3",
+ "semver": "^6.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/helper-globals": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz",
+ "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-member-expression-to-functions": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz",
+ "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.27.1",
+ "@babel/types": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
+ "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.27.1",
+ "@babel/types": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.28.3",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz",
+ "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.27.1",
+ "@babel/traverse": "^7.28.3"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-optimise-call-expression": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz",
+ "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-plugin-utils": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz",
+ "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-replace-supers": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz",
+ "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-member-expression-to-functions": "^7.27.1",
+ "@babel/helper-optimise-call-expression": "^7.27.1",
+ "@babel/traverse": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz",
+ "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/traverse": "^7.27.1",
+ "@babel/types": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-string-parser": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
+ "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
+ "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz",
+ "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz",
+ "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.27.2",
+ "@babel/types": "^7.28.4"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz",
+ "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.28.4"
+ },
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-jsx": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz",
+ "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-syntax-typescript": {
+ "version": "7.27.1",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz",
+ "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-plugin-utils": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/plugin-transform-typescript": {
+ "version": "7.28.0",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.0.tgz",
+ "integrity": "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.27.3",
+ "@babel/helper-create-class-features-plugin": "^7.27.1",
+ "@babel/helper-plugin-utils": "^7.27.1",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1",
+ "@babel/plugin-syntax-typescript": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.27.2",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
+ "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/parser": "^7.27.2",
+ "@babel/types": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz",
+ "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/generator": "^7.28.3",
+ "@babel/helper-globals": "^7.28.0",
+ "@babel/parser": "^7.28.4",
+ "@babel/template": "^7.27.2",
+ "@babel/types": "^7.28.4",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.28.4",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz",
+ "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-string-parser": "^7.27.1",
+ "@babel/helper-validator-identifier": "^7.27.1"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@cloudflare/kv-asset-handler": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.4.0.tgz",
+ "integrity": "sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==",
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "dependencies": {
+ "mime": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@cloudflare/kv-asset-handler/node_modules/mime": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
+ "integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/@emnapi/core": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz",
+ "integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.1.0",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/runtime": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz",
+ "integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/wasi-threads": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz",
+ "integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.10.tgz",
+ "integrity": "sha512-0NFWnA+7l41irNuaSVlLfgNT12caWJVLzp5eAVhZ0z1qpxbockccEt3s+149rE64VUI3Ml2zt8Nv5JVc4QXTsw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.10.tgz",
+ "integrity": "sha512-dQAxF1dW1C3zpeCDc5KqIYuZ1tgAdRXNoZP7vkBIRtKZPYe2xVr/d3SkirklCHudW1B45tGiUlz2pUWDfbDD4w==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.10.tgz",
+ "integrity": "sha512-LSQa7eDahypv/VO6WKohZGPSJDq5OVOo3UoFR1E4t4Gj1W7zEQMUhI+lo81H+DtB+kP+tDgBp+M4oNCwp6kffg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.10.tgz",
+ "integrity": "sha512-MiC9CWdPrfhibcXwr39p9ha1x0lZJ9KaVfvzA0Wxwz9ETX4v5CHfF09bx935nHlhi+MxhA63dKRRQLiVgSUtEg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.10.tgz",
+ "integrity": "sha512-JC74bdXcQEpW9KkV326WpZZjLguSZ3DfS8wrrvPMHgQOIEIG/sPXEN/V8IssoJhbefLRcRqw6RQH2NnpdprtMA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.10.tgz",
+ "integrity": "sha512-tguWg1olF6DGqzws97pKZ8G2L7Ig1vjDmGTwcTuYHbuU6TTjJe5FXbgs5C1BBzHbJ2bo1m3WkQDbWO2PvamRcg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.10.tgz",
+ "integrity": "sha512-3ZioSQSg1HT2N05YxeJWYR+Libe3bREVSdWhEEgExWaDtyFbbXWb49QgPvFH8u03vUPX10JhJPcz7s9t9+boWg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.10.tgz",
+ "integrity": "sha512-LLgJfHJk014Aa4anGDbh8bmI5Lk+QidDmGzuC2D+vP7mv/GeSN+H39zOf7pN5N8p059FcOfs2bVlrRr4SK9WxA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.10.tgz",
+ "integrity": "sha512-oR31GtBTFYCqEBALI9r6WxoU/ZofZl962pouZRTEYECvNF/dtXKku8YXcJkhgK/beU+zedXfIzHijSRapJY3vg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.10.tgz",
+ "integrity": "sha512-5luJWN6YKBsawd5f9i4+c+geYiVEw20FVW5x0v1kEMWNq8UctFjDiMATBxLvmmHA4bf7F6hTRaJgtghFr9iziQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.10.tgz",
+ "integrity": "sha512-NrSCx2Kim3EnnWgS4Txn0QGt0Xipoumb6z6sUtl5bOEZIVKhzfyp/Lyw4C1DIYvzeW/5mWYPBFJU3a/8Yr75DQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.10.tgz",
+ "integrity": "sha512-xoSphrd4AZda8+rUDDfD9J6FUMjrkTz8itpTITM4/xgerAZZcFW7Dv+sun7333IfKxGG8gAq+3NbfEMJfiY+Eg==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.10.tgz",
+ "integrity": "sha512-ab6eiuCwoMmYDyTnyptoKkVS3k8fy/1Uvq7Dj5czXI6DF2GqD2ToInBI0SHOp5/X1BdZ26RKc5+qjQNGRBelRA==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.10.tgz",
+ "integrity": "sha512-NLinzzOgZQsGpsTkEbdJTCanwA5/wozN9dSgEl12haXJBzMTpssebuXR42bthOF3z7zXFWH1AmvWunUCkBE4EA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.10.tgz",
+ "integrity": "sha512-FE557XdZDrtX8NMIeA8LBJX3dC2M8VGXwfrQWU7LB5SLOajfJIxmSdyL/gU1m64Zs9CBKvm4UAuBp5aJ8OgnrA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.10.tgz",
+ "integrity": "sha512-3BBSbgzuB9ajLoVZk0mGu+EHlBwkusRmeNYdqmznmMc9zGASFjSsxgkNsqmXugpPk00gJ0JNKh/97nxmjctdew==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.10.tgz",
+ "integrity": "sha512-QSX81KhFoZGwenVyPoberggdW1nrQZSvfVDAIUXr3WqLRZGZqWk/P4T8p2SP+de2Sr5HPcvjhcJzEiulKgnxtA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.10.tgz",
+ "integrity": "sha512-AKQM3gfYfSW8XRk8DdMCzaLUFB15dTrZfnX8WXQoOUpUBQ+NaAFCP1kPS/ykbbGYz7rxn0WS48/81l9hFl3u4A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.10.tgz",
+ "integrity": "sha512-7RTytDPGU6fek/hWuN9qQpeGPBZFfB4zZgcz2VK2Z5VpdUxEI8JKYsg3JfO0n/Z1E/6l05n0unDCNc4HnhQGig==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.10.tgz",
+ "integrity": "sha512-5Se0VM9Wtq797YFn+dLimf2Zx6McttsH2olUBsDml+lm0GOCRVebRWUvDtkY4BWYv/3NgzS8b/UM3jQNh5hYyw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.10.tgz",
+ "integrity": "sha512-XkA4frq1TLj4bEMB+2HnI0+4RnjbuGZfet2gs/LNs5Hc7D89ZQBHQ0gL2ND6Lzu1+QVkjp3x1gIcPKzRNP8bXw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.10.tgz",
+ "integrity": "sha512-AVTSBhTX8Y/Fz6OmIVBip9tJzZEUcY8WLh7I59+upa5/GPhh2/aM6bvOMQySspnCCHvFi79kMtdJS1w0DXAeag==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.10.tgz",
+ "integrity": "sha512-fswk3XT0Uf2pGJmOpDB7yknqhVkJQkAQOcW/ccVOtfx05LkbWOaRAtn5SaqXypeKQra1QaEa841PgrSL9ubSPQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.10.tgz",
+ "integrity": "sha512-ah+9b59KDTSfpaCg6VdJoOQvKjI33nTaQr4UluQwW7aEwZQsbMCfTmfEO4VyewOxx4RaDT/xCy9ra2GPWmO7Kw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.10.tgz",
+ "integrity": "sha512-QHPDbKkrGO8/cz9LKVnJU22HOi4pxZnZhhA2HYHez5Pz4JeffhDjf85E57Oyco163GnzNCVkZK0b/n4Y0UHcSw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.10.tgz",
+ "integrity": "sha512-9KpxSVFCu0iK1owoez6aC/s/EdUQLDN3adTxGCqxMVhrPDj6bt5dbrHDXUuq+Bs2vATFBBrQS5vdQ/Ed2P+nbw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@ioredis/commands": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.4.0.tgz",
+ "integrity": "sha512-aFT2yemJJo+TZCmieA7qnYGQooOS7QfNmYrzGtsYd3g9j5iDP8AimYYAesf79ohjbLG12XxC4nG5DyEnC88AsQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@isaacs/cliui": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+ "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^5.1.2",
+ "string-width-cjs": "npm:string-width@^4.2.0",
+ "strip-ansi": "^7.0.1",
+ "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+ "wrap-ansi": "^8.1.0",
+ "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/@isaacs/fs-minipass": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
+ "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "minipass": "^7.0.4"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/remapping": {
+ "version": "2.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz",
+ "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/source-map": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz",
+ "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@kwsites/file-exists": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz",
+ "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.1.1"
+ }
+ },
+ "node_modules/@kwsites/promise-deferred": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz",
+ "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@mapbox/node-pre-gyp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-2.0.0.tgz",
+ "integrity": "sha512-llMXd39jtP0HpQLVI37Bf1m2ADlEb35GYSh1SDSLsBhR+5iCxiNGlT31yqbNtVHygHAtMy6dWFERpU2JgufhPg==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "consola": "^3.2.3",
+ "detect-libc": "^2.0.0",
+ "https-proxy-agent": "^7.0.5",
+ "node-fetch": "^2.6.7",
+ "nopt": "^8.0.0",
+ "semver": "^7.5.3",
+ "tar": "^7.4.0"
+ },
+ "bin": {
+ "node-pre-gyp": "bin/node-pre-gyp"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@mapbox/node-pre-gyp/node_modules/detect-libc": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.0.tgz",
+ "integrity": "sha512-vEtk+OcP7VBRtQZ1EJ3bdgzSfBjgnEalLTp5zjJrS+2Z1w2KZly4SBdac/WDU3hhsNAZ9E8SC96ME4Ey8MZ7cg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@mdi/font": {
+ "version": "7.4.47",
+ "resolved": "https://registry.npmjs.org/@mdi/font/-/font-7.4.47.tgz",
+ "integrity": "sha512-43MtGpd585SNzHZPcYowu/84Vz2a2g31TvPMTm9uTiCSWzaheQySUcSyUH/46fPnuPQWof2yd0pGBtzee/IQWw==",
+ "license": "Apache-2.0"
+ },
+ "node_modules/@napi-rs/wasm-runtime": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.5.tgz",
+ "integrity": "sha512-TBr9Cf9onSAS2LQ2+QHx6XcC6h9+RIzJgbqG3++9TUZSH204AwEy5jg3BTQ0VATsyoGj4ee49tN/y6rvaOOtcg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.5.0",
+ "@emnapi/runtime": "^1.5.0",
+ "@tybys/wasm-util": "^0.10.1"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+ "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+ "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+ "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nuxt/cli": {
+ "version": "3.28.0",
+ "resolved": "https://registry.npmjs.org/@nuxt/cli/-/cli-3.28.0.tgz",
+ "integrity": "sha512-WQ751WxWLBIeH3TDFt/LWQ2znyAKxpR5+gpv80oerwnVQs4GKajAfR6dIgExXZkjaPUHEFv2lVD9vM+frbprzw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "c12": "^3.2.0",
+ "citty": "^0.1.6",
+ "clipboardy": "^4.0.0",
+ "confbox": "^0.2.2",
+ "consola": "^3.4.2",
+ "defu": "^6.1.4",
+ "exsolve": "^1.0.7",
+ "fuse.js": "^7.1.0",
+ "get-port-please": "^3.2.0",
+ "giget": "^2.0.0",
+ "h3": "^1.15.4",
+ "httpxy": "^0.1.7",
+ "jiti": "^2.5.1",
+ "listhen": "^1.9.0",
+ "nypm": "^0.6.1",
+ "ofetch": "^1.4.1",
+ "ohash": "^2.0.11",
+ "pathe": "^2.0.3",
+ "perfect-debounce": "^1.0.0",
+ "pkg-types": "^2.2.0",
+ "scule": "^1.3.0",
+ "semver": "^7.7.2",
+ "std-env": "^3.9.0",
+ "tinyexec": "^1.0.1",
+ "ufo": "^1.6.1",
+ "youch": "^4.1.0-beta.11"
+ },
+ "bin": {
+ "nuxi": "bin/nuxi.mjs",
+ "nuxi-ng": "bin/nuxi.mjs",
+ "nuxt": "bin/nuxi.mjs",
+ "nuxt-cli": "bin/nuxi.mjs"
+ },
+ "engines": {
+ "node": "^16.10.0 || >=18.0.0"
+ }
+ },
+ "node_modules/@nuxt/cli/node_modules/perfect-debounce": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
+ "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@nuxt/devalue": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@nuxt/devalue/-/devalue-2.0.2.tgz",
+ "integrity": "sha512-GBzP8zOc7CGWyFQS6dv1lQz8VVpz5C2yRszbXufwG/9zhStTIH50EtD87NmWbTMwXDvZLNg8GIpb1UFdH93JCA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@nuxt/devtools": {
+ "version": "2.6.5",
+ "resolved": "https://registry.npmjs.org/@nuxt/devtools/-/devtools-2.6.5.tgz",
+ "integrity": "sha512-Xh9XF1SzCTL5Zj6EULqsN2UjiNj4zWuUpS69rGAy5C55UTaj+Wn46IkDc6Q0+EKkGI279zlG6SzPRFawqPPUEw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nuxt/devtools-kit": "2.6.5",
+ "@nuxt/devtools-wizard": "2.6.5",
+ "@nuxt/kit": "^3.19.2",
+ "@vue/devtools-core": "^7.7.7",
+ "@vue/devtools-kit": "^7.7.7",
+ "birpc": "^2.5.0",
+ "consola": "^3.4.2",
+ "destr": "^2.0.5",
+ "error-stack-parser-es": "^1.0.5",
+ "execa": "^8.0.1",
+ "fast-npm-meta": "^0.4.6",
+ "get-port-please": "^3.2.0",
+ "hookable": "^5.5.3",
+ "image-meta": "^0.2.1",
+ "is-installed-globally": "^1.0.0",
+ "launch-editor": "^2.11.1",
+ "local-pkg": "^1.1.2",
+ "magicast": "^0.3.5",
+ "nypm": "^0.6.2",
+ "ohash": "^2.0.11",
+ "pathe": "^2.0.3",
+ "perfect-debounce": "^1.0.0",
+ "pkg-types": "^2.3.0",
+ "semver": "^7.7.2",
+ "simple-git": "^3.28.0",
+ "sirv": "^3.0.2",
+ "structured-clone-es": "^1.0.0",
+ "tinyglobby": "^0.2.15",
+ "vite-plugin-inspect": "^11.3.3",
+ "vite-plugin-vue-tracer": "^1.0.0",
+ "which": "^5.0.0",
+ "ws": "^8.18.3"
+ },
+ "bin": {
+ "devtools": "cli.mjs"
+ },
+ "peerDependencies": {
+ "vite": ">=6.0"
+ }
+ },
+ "node_modules/@nuxt/devtools-kit": {
+ "version": "2.6.5",
+ "resolved": "https://registry.npmjs.org/@nuxt/devtools-kit/-/devtools-kit-2.6.5.tgz",
+ "integrity": "sha512-t+NxoENyzJ8KZDrnbVYv3FJI5VXqSi6X4w6ZsuIIh0aKABu6+6k9nR/LoEhrM0oekn/2LDhA0NmsRZyzCXt2xQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nuxt/kit": "^3.19.2",
+ "execa": "^8.0.1"
+ },
+ "peerDependencies": {
+ "vite": ">=6.0"
+ }
+ },
+ "node_modules/@nuxt/devtools-wizard": {
+ "version": "2.6.5",
+ "resolved": "https://registry.npmjs.org/@nuxt/devtools-wizard/-/devtools-wizard-2.6.5.tgz",
+ "integrity": "sha512-nYYGxT4lmQDvfHL6qolNWLu0QTavsdN/98F57falPuvdgs5ev1NuYsC12hXun+5ENcnigEcoM9Ij92qopBgqmQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "consola": "^3.4.2",
+ "diff": "^8.0.2",
+ "execa": "^8.0.1",
+ "magicast": "^0.3.5",
+ "pathe": "^2.0.3",
+ "pkg-types": "^2.3.0",
+ "prompts": "^2.4.2",
+ "semver": "^7.7.2"
+ },
+ "bin": {
+ "devtools-wizard": "cli.mjs"
+ }
+ },
+ "node_modules/@nuxt/devtools/node_modules/perfect-debounce": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
+ "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@nuxt/kit": {
+ "version": "3.19.2",
+ "resolved": "https://registry.npmjs.org/@nuxt/kit/-/kit-3.19.2.tgz",
+ "integrity": "sha512-+QiqO0WcIxsKLUqXdVn3m4rzTRm2fO9MZgd330utCAaagGmHsgiMJp67kE14boJEPutnikfz3qOmrzBnDIHUUg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "c12": "^3.2.0",
+ "consola": "^3.4.2",
+ "defu": "^6.1.4",
+ "destr": "^2.0.5",
+ "errx": "^0.1.0",
+ "exsolve": "^1.0.7",
+ "ignore": "^7.0.5",
+ "jiti": "^2.5.1",
+ "klona": "^2.0.6",
+ "knitwork": "^1.2.0",
+ "mlly": "^1.8.0",
+ "ohash": "^2.0.11",
+ "pathe": "^2.0.3",
+ "pkg-types": "^2.3.0",
+ "rc9": "^2.1.2",
+ "scule": "^1.3.0",
+ "semver": "^7.7.2",
+ "std-env": "^3.9.0",
+ "tinyglobby": "^0.2.15",
+ "ufo": "^1.6.1",
+ "unctx": "^2.4.1",
+ "unimport": "^5.2.0",
+ "untyped": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18.12.0"
+ }
+ },
+ "node_modules/@nuxt/telemetry": {
+ "version": "2.6.6",
+ "resolved": "https://registry.npmjs.org/@nuxt/telemetry/-/telemetry-2.6.6.tgz",
+ "integrity": "sha512-Zh4HJLjzvm3Cq9w6sfzIFyH9ozK5ePYVfCUzzUQNiZojFsI2k1QkSBrVI9BGc6ArKXj/O6rkI6w7qQ+ouL8Cag==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nuxt/kit": "^3.15.4",
+ "citty": "^0.1.6",
+ "consola": "^3.4.2",
+ "destr": "^2.0.3",
+ "dotenv": "^16.4.7",
+ "git-url-parse": "^16.0.1",
+ "is-docker": "^3.0.0",
+ "ofetch": "^1.4.1",
+ "package-manager-detector": "^1.1.0",
+ "pathe": "^2.0.3",
+ "rc9": "^2.1.2",
+ "std-env": "^3.8.1"
+ },
+ "bin": {
+ "nuxt-telemetry": "bin/nuxt-telemetry.mjs"
+ },
+ "engines": {
+ "node": ">=18.12.0"
+ }
+ },
+ "node_modules/@nuxt/vite-builder": {
+ "version": "3.19.2",
+ "resolved": "https://registry.npmjs.org/@nuxt/vite-builder/-/vite-builder-3.19.2.tgz",
+ "integrity": "sha512-SESdHAKWy63RKG3uqrBEJvTbfkmEsiggmDEqjEwhBP2fe0E6bGTmLpX/Eh4AuOLbZuZOmir984OHFiM/Q/MLhg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nuxt/kit": "3.19.2",
+ "@rollup/plugin-replace": "^6.0.2",
+ "@vitejs/plugin-vue": "^6.0.1",
+ "@vitejs/plugin-vue-jsx": "^5.1.1",
+ "autoprefixer": "^10.4.21",
+ "consola": "^3.4.2",
+ "cssnano": "^7.1.1",
+ "defu": "^6.1.4",
+ "esbuild": "^0.25.9",
+ "escape-string-regexp": "^5.0.0",
+ "exsolve": "^1.0.7",
+ "externality": "^1.0.2",
+ "get-port-please": "^3.2.0",
+ "h3": "^1.15.4",
+ "jiti": "^2.5.1",
+ "knitwork": "^1.2.0",
+ "magic-string": "^0.30.19",
+ "mlly": "^1.8.0",
+ "mocked-exports": "^0.1.1",
+ "ohash": "^2.0.11",
+ "pathe": "^2.0.3",
+ "perfect-debounce": "^2.0.0",
+ "pkg-types": "^2.3.0",
+ "postcss": "^8.5.6",
+ "rollup-plugin-visualizer": "^6.0.3",
+ "std-env": "^3.9.0",
+ "ufo": "^1.6.1",
+ "unenv": "^2.0.0-rc.21",
+ "vite": "^7.1.5",
+ "vite-node": "^3.2.4",
+ "vite-plugin-checker": "^0.10.3",
+ "vue-bundle-renderer": "^2.1.2"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "peerDependencies": {
+ "vue": "^3.3.4"
+ }
+ },
+ "node_modules/@nuxtjs/vuetify": {
+ "version": "1.12.3",
+ "resolved": "https://registry.npmjs.org/@nuxtjs/vuetify/-/vuetify-1.12.3.tgz",
+ "integrity": "sha512-6uVL3cfESMB00eVjJTNkyU4jvuPTGPn1yteo7lQTH6v+fxHcPaOgvzVYHIKSHIz1DecuOiB5c9b+YjsRP5+C8A==",
+ "license": "MIT",
+ "dependencies": {
+ "deepmerge": "^4.2.2",
+ "sass": "~1.32.13",
+ "sass-loader": "^10.2.0",
+ "vuetify": "^2.6",
+ "vuetify-loader": "^1.7.3"
+ }
+ },
+ "node_modules/@nuxtjs/vuetify/node_modules/@vue/compiler-sfc": {
+ "version": "2.7.16",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.16.tgz",
+ "integrity": "sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==",
+ "peer": true,
+ "dependencies": {
+ "@babel/parser": "^7.23.5",
+ "postcss": "^8.4.14",
+ "source-map": "^0.6.1"
+ },
+ "optionalDependencies": {
+ "prettier": "^1.18.2 || ^2.0.0"
+ }
+ },
+ "node_modules/@nuxtjs/vuetify/node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "license": "MIT",
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/@nuxtjs/vuetify/node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/@nuxtjs/vuetify/node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "license": "MIT",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/@nuxtjs/vuetify/node_modules/sass": {
+ "version": "1.32.13",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.32.13.tgz",
+ "integrity": "sha512-dEgI9nShraqP7cXQH+lEXVf73WOPCse0QlFzSD8k+1TcOxCMwVXfQlr0jtoluZysQOyJGnfr21dLvYKDJq8HkA==",
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": ">=3.0.0 <4.0.0"
+ },
+ "bin": {
+ "sass": "sass.js"
+ },
+ "engines": {
+ "node": ">=8.9.0"
+ }
+ },
+ "node_modules/@nuxtjs/vuetify/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "license": "BSD-3-Clause",
+ "peer": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/@nuxtjs/vuetify/node_modules/vue": {
+ "version": "2.7.16",
+ "resolved": "https://registry.npmjs.org/vue/-/vue-2.7.16.tgz",
+ "integrity": "sha512-4gCtFXaAA3zYZdTp5s4Hl2sozuySsgz4jy1EnpBHNfpMa9dK1ZCG7viqBPCwXtmgc8nHqUsAu3G4gtmXkkY3Sw==",
+ "deprecated": "Vue 2 has reached EOL and is no longer actively maintained. See https://v2.vuejs.org/eol/ for more details.",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@vue/compiler-sfc": "2.7.16",
+ "csstype": "^3.1.0"
+ }
+ },
+ "node_modules/@nuxtjs/vuetify/node_modules/vuetify": {
+ "version": "2.6.13",
+ "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-2.6.13.tgz",
+ "integrity": "sha512-HhJi52IzhfrmWFwcYFUiA1GRIzz9smbR06Lj61Ml5HgD5PBcMiDywUnNPVid1VsXO4qWpBU6kO3O89uTxH1yzw==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/johnleider"
+ },
+ "peerDependencies": {
+ "vue": "^2.6.4"
+ }
+ },
+ "node_modules/@nuxtjs/vuetify/node_modules/vuetify-loader": {
+ "version": "1.9.2",
+ "resolved": "https://registry.npmjs.org/vuetify-loader/-/vuetify-loader-1.9.2.tgz",
+ "integrity": "sha512-8PP2w7aAs/rjA+Izec6qY7sHVb75MNrGQrDOTZJ5IEnvl+NiFhVpU2iWdRDZ3eMS842cWxSWStvkr+KJJKy+Iw==",
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.4.1",
+ "acorn-walk": "^8.2.0",
+ "decache": "^4.6.0",
+ "file-loader": "^6.2.0",
+ "loader-utils": "^2.0.0"
+ },
+ "peerDependencies": {
+ "gm": "^1.23.0",
+ "pug": "^2.0.0 || ^3.0.0",
+ "sharp": "*",
+ "vue": "^2.7.2",
+ "vuetify": "^1.3.0 || ^2.0.0",
+ "webpack": "^4.0.0 || ^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "gm": {
+ "optional": true
+ },
+ "pug": {
+ "optional": true
+ },
+ "sharp": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@oxc-minify/binding-android-arm64": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-minify/binding-android-arm64/-/binding-android-arm64-0.87.0.tgz",
+ "integrity": "sha512-ZbJmAfXvNAamOSnXId3BiM3DiuzlD1isqKjtmRFb/hpvChHHA23FSPrFcO16w+ugZKg33sZ93FinFkKtlC4hww==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-minify/binding-darwin-arm64": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-minify/binding-darwin-arm64/-/binding-darwin-arm64-0.87.0.tgz",
+ "integrity": "sha512-ewmNsTY8YbjWOI8+EOWKTVATOYvG4Qq4zQHH5VFBeqhQPVusY1ORD6Ei+BijVKrnlbpjibLlkTl8IWqXCGK89A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-minify/binding-darwin-x64": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-minify/binding-darwin-x64/-/binding-darwin-x64-0.87.0.tgz",
+ "integrity": "sha512-qDH4w4EYttSC3Cs2VCh+CiMYKrcL2SNmnguBZXoUXe/RNk3csM+RhgcwdpX687xGvOhTFhH5PCIA84qh3ZpIbQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-minify/binding-freebsd-x64": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-minify/binding-freebsd-x64/-/binding-freebsd-x64-0.87.0.tgz",
+ "integrity": "sha512-5kxjHlSev2A09rDeITk+LMHxSrU3Iu8pUb0Zp4m+ul8FKlB9FrvFkAYwbctin6g47O98s3Win7Ewhy0w8JaiUA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-minify/binding-linux-arm-gnueabihf": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.87.0.tgz",
+ "integrity": "sha512-NjbGXnNaAl5EgyonaDg2cPyH2pTf5a/+AP/5SRCJ0KetpXV22ZSUCvcy04Yt4QqjMcDs+WnJaGVxwx15Ofr6Gw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-minify/binding-linux-arm-musleabihf": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.87.0.tgz",
+ "integrity": "sha512-llAjfCA0iV2LMMl+LTR3JhqAc2iQmj+DTKd0VWOrbNOuNczeE9D5kJFkqYplD73LrkuqxrX9oDeUjjeLdVBPXw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-minify/binding-linux-arm64-gnu": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.87.0.tgz",
+ "integrity": "sha512-tf2Shom09AaSmu7U1hYYcEFF/cd+20HtmQ8eyGsRkqD5bqUj6lDu8TNSU9FWZ9tcZ83NzyFMwXZWHyeeIIbpxw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-minify/binding-linux-arm64-musl": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.87.0.tgz",
+ "integrity": "sha512-pgWeYfSprtpnJVea9Q5eI6Eo80lDGlMw2JdcSMXmShtBjEhBl6bvDNHlV+6kNfh7iT65y/uC6FR8utFrRghu8A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-minify/binding-linux-riscv64-gnu": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.87.0.tgz",
+ "integrity": "sha512-O1QPczlT+lqNZVeKOdFxxL+s1RIlnixaJYFLrcqDcRyn82MGKLz7sAenBTFRQoIfLnSxtMGL6dqHOefYkQx7Cg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-minify/binding-linux-s390x-gnu": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.87.0.tgz",
+ "integrity": "sha512-tcwt3ZUWOKfNLXN2edxFVHMlIuPvbuyMaKmRopgljSCfFcNHWhfTNlxlvmECRNhuQ91EcGwte6F1dwoeMCNd7A==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-minify/binding-linux-x64-gnu": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.87.0.tgz",
+ "integrity": "sha512-Xf4AXF14KXUzSnfgTcFLFSM0TykJhFw14+xwNvlAb6WdqXAKlMrz9joIAezc8dkW1NNscCVTsqBUPJ4RhvCM1Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-minify/binding-linux-x64-musl": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-minify/binding-linux-x64-musl/-/binding-linux-x64-musl-0.87.0.tgz",
+ "integrity": "sha512-LIqvpx9UihEW4n9QbEljDnfUdAWqhr6dRqmzSFwVAeLZRUECluLCDdsdwemrC/aZkvnisA4w0LFcFr3HmeTLJg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-minify/binding-wasm32-wasi": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-minify/binding-wasm32-wasi/-/binding-wasm32-wasi-0.87.0.tgz",
+ "integrity": "sha512-h0xluvc+YryfH5G5dndjGHuA/D4Kp85EkPMxqoOjNudOKDCtdobEaC9horhCqnOOQ0lgn+PGFl3w8u4ToOuRrA==",
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@napi-rs/wasm-runtime": "^1.0.3"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-minify/binding-win32-arm64-msvc": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.87.0.tgz",
+ "integrity": "sha512-fgxSx+TUc7e2rNtRAMnhHrjqh1e8p/JKmWxRZXtkILveMr/TOHGiDis7U3JJbwycmTZ+HSsJ/PNFQl+tKzmDxw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-minify/binding-win32-x64-msvc": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-minify/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.87.0.tgz",
+ "integrity": "sha512-K6TTrlitEJgD0FGIW2r0t3CIJNqBkzHT97h49gZLS24ey2UG1zKt27iSHkpXMJYDiG97ZD2yv3pSph1ctMlFXw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-android-arm64": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-android-arm64/-/binding-android-arm64-0.87.0.tgz",
+ "integrity": "sha512-3APxTyYaAjpW5zifjzfsPgoIa4YHwA5GBjtgLRQpGVXCykXBIEbUTokoAs411ZuOwS3sdTVXBTGAdziXRd8rUg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-darwin-arm64": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.87.0.tgz",
+ "integrity": "sha512-99e8E76M+k3Gtwvs5EU3VTs2hQkJmvnrl/eu7HkBUc9jLFHA4nVjYSgukMuqahWe270udUYEPRfcWKmoE1Nukg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-darwin-x64": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-darwin-x64/-/binding-darwin-x64-0.87.0.tgz",
+ "integrity": "sha512-2rRo6Dz560/4ot5Q0KPUTEunEObkP8mDC9mMiH0RJk1FiOb9c+xpPbkYoUHNKuVMm8uIoiBCxIAbPtBhs9QaXQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-freebsd-x64": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.87.0.tgz",
+ "integrity": "sha512-uR+WZAvWkFQPVoeqXgQFr7iy+3hEI295qTbQ4ujmklgM5eTX3YgMFoIV00Stloxfd1irSDDSaK7ySnnzF6mRJg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-linux-arm-gnueabihf": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.87.0.tgz",
+ "integrity": "sha512-Emm1NpVGKbwzQOIZJI8ZuZu0z8FAd5xscqdS6qpDFpDdEMxk6ab7o3nM8V09RhNCORAzeUlk4TBHQ2Crzjd50A==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-linux-arm-musleabihf": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.87.0.tgz",
+ "integrity": "sha512-1PPCxRZSJXzQaqc8y+wH7EqPgSfQ/JU3pK6WTN/1SUe/8paNVSKKqk175a8BbRVxGUtPnwEG89pi+xfPTSE7GA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-linux-arm64-gnu": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.87.0.tgz",
+ "integrity": "sha512-fcnnsfcyLamJOMVKq+BQ8dasb8gRnZtNpCUfZhaEFAdXQ7J2RmZreFzlygcn80iti0V7c5LejcjHbF4IdK3GAw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-linux-arm64-musl": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.87.0.tgz",
+ "integrity": "sha512-tBPkSPgRSSbmrje8CUovISi/Hj/tWjZJ3n/qnrjx2B+u86hWtwLsngtPDQa5d4seSyDaHSx6tNEUcH7+g5Ee0Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-linux-riscv64-gnu": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.87.0.tgz",
+ "integrity": "sha512-z4UKGM4wv2wEAQAlx2pBq6+pDJw5J/5oDEXqW6yBSLbWLjLDo4oagmRSE3+giOWteUa+0FVJ+ypq4iYxBkYSWg==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-linux-s390x-gnu": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.87.0.tgz",
+ "integrity": "sha512-6W1ENe/nZtr2TBnrEzmdGEraEAdZOiH3YoUNNeQWuqwLkmpoHTJJdclieToPe/l2IKJ4WL3FsSLSGHE8yt/OEg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-linux-x64-gnu": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.87.0.tgz",
+ "integrity": "sha512-s3kB/Ii3X3IOZ27Iu7wx2zYkIcDO22Emu32SNC6kkUSy09dPBc1yaW14TnAkPMe/rvtuzR512JPWj3iGpl+Dng==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-linux-x64-musl": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.87.0.tgz",
+ "integrity": "sha512-3+M9hfrZSDi4+Uy4Ll3rtOuVG3IHDQlj027jgtmAAHJK1eqp4CQfC7rrwE+LFUqUwX+KD2GwlxR+eHyyEf5Gbg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-wasm32-wasi": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-wasm32-wasi/-/binding-wasm32-wasi-0.87.0.tgz",
+ "integrity": "sha512-2jgeEeOa4GbQQg2Et/gFTgs5wKS/+CxIg+CN2mMOJ4EqbmvUVeGiumO01oFOWTYnJy1oONwIocBzrnMuvOcItA==",
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@napi-rs/wasm-runtime": "^1.0.3"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-win32-arm64-msvc": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.87.0.tgz",
+ "integrity": "sha512-KZp9poaBaVvuFM0TrsHCDOjPQK5eMDXblz21boMhKHGW5/bOlkMlg3CYn5j0f67FkK68NSdNKREMxmibBeXllQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@oxc-parser/binding-win32-x64-msvc": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-parser/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.87.0.tgz",
+ "integrity": "sha512-86uisngtp/8XdcerIKxMyJTqgDSTJatkfpylpUH0d96W8Bb9E+bVvM2fIIhLWB0Eb03PeY2BdIT7DNIln9TnHg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=20.0.0"
+ }
+ },
+ "node_modules/@oxc-project/types": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.87.0.tgz",
+ "integrity": "sha512-ipZFWVGE9fADBVXXWJWY/cxpysc41Gt5upKDeb32F6WMgFyO7XETUMVq8UuREKCih+Km5E6p2VhEvf6Fuhey6g==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/Boshen"
+ }
+ },
+ "node_modules/@oxc-transform/binding-android-arm64": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-transform/binding-android-arm64/-/binding-android-arm64-0.87.0.tgz",
+ "integrity": "sha512-B7W6J8T9cS054LUGLfYkYz8bz5+t+4yPftZ67Bn6MJ03okMLnbbEfm1bID1tqcP5tJwMurTILVy/dQfDYDcMgQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-transform/binding-darwin-arm64": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-arm64/-/binding-darwin-arm64-0.87.0.tgz",
+ "integrity": "sha512-HImW3xOPx7FHKqfC5WfE82onhRfnWQUiB7R+JgYrk+7NR404h3zANSPzu3V/W9lbDxlmHTcqoD2LKbNC5j0TQA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-transform/binding-darwin-x64": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-transform/binding-darwin-x64/-/binding-darwin-x64-0.87.0.tgz",
+ "integrity": "sha512-MDbgugi6mvuPTfS78E2jyozm7493Kuqmpc5r406CsUdEsXlnsF+xvmKlrW9ZIkisO74dD+HWouSiDtNyPQHjlw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-transform/binding-freebsd-x64": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-transform/binding-freebsd-x64/-/binding-freebsd-x64-0.87.0.tgz",
+ "integrity": "sha512-N0M5D/4haJw7BMn2WZ3CWz0WkdLyoK1+3KxOyCv2CPedMCxx6eQay2AtJxSzj9tjVU1+ukbSb2fDO24JIJGsVA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-transform/binding-linux-arm-gnueabihf": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.87.0.tgz",
+ "integrity": "sha512-PubObCNOUOzm1S+P0yn7S+/6xRLbSPMqhgrb73L3p+J1Z20fv/FYVg0kFd36Yho24TSC/byOkebEZWAtxCasWw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-transform/binding-linux-arm-musleabihf": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.87.0.tgz",
+ "integrity": "sha512-Nk2d/FS7sMCmCl99vHojzigakjDPamkjOXs2i+H71o/NqytS0pk3M+tXat8M3IGpeLJIEszA5Mv+dcq731nlYA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-transform/binding-linux-arm64-gnu": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.87.0.tgz",
+ "integrity": "sha512-BxFkIcso2V1+FCDoU+KctxvJzSQVSnEZ5EEQ8O3Up9EoFVQRnZ8ktXvqYj2Oqvc4IYPskLPsKUgc9gdK8wGhUg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-transform/binding-linux-arm64-musl": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.87.0.tgz",
+ "integrity": "sha512-MZ1/TNaebhXK73j1UDfwyBFnAy0tT3n6otOkhlt1vlJwqboUS/D7E/XrCZmAuHIfVPxAXRPovkl7kfxLB43SKw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-transform/binding-linux-riscv64-gnu": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.87.0.tgz",
+ "integrity": "sha512-JCWE6n4Hicu0FVbvmLdH/dS8V6JykOUsbrbDYm6JwFlHr4eFTTlS2B+mh5KPOxcdeOlv/D/XRnvMJ6WGYs25EA==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-transform/binding-linux-s390x-gnu": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.87.0.tgz",
+ "integrity": "sha512-n2NTgM+3PqFagJV9UXRDNOmYesF+TO9SF9FeHqwVmW893ayef9KK+vfWAAhvOYHXYaKWT5XoHd87ODD7nruyhw==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-transform/binding-linux-x64-gnu": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.87.0.tgz",
+ "integrity": "sha512-ZOKW3wx0bW2O7jGdOzr8DyLZqX2C36sXvJdsHj3IueZZ//d/NjLZqEiUKz+q0JlERHtCVKShQ5PLaCx7NpuqNg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-transform/binding-linux-x64-musl": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-transform/binding-linux-x64-musl/-/binding-linux-x64-musl-0.87.0.tgz",
+ "integrity": "sha512-eIspx/JqkVMPK1CAYEOo2J8o49s4ZTf+32MSMUknIN2ZS1fvRmWS0D/xFFaLP/9UGhdrXRIPbn/iSYEA8JnV/g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-transform/binding-wasm32-wasi": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-transform/binding-wasm32-wasi/-/binding-wasm32-wasi-0.87.0.tgz",
+ "integrity": "sha512-4uRjJQnt/+kmJUIC6Iwzn+MqqZhLP1zInPtDwgL37KI4VuUewUQWoL+sggMssMEgm7ZJwOPoZ6piuSWwMgOqgQ==",
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@napi-rs/wasm-runtime": "^1.0.3"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-transform/binding-win32-arm64-msvc": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.87.0.tgz",
+ "integrity": "sha512-l/qSi4/N5W1yXKU9+1gWGo0tBoRpp4zvHYrpsbq3zbefPL4VYdA0gKF7O10/ZQVkYylzxiVh2zpYO34/FbZdIg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@oxc-transform/binding-win32-x64-msvc": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/@oxc-transform/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.87.0.tgz",
+ "integrity": "sha512-jG/MhMjfSdyj5KyhnwNWr4mnAlAsz+gNUYpjQ+UXWsfsoB3f8HqbsTkG02RBtNa/IuVQYvYYVf1eIimNN3gBEQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@parcel/watcher": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz",
+ "integrity": "sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "detect-libc": "^1.0.3",
+ "is-glob": "^4.0.3",
+ "micromatch": "^4.0.5",
+ "node-addon-api": "^7.0.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "@parcel/watcher-android-arm64": "2.5.1",
+ "@parcel/watcher-darwin-arm64": "2.5.1",
+ "@parcel/watcher-darwin-x64": "2.5.1",
+ "@parcel/watcher-freebsd-x64": "2.5.1",
+ "@parcel/watcher-linux-arm-glibc": "2.5.1",
+ "@parcel/watcher-linux-arm-musl": "2.5.1",
+ "@parcel/watcher-linux-arm64-glibc": "2.5.1",
+ "@parcel/watcher-linux-arm64-musl": "2.5.1",
+ "@parcel/watcher-linux-x64-glibc": "2.5.1",
+ "@parcel/watcher-linux-x64-musl": "2.5.1",
+ "@parcel/watcher-win32-arm64": "2.5.1",
+ "@parcel/watcher-win32-ia32": "2.5.1",
+ "@parcel/watcher-win32-x64": "2.5.1"
+ }
+ },
+ "node_modules/@parcel/watcher-android-arm64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz",
+ "integrity": "sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-darwin-arm64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz",
+ "integrity": "sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-darwin-x64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz",
+ "integrity": "sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-freebsd-x64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz",
+ "integrity": "sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm-glibc": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz",
+ "integrity": "sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm-musl": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz",
+ "integrity": "sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm64-glibc": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz",
+ "integrity": "sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-arm64-musl": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz",
+ "integrity": "sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-x64-glibc": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz",
+ "integrity": "sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-linux-x64-musl": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz",
+ "integrity": "sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-wasm": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-wasm/-/watcher-wasm-2.5.1.tgz",
+ "integrity": "sha512-RJxlQQLkaMMIuWRozy+z2vEqbaQlCuaCgVZIUCzQLYggY22LZbP5Y1+ia+FD724Ids9e+XIyOLXLrLgQSHIthw==",
+ "bundleDependencies": [
+ "napi-wasm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-glob": "^4.0.3",
+ "micromatch": "^4.0.5",
+ "napi-wasm": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-wasm/node_modules/napi-wasm": {
+ "version": "1.1.0",
+ "dev": true,
+ "inBundle": true,
+ "license": "MIT"
+ },
+ "node_modules/@parcel/watcher-win32-arm64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz",
+ "integrity": "sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-ia32": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz",
+ "integrity": "sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@parcel/watcher-win32-x64": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz",
+ "integrity": "sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/@pkgjs/parseargs": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@polka/url": {
+ "version": "1.0.0-next.29",
+ "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz",
+ "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@poppinss/colors": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.5.tgz",
+ "integrity": "sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "kleur": "^4.1.5"
+ }
+ },
+ "node_modules/@poppinss/colors/node_modules/kleur": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
+ "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@poppinss/dumper": {
+ "version": "0.6.4",
+ "resolved": "https://registry.npmjs.org/@poppinss/dumper/-/dumper-0.6.4.tgz",
+ "integrity": "sha512-iG0TIdqv8xJ3Lt9O8DrPRxw1MRLjNpoqiSGU03P/wNLP/s0ra0udPJ1J2Tx5M0J3H/cVyEgpbn8xUKRY9j59kQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@poppinss/colors": "^4.1.5",
+ "@sindresorhus/is": "^7.0.2",
+ "supports-color": "^10.0.0"
+ }
+ },
+ "node_modules/@poppinss/exception": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@poppinss/exception/-/exception-1.2.2.tgz",
+ "integrity": "sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@rolldown/pluginutils": {
+ "version": "1.0.0-beta.29",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.29.tgz",
+ "integrity": "sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@rollup/plugin-alias": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-alias/-/plugin-alias-5.1.1.tgz",
+ "integrity": "sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/plugin-commonjs": {
+ "version": "28.0.6",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.6.tgz",
+ "integrity": "sha512-XSQB1K7FUU5QP+3lOQmVCE3I0FcbbNvmNT4VJSj93iUjayaARrTQeoRdiYQoftAJBLrR9t2agwAd3ekaTgHNlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@rollup/pluginutils": "^5.0.1",
+ "commondir": "^1.0.1",
+ "estree-walker": "^2.0.2",
+ "fdir": "^6.2.0",
+ "is-reference": "1.2.1",
+ "magic-string": "^0.30.3",
+ "picomatch": "^4.0.2"
+ },
+ "engines": {
+ "node": ">=16.0.0 || 14 >= 14.17"
+ },
+ "peerDependencies": {
+ "rollup": "^2.68.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/plugin-commonjs/node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@rollup/plugin-inject": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz",
+ "integrity": "sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@rollup/pluginutils": "^5.0.1",
+ "estree-walker": "^2.0.2",
+ "magic-string": "^0.30.3"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/plugin-inject/node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@rollup/plugin-json": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.1.0.tgz",
+ "integrity": "sha512-EGI2te5ENk1coGeADSIwZ7G2Q8CJS2sF120T7jLw4xFw9n7wIOXHo+kIYRAoVpJAN+kmqZSoO3Fp4JtoNF4ReA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@rollup/pluginutils": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/plugin-node-resolve": {
+ "version": "16.0.1",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.1.tgz",
+ "integrity": "sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@rollup/pluginutils": "^5.0.1",
+ "@types/resolve": "1.20.2",
+ "deepmerge": "^4.2.2",
+ "is-module": "^1.0.0",
+ "resolve": "^1.22.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^2.78.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/plugin-replace": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-6.0.2.tgz",
+ "integrity": "sha512-7QaYCf8bqF04dOy7w/eHmJeNExxTYwvKAmlSAH/EaWWUzbT0h5sbF6bktFoX/0F/0qwng5/dWFMyf3gzaM8DsQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@rollup/pluginutils": "^5.0.1",
+ "magic-string": "^0.30.3"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/plugin-terser": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz",
+ "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "serialize-javascript": "^6.0.1",
+ "smob": "^1.0.0",
+ "terser": "^5.17.4"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^2.0.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/pluginutils": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.3.0.tgz",
+ "integrity": "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0",
+ "estree-walker": "^2.0.2",
+ "picomatch": "^4.0.2"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@rollup/pluginutils/node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.52.1.tgz",
+ "integrity": "sha512-sifE8uDpDvortUdi3xFevQ9WN5L3orrglg7iO/DhIpSVCwJOxBs9k9JzCC76KEZkLY4UkHWj+KESdFhlsNmDLw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.52.1.tgz",
+ "integrity": "sha512-s83W/rRAPshsyzH9cS0CPKZVLlo2GGRt/1BocbR64DIyr2tMN1f2OZEjbFUnkAA2ewfbd+9waSYS0vbrlsG3qg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.52.1.tgz",
+ "integrity": "sha512-lJkbZBREVUY9Vdw6DrzCysWv9Trcl7SyNxPRQMqvt6V/xmQC140aOcSkyWzwQ9t+s3ojvvWYZMpSazAbSTNfSA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.52.1.tgz",
+ "integrity": "sha512-cw852iGDmvuXeOz2lwpocEL9wkHg3TBZRdAbwmra/YJ5KVxaj7nDdYJ9P0OAVxsbsKa0hFML+dwRHA02kB8Q+g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.52.1.tgz",
+ "integrity": "sha512-nLezpaKL1jY63BunCbeA7B7B/5i4DQifNRBfzZ0+p3BxRejeKdzP7T3rfD5YpNy3+RysFy8Zw3EAnvXyrbZzqQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.52.1.tgz",
+ "integrity": "sha512-USdXZmfo+t4DoUC02UotEf7e6ADsaQ1pvOtOZV2iT2wEmB6y7iMJA0MsIZTbp27enq9v+YK43s3ztYPVy0T2bA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.52.1.tgz",
+ "integrity": "sha512-n3YunK17pY3BuZhLNTcRCT83JkFRfBKnG4R2vROUZvxLJlYkIQXfDGQRVZ7ZZBp1INxXm4fzT4jrd6Tm5DMZ7g==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.52.1.tgz",
+ "integrity": "sha512-45geWgFvA+SKw49tRkHI7xBizBZc6bismWIg+zqwK1OZN0hqMXe39BExVu45o768KDoM7XGoZ1pDE9opiHKKag==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.52.1.tgz",
+ "integrity": "sha512-7m2ybyIOd5j/U43JSfMblwiZG69yAfuvg6TXhHvOtoQMjw6Or48FmgUxyAZ4ZzH7isxfMyr8M26m0pBkoAIEdQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.52.1.tgz",
+ "integrity": "sha512-qnmMzRpkKG1T1EzKVtA/8Q0YAYalRN+h+WzWcbyD0SqjVwxmqrPj/TuuH30TwUp6X2UaUhfWSHccMgF+T6jDpw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.52.1.tgz",
+ "integrity": "sha512-5Fc7jWzggy8RXJTew+8FoUXwpvJIuwOcYEMSJxs/9MB+oG/C4NRM23Xg+vW173sQz0H6RSViMmoKJih/hVQQow==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.52.1.tgz",
+ "integrity": "sha512-DxnsniAn/iv23PtQhOU0l+cXAG3IvWkzEOc9t4THzWJs/NKpF955GnbYKo6PwqwlcbxO/ARn4B8IMg4ghW+DOw==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.52.1.tgz",
+ "integrity": "sha512-xAlxc3PeGHNpLmisSs8UpFm/A8aPOVeoHhWePEH0rDVFCC4uwWx4W1ecq/oYT2gjkRtVBxD1GjjNYJQrN9fX4A==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.52.1.tgz",
+ "integrity": "sha512-b5xbekmUtAkPY3TqrYMvbAltNNmpMApdMDxjYiaUQ8k1ep0iS/900CJEZq/RPd5gXF59Lp+me1wXbkW1xpxw4g==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.52.1.tgz",
+ "integrity": "sha512-CcNQx6CuvJH/SMt3dElyqrCK7BCCAOQtdobJIVhJ7AaA5nrE0RkNHTVzDyXkYqkgoMjuF2p0tEchX7YuOeal4w==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.52.1.tgz",
+ "integrity": "sha512-xsKzVShwurM4JjGyMo/n4lb13mzpfDmg0yWiMlO65XSkhIpWnGnE4z66y9leVALb3M7sWiNluCKUv2ZZ0DWy1w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.52.1.tgz",
+ "integrity": "sha512-AtzCeCyU6wYbJq7akOX3oZmc1pcY6yNYYC+HbjAcnjB63hXc22AX6nWtoU9TOJw3EQRxCLIubwGmnSrk66khpQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.52.1.tgz",
+ "integrity": "sha512-pZb5K1hqS6MmdSgNUfWIzemPNNwmg5n7HhZHSyClwGd/IoQCiTjUGs09O/lxOZLHlltqUyVl0Y/4dcd8j90FEw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.52.1.tgz",
+ "integrity": "sha512-A6hkNBmS3yahy06sFIouOjC5MO/ciPSBxdbWdGIk7ue3lhR1wJ9mJ27kZFK/N8ZOLwO1YdymYhhfI3gGHHpliA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.52.1.tgz",
+ "integrity": "sha512-HRNyKIYDpuC7FIVJ8kH1RFGoEp4beASrjKksx3f2Oa82pLxNVhBIM1gC7WEd7z9djZ0OW6o9qhXFo7gAU4QCWw==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.52.1.tgz",
+ "integrity": "sha512-rkpnc4BKw8QoP9yynwLJqjVgmkko8yjqEHHYlUPv/xznRb3mQ7iN7fpc5fOqCFtYCeEyilBAun5a4wKLLKYX2g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.52.1.tgz",
+ "integrity": "sha512-ZzNEDNx/4sWP94UNAc6OfVNJFM2G4vz6IcIhBJv8BYyLeGNQldV5Dn22+i8Y7yn4a7unFjdAX/1nwNBfc7tUcg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@sindresorhus/is": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.1.0.tgz",
+ "integrity": "sha512-7F/yz2IphV39hiS2zB4QYVkivrptHHh0K8qJJd9HhuWSdvf8AN7NpebW3CcDZDBQsUPMoDKWsY2WWgW7bqOcfA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/is?sponsor=1"
+ }
+ },
+ "node_modules/@sindresorhus/merge-streams": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz",
+ "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@speed-highlight/core": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/@speed-highlight/core/-/core-1.2.7.tgz",
+ "integrity": "sha512-0dxmVj4gxg3Jg879kvFS/msl4s9F3T9UXC1InxgOf7t5NvcPD97u/WTA5vL/IxWHMn7qSxBozqrnnE2wvl1m8g==",
+ "dev": true,
+ "license": "CC0-1.0"
+ },
+ "node_modules/@tybys/wasm-util": {
+ "version": "0.10.1",
+ "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
+ "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@types/eslint": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-9.6.1.tgz",
+ "integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@types/estree": "*",
+ "@types/json-schema": "*"
+ }
+ },
+ "node_modules/@types/eslint-scope": {
+ "version": "3.7.7",
+ "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.7.tgz",
+ "integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@types/eslint": "*",
+ "@types/estree": "*"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+ "license": "MIT"
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "24.5.2",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.5.2.tgz",
+ "integrity": "sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "undici-types": "~7.12.0"
+ }
+ },
+ "node_modules/@types/parse-path": {
+ "version": "7.0.3",
+ "resolved": "https://registry.npmjs.org/@types/parse-path/-/parse-path-7.0.3.tgz",
+ "integrity": "sha512-LriObC2+KYZD3FzCrgWGv/qufdUy4eXrxcLgQMfYXgPbLIecKIsVBaQgUPmxSSLcjmYbDTQbMgr6qr6l/eb7Bg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/resolve": {
+ "version": "1.20.2",
+ "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz",
+ "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@unhead/vue": {
+ "version": "2.0.17",
+ "resolved": "https://registry.npmjs.org/@unhead/vue/-/vue-2.0.17.tgz",
+ "integrity": "sha512-jzmGZYeMAhETV6qfetmLbZzUjjx1TjdNvFSobeFZb73D7dwD9wl/nOAx36qq+TvjZsLJdF5PQWToz2oDGAUqCg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hookable": "^5.5.3",
+ "unhead": "2.0.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/harlan-zw"
+ },
+ "peerDependencies": {
+ "vue": ">=3.5.18"
+ }
+ },
+ "node_modules/@vercel/nft": {
+ "version": "0.30.1",
+ "resolved": "https://registry.npmjs.org/@vercel/nft/-/nft-0.30.1.tgz",
+ "integrity": "sha512-2mgJZv4AYBFkD/nJ4QmiX5Ymxi+AisPLPcS/KPXVqniyQNqKXX+wjieAbDXQP3HcogfEbpHoRMs49Cd4pfkk8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@mapbox/node-pre-gyp": "^2.0.0",
+ "@rollup/pluginutils": "^5.1.3",
+ "acorn": "^8.6.0",
+ "acorn-import-attributes": "^1.9.5",
+ "async-sema": "^3.1.1",
+ "bindings": "^1.4.0",
+ "estree-walker": "2.0.2",
+ "glob": "^10.4.5",
+ "graceful-fs": "^4.2.9",
+ "node-gyp-build": "^4.2.2",
+ "picomatch": "^4.0.2",
+ "resolve-from": "^5.0.0"
+ },
+ "bin": {
+ "nft": "out/cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@vercel/nft/node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@vitejs/plugin-vue": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.1.tgz",
+ "integrity": "sha512-+MaE752hU0wfPFJEUAIxqw18+20euHHdxVtMvbFcOEpjEyfqXH/5DCoTHiVJ0J29EhTJdoTkjEv5YBKU9dnoTw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@rolldown/pluginutils": "1.0.0-beta.29"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "peerDependencies": {
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
+ "vue": "^3.2.25"
+ }
+ },
+ "node_modules/@vitejs/plugin-vue-jsx": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-5.1.1.tgz",
+ "integrity": "sha512-uQkfxzlF8SGHJJVH966lFTdjM/lGcwJGzwAHpVqAPDD/QcsqoUGa+q31ox1BrUfi+FLP2ChVp7uLXE3DkHyDdQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/core": "^7.28.3",
+ "@babel/plugin-syntax-typescript": "^7.27.1",
+ "@babel/plugin-transform-typescript": "^7.28.0",
+ "@rolldown/pluginutils": "^1.0.0-beta.34",
+ "@vue/babel-plugin-jsx": "^1.5.0"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "peerDependencies": {
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
+ "vue": "^3.0.0"
+ }
+ },
+ "node_modules/@vitejs/plugin-vue-jsx/node_modules/@rolldown/pluginutils": {
+ "version": "1.0.0-beta.39",
+ "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.39.tgz",
+ "integrity": "sha512-GkTtNCV8ObWbq3LrJStPBv9jkRPct8WlwotVjx3aU0RwfH3LyheixWK9Zhaj22C4EQj/TJxYyetoX+uOn/MWKw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@volar/language-core": {
+ "version": "2.4.23",
+ "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.23.tgz",
+ "integrity": "sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@volar/source-map": "2.4.23"
+ }
+ },
+ "node_modules/@volar/source-map": {
+ "version": "2.4.23",
+ "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.23.tgz",
+ "integrity": "sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@volar/typescript": {
+ "version": "2.4.23",
+ "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.23.tgz",
+ "integrity": "sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@volar/language-core": "2.4.23",
+ "path-browserify": "^1.0.1",
+ "vscode-uri": "^3.0.8"
+ }
+ },
+ "node_modules/@vue-macros/common": {
+ "version": "3.0.0-beta.16",
+ "resolved": "https://registry.npmjs.org/@vue-macros/common/-/common-3.0.0-beta.16.tgz",
+ "integrity": "sha512-8O2gWxWFiaoNkk7PGi0+p7NPGe/f8xJ3/INUufvje/RZOs7sJvlI1jnR4lydtRFa/mU0ylMXUXXjSK0fHDEYTA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-sfc": "^3.5.17",
+ "ast-kit": "^2.1.1",
+ "local-pkg": "^1.1.1",
+ "magic-string-ast": "^1.0.0",
+ "unplugin-utils": "^0.2.4"
+ },
+ "engines": {
+ "node": ">=20.18.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/vue-macros"
+ },
+ "peerDependencies": {
+ "vue": "^2.7.0 || ^3.2.25"
+ },
+ "peerDependenciesMeta": {
+ "vue": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vue/babel-helper-vue-transform-on": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.5.0.tgz",
+ "integrity": "sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@vue/babel-plugin-jsx": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.5.0.tgz",
+ "integrity": "sha512-mneBhw1oOqCd2247O0Yw/mRwC9jIGACAJUlawkmMBiNmL4dGA2eMzuNZVNqOUfYTa6vqmND4CtOPzmEEEqLKFw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.27.1",
+ "@babel/helper-plugin-utils": "^7.27.1",
+ "@babel/plugin-syntax-jsx": "^7.27.1",
+ "@babel/template": "^7.27.2",
+ "@babel/traverse": "^7.28.0",
+ "@babel/types": "^7.28.2",
+ "@vue/babel-helper-vue-transform-on": "1.5.0",
+ "@vue/babel-plugin-resolve-type": "1.5.0",
+ "@vue/shared": "^3.5.18"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ },
+ "peerDependenciesMeta": {
+ "@babel/core": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vue/babel-plugin-resolve-type": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@vue/babel-plugin-resolve-type/-/babel-plugin-resolve-type-1.5.0.tgz",
+ "integrity": "sha512-Wm/60o+53JwJODm4Knz47dxJnLDJ9FnKnGZJbUUf8nQRAtt6P+undLUAVU3Ha33LxOJe6IPoifRQ6F/0RrU31w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "@babel/helper-module-imports": "^7.27.1",
+ "@babel/helper-plugin-utils": "^7.27.1",
+ "@babel/parser": "^7.28.0",
+ "@vue/compiler-sfc": "^3.5.18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sxzz"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0-0"
+ }
+ },
+ "node_modules/@vue/compiler-core": {
+ "version": "3.5.21",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.21.tgz",
+ "integrity": "sha512-8i+LZ0vf6ZgII5Z9XmUvrCyEzocvWT+TeR2VBUVlzIH6Tyv57E20mPZ1bCS+tbejgUgmjrEh7q/0F0bibskAmw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.28.3",
+ "@vue/shared": "3.5.21",
+ "entities": "^4.5.0",
+ "estree-walker": "^2.0.2",
+ "source-map-js": "^1.2.1"
+ }
+ },
+ "node_modules/@vue/compiler-core/node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "license": "MIT"
+ },
+ "node_modules/@vue/compiler-dom": {
+ "version": "3.5.21",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.21.tgz",
+ "integrity": "sha512-jNtbu/u97wiyEBJlJ9kmdw7tAr5Vy0Aj5CgQmo+6pxWNQhXZDPsRr1UWPN4v3Zf82s2H3kF51IbzZ4jMWAgPlQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-core": "3.5.21",
+ "@vue/shared": "3.5.21"
+ }
+ },
+ "node_modules/@vue/compiler-sfc": {
+ "version": "3.5.21",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.21.tgz",
+ "integrity": "sha512-SXlyk6I5eUGBd2v8Ie7tF6ADHE9kCR6mBEuPyH1nUZ0h6Xx6nZI29i12sJKQmzbDyr2tUHMhhTt51Z6blbkTTQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.28.3",
+ "@vue/compiler-core": "3.5.21",
+ "@vue/compiler-dom": "3.5.21",
+ "@vue/compiler-ssr": "3.5.21",
+ "@vue/shared": "3.5.21",
+ "estree-walker": "^2.0.2",
+ "magic-string": "^0.30.18",
+ "postcss": "^8.5.6",
+ "source-map-js": "^1.2.1"
+ }
+ },
+ "node_modules/@vue/compiler-sfc/node_modules/estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+ "license": "MIT"
+ },
+ "node_modules/@vue/compiler-ssr": {
+ "version": "3.5.21",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.21.tgz",
+ "integrity": "sha512-vKQ5olH5edFZdf5ZrlEgSO1j1DMA4u23TVK5XR1uMhvwnYvVdDF0nHXJUblL/GvzlShQbjhZZ2uvYmDlAbgo9w==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-dom": "3.5.21",
+ "@vue/shared": "3.5.21"
+ }
+ },
+ "node_modules/@vue/compiler-vue2": {
+ "version": "2.7.16",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz",
+ "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "de-indent": "^1.0.2",
+ "he": "^1.2.0"
+ }
+ },
+ "node_modules/@vue/devtools-api": {
+ "version": "6.6.4",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
+ "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
+ "license": "MIT"
+ },
+ "node_modules/@vue/devtools-core": {
+ "version": "7.7.7",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-core/-/devtools-core-7.7.7.tgz",
+ "integrity": "sha512-9z9TLbfC+AjAi1PQyWX+OErjIaJmdFlbDHcD+cAMYKY6Bh5VlsAtCeGyRMrXwIlMEQPukvnWt3gZBLwTAIMKzQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vue/devtools-kit": "^7.7.7",
+ "@vue/devtools-shared": "^7.7.7",
+ "mitt": "^3.0.1",
+ "nanoid": "^5.1.0",
+ "pathe": "^2.0.3",
+ "vite-hot-client": "^2.0.4"
+ },
+ "peerDependencies": {
+ "vue": "^3.0.0"
+ }
+ },
+ "node_modules/@vue/devtools-kit": {
+ "version": "7.7.7",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-kit/-/devtools-kit-7.7.7.tgz",
+ "integrity": "sha512-wgoZtxcTta65cnZ1Q6MbAfePVFxfM+gq0saaeytoph7nEa7yMXoi6sCPy4ufO111B9msnw0VOWjPEFCXuAKRHA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vue/devtools-shared": "^7.7.7",
+ "birpc": "^2.3.0",
+ "hookable": "^5.5.3",
+ "mitt": "^3.0.1",
+ "perfect-debounce": "^1.0.0",
+ "speakingurl": "^14.0.1",
+ "superjson": "^2.2.2"
+ }
+ },
+ "node_modules/@vue/devtools-kit/node_modules/perfect-debounce": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-1.0.0.tgz",
+ "integrity": "sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@vue/devtools-shared": {
+ "version": "7.7.7",
+ "resolved": "https://registry.npmjs.org/@vue/devtools-shared/-/devtools-shared-7.7.7.tgz",
+ "integrity": "sha512-+udSj47aRl5aKb0memBvcUG9koarqnxNM5yjuREvqwK6T3ap4mn3Zqqc17QrBFTqSMjr3HK1cvStEZpMDpfdyw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "rfdc": "^1.4.1"
+ }
+ },
+ "node_modules/@vue/language-core": {
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.0.8.tgz",
+ "integrity": "sha512-eYs6PF7bxoPYvek9qxceo1BCwFbJZYqJll+WaYC8o8ec60exqj+n+QRGGiJHSeUfYp0hDxARbMdxMq/fbPgU5g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@volar/language-core": "2.4.23",
+ "@vue/compiler-dom": "^3.5.0",
+ "@vue/compiler-vue2": "^2.7.16",
+ "@vue/shared": "^3.5.0",
+ "alien-signals": "^2.0.5",
+ "muggle-string": "^0.4.1",
+ "path-browserify": "^1.0.1",
+ "picomatch": "^4.0.2"
+ },
+ "peerDependencies": {
+ "typescript": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@vue/reactivity": {
+ "version": "3.5.21",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.21.tgz",
+ "integrity": "sha512-3ah7sa+Cwr9iiYEERt9JfZKPw4A2UlbY8RbbnH2mGCE8NwHkhmlZt2VsH0oDA3P08X3jJd29ohBDtX+TbD9AsA==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/shared": "3.5.21"
+ }
+ },
+ "node_modules/@vue/runtime-core": {
+ "version": "3.5.21",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.21.tgz",
+ "integrity": "sha512-+DplQlRS4MXfIf9gfD1BOJpk5RSyGgGXD/R+cumhe8jdjUcq/qlxDawQlSI8hCKupBlvM+3eS1se5xW+SuNAwA==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/reactivity": "3.5.21",
+ "@vue/shared": "3.5.21"
+ }
+ },
+ "node_modules/@vue/runtime-dom": {
+ "version": "3.5.21",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.21.tgz",
+ "integrity": "sha512-3M2DZsOFwM5qI15wrMmNF5RJe1+ARijt2HM3TbzBbPSuBHOQpoidE+Pa+XEaVN+czbHf81ETRoG1ltztP2em8w==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/reactivity": "3.5.21",
+ "@vue/runtime-core": "3.5.21",
+ "@vue/shared": "3.5.21",
+ "csstype": "^3.1.3"
+ }
+ },
+ "node_modules/@vue/server-renderer": {
+ "version": "3.5.21",
+ "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.21.tgz",
+ "integrity": "sha512-qr8AqgD3DJPJcGvLcJKQo2tAc8OnXRcfxhOJCPF+fcfn5bBGz7VCcO7t+qETOPxpWK1mgysXvVT/j+xWaHeMWA==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-ssr": "3.5.21",
+ "@vue/shared": "3.5.21"
+ },
+ "peerDependencies": {
+ "vue": "3.5.21"
+ }
+ },
+ "node_modules/@vue/shared": {
+ "version": "3.5.21",
+ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.21.tgz",
+ "integrity": "sha512-+2k1EQpnYuVuu3N7atWyG3/xoFWIVJZq4Mz8XNOdScFI0etES75fbny/oU4lKWk/577P1zmg0ioYvpGEDZ3DLw==",
+ "license": "MIT"
+ },
+ "node_modules/@webassemblyjs/ast": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz",
+ "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/helper-numbers": "1.13.2",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2"
+ }
+ },
+ "node_modules/@webassemblyjs/floating-point-hex-parser": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz",
+ "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@webassemblyjs/helper-api-error": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz",
+ "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@webassemblyjs/helper-buffer": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz",
+ "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@webassemblyjs/helper-numbers": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz",
+ "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/floating-point-hex-parser": "1.13.2",
+ "@webassemblyjs/helper-api-error": "1.13.2",
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "node_modules/@webassemblyjs/helper-wasm-bytecode": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz",
+ "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@webassemblyjs/helper-wasm-section": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz",
+ "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-buffer": "1.14.1",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+ "@webassemblyjs/wasm-gen": "1.14.1"
+ }
+ },
+ "node_modules/@webassemblyjs/ieee754": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz",
+ "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@xtuc/ieee754": "^1.2.0"
+ }
+ },
+ "node_modules/@webassemblyjs/leb128": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz",
+ "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==",
+ "license": "Apache-2.0",
+ "peer": true,
+ "dependencies": {
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "node_modules/@webassemblyjs/utf8": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz",
+ "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/@webassemblyjs/wasm-edit": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz",
+ "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-buffer": "1.14.1",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+ "@webassemblyjs/helper-wasm-section": "1.14.1",
+ "@webassemblyjs/wasm-gen": "1.14.1",
+ "@webassemblyjs/wasm-opt": "1.14.1",
+ "@webassemblyjs/wasm-parser": "1.14.1",
+ "@webassemblyjs/wast-printer": "1.14.1"
+ }
+ },
+ "node_modules/@webassemblyjs/wasm-gen": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz",
+ "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+ "@webassemblyjs/ieee754": "1.13.2",
+ "@webassemblyjs/leb128": "1.13.2",
+ "@webassemblyjs/utf8": "1.13.2"
+ }
+ },
+ "node_modules/@webassemblyjs/wasm-opt": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz",
+ "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-buffer": "1.14.1",
+ "@webassemblyjs/wasm-gen": "1.14.1",
+ "@webassemblyjs/wasm-parser": "1.14.1"
+ }
+ },
+ "node_modules/@webassemblyjs/wasm-parser": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz",
+ "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@webassemblyjs/helper-api-error": "1.13.2",
+ "@webassemblyjs/helper-wasm-bytecode": "1.13.2",
+ "@webassemblyjs/ieee754": "1.13.2",
+ "@webassemblyjs/leb128": "1.13.2",
+ "@webassemblyjs/utf8": "1.13.2"
+ }
+ },
+ "node_modules/@webassemblyjs/wast-printer": {
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz",
+ "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@webassemblyjs/ast": "1.14.1",
+ "@xtuc/long": "4.2.2"
+ }
+ },
+ "node_modules/@xtuc/ieee754": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
+ "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
+ "license": "BSD-3-Clause",
+ "peer": true
+ },
+ "node_modules/@xtuc/long": {
+ "version": "4.2.2",
+ "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
+ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
+ "license": "Apache-2.0",
+ "peer": true
+ },
+ "node_modules/abbrev": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz",
+ "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^18.17.0 || >=20.5.0"
+ }
+ },
+ "node_modules/abort-controller": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+ "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "event-target-shim": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=6.5"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "8.15.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-import-attributes": {
+ "version": "1.9.5",
+ "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz",
+ "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^8"
+ }
+ },
+ "node_modules/acorn-import-phases": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/acorn-import-phases/-/acorn-import-phases-1.0.4.tgz",
+ "integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=10.13.0"
+ },
+ "peerDependencies": {
+ "acorn": "^8.14.0"
+ }
+ },
+ "node_modules/acorn-walk": {
+ "version": "8.3.4",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
+ "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.11.0"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/agent-base": {
+ "version": "7.1.4",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
+ "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "fast-json-stable-stringify": "^2.0.0",
+ "json-schema-traverse": "^0.4.1",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ajv-formats": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
+ "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "ajv": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ajv-formats/node_modules/ajv": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ajv-formats/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/ajv-keywords": {
+ "version": "3.5.2",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
+ "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "ajv": "^6.9.1"
+ }
+ },
+ "node_modules/alien-signals": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-2.0.7.tgz",
+ "integrity": "sha512-wE7y3jmYeb0+h6mr5BOovuqhFv22O/MV9j5p0ndJsa7z1zJNPGQ4ph5pQk/kTTCWRC3xsA4SmtwmkzQO+7NCNg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/ansi-regex": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz",
+ "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+ "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/ansis": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/ansis/-/ansis-4.1.0.tgz",
+ "integrity": "sha512-BGcItUBWSMRgOCe+SVZJ+S7yTRG0eGt9cXAHev72yuGcY23hnLA7Bky5L/xLyPINoSN95geovfBkqoTlNZYa7w==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "license": "ISC",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/anymatch/node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/archiver": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/archiver/-/archiver-7.0.1.tgz",
+ "integrity": "sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "archiver-utils": "^5.0.2",
+ "async": "^3.2.4",
+ "buffer-crc32": "^1.0.0",
+ "readable-stream": "^4.0.0",
+ "readdir-glob": "^1.1.2",
+ "tar-stream": "^3.0.0",
+ "zip-stream": "^6.0.1"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/archiver-utils": {
+ "version": "5.0.2",
+ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-5.0.2.tgz",
+ "integrity": "sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "glob": "^10.0.0",
+ "graceful-fs": "^4.2.0",
+ "is-stream": "^2.0.1",
+ "lazystream": "^1.0.0",
+ "lodash": "^4.17.15",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ast-kit": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.1.2.tgz",
+ "integrity": "sha512-cl76xfBQM6pztbrFWRnxbrDm9EOqDr1BF6+qQnnDZG2Co2LjyUktkN9GTJfBAfdae+DbT2nJf2nCGAdDDN7W2g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.28.0",
+ "pathe": "^2.0.3"
+ },
+ "engines": {
+ "node": ">=20.18.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sxzz"
+ }
+ },
+ "node_modules/ast-walker-scope": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/ast-walker-scope/-/ast-walker-scope-0.8.2.tgz",
+ "integrity": "sha512-3pYeLyDZ6nJew9QeBhS4Nly02269Dkdk32+zdbbKmL6n4ZuaGorwwA+xx12xgOciA8BF1w9x+dlH7oUkFTW91w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.28.3",
+ "ast-kit": "^2.1.2"
+ },
+ "engines": {
+ "node": ">=20.18.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sxzz"
+ }
+ },
+ "node_modules/async": {
+ "version": "3.2.6",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz",
+ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/async-sema": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/async-sema/-/async-sema-3.1.1.tgz",
+ "integrity": "sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/autoprefixer": {
+ "version": "10.4.21",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz",
+ "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "browserslist": "^4.24.4",
+ "caniuse-lite": "^1.0.30001702",
+ "fraction.js": "^4.3.7",
+ "normalize-range": "^0.1.2",
+ "picocolors": "^1.1.1",
+ "postcss-value-parser": "^4.2.0"
+ },
+ "bin": {
+ "autoprefixer": "bin/autoprefixer"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ },
+ "peerDependencies": {
+ "postcss": "^8.1.0"
+ }
+ },
+ "node_modules/b4a": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.7.1.tgz",
+ "integrity": "sha512-ZovbrBV0g6JxK5cGUF1Suby1vLfKjv4RWi8IxoaO/Mon8BDD9I21RxjHFtgQ+kskJqLAVyQZly3uMBui+vhc8Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peerDependencies": {
+ "react-native-b4a": "*"
+ },
+ "peerDependenciesMeta": {
+ "react-native-b4a": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/bare-events": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.7.0.tgz",
+ "integrity": "sha512-b3N5eTW1g7vXkw+0CXh/HazGTcO5KYuu/RCNaJbDMPI6LHDi+7qe8EmxKUVe1sUbY2KZOVZFyj62x0OEz9qyAA==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/baseline-browser-mapping": {
+ "version": "2.8.6",
+ "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.8.6.tgz",
+ "integrity": "sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==",
+ "license": "Apache-2.0",
+ "bin": {
+ "baseline-browser-mapping": "dist/cli.js"
+ }
+ },
+ "node_modules/big.js": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
+ "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/bindings": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz",
+ "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "file-uri-to-path": "1.0.0"
+ }
+ },
+ "node_modules/birpc": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/birpc/-/birpc-2.6.1.tgz",
+ "integrity": "sha512-LPnFhlDpdSH6FJhJyn4M0kFO7vtQ5iPw24FnG0y21q09xC7e8+1LeR31S1MAIrDAHp4m7aas4bEkTDTvMAtebQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/boolbase": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/brace-expansion": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browserslist": {
+ "version": "4.26.2",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.2.tgz",
+ "integrity": "sha512-ECFzp6uFOSB+dcZ5BK/IBaGWssbSYBHvuMeMt3MMFyhI0Z8SqGgEkBLARgpRH3hutIgPVsALcMwbDrJqPxQ65A==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "baseline-browser-mapping": "^2.8.3",
+ "caniuse-lite": "^1.0.30001741",
+ "electron-to-chromium": "^1.5.218",
+ "node-releases": "^2.0.21",
+ "update-browserslist-db": "^1.1.3"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
+ "node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
+ "node_modules/buffer-crc32": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz",
+ "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+ "license": "MIT"
+ },
+ "node_modules/bundle-name": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz",
+ "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "run-applescript": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/c12": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/c12/-/c12-3.3.0.tgz",
+ "integrity": "sha512-K9ZkuyeJQeqLEyqldbYLG3wjqwpw4BVaAqvmxq3GYKK0b1A/yYQdIcJxkzAOWcNVWhJpRXAPfZFueekiY/L8Dw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": "^4.0.3",
+ "confbox": "^0.2.2",
+ "defu": "^6.1.4",
+ "dotenv": "^17.2.2",
+ "exsolve": "^1.0.7",
+ "giget": "^2.0.0",
+ "jiti": "^2.5.1",
+ "ohash": "^2.0.11",
+ "pathe": "^2.0.3",
+ "perfect-debounce": "^2.0.0",
+ "pkg-types": "^2.3.0",
+ "rc9": "^2.1.2"
+ },
+ "peerDependencies": {
+ "magicast": "^0.3.5"
+ },
+ "peerDependenciesMeta": {
+ "magicast": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/c12/node_modules/dotenv": {
+ "version": "17.2.2",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.2.tgz",
+ "integrity": "sha512-Sf2LSQP+bOlhKWWyhFsn0UsfdK/kCWRv1iuA2gXAwt3dyNabr6QSj00I2V10pidqz69soatm9ZwZvpQMTIOd5Q==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
+ "node_modules/cac": {
+ "version": "6.7.14",
+ "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
+ "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/callsite": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
+ "integrity": "sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/caniuse-api": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
+ "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "browserslist": "^4.0.0",
+ "caniuse-lite": "^1.0.0",
+ "lodash.memoize": "^4.1.2",
+ "lodash.uniq": "^4.5.0"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001743",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001743.tgz",
+ "integrity": "sha512-e6Ojr7RV14Un7dz6ASD0aZDmQPT/A+eZU+nuTNfjqmRrmkmQlnTNWH0SKmqagx9PeW87UVqapSurtAXifmtdmw==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "CC-BY-4.0"
+ },
+ "node_modules/chokidar": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
+ "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "readdirp": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 14.16.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/chownr": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
+ "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/chrome-trace-event": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz",
+ "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/citty": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/citty/-/citty-0.1.6.tgz",
+ "integrity": "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "consola": "^3.2.3"
+ }
+ },
+ "node_modules/clipboardy": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-4.0.0.tgz",
+ "integrity": "sha512-5mOlNS0mhX0707P2I0aZ2V/cmHUEO/fL7VFLqszkhUsxt7RwnmrInf/eEQKlf5GzvYeHIjT+Ov1HRfNmymlG0w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "execa": "^8.0.1",
+ "is-wsl": "^3.1.0",
+ "is64bit": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/cliui": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
+ "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.1",
+ "wrap-ansi": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/cliui/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cliui/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/cliui/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cliui/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cliui/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cliui/node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/cluster-key-slot": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz",
+ "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/colord": {
+ "version": "2.9.3",
+ "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz",
+ "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/commander": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
+ "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/commondir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+ "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/compatx": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/compatx/-/compatx-0.2.0.tgz",
+ "integrity": "sha512-6gLRNt4ygsi5NyMVhceOCFv14CIdDFN7fQjX1U4+47qVE/+kjPoXMK65KWK+dWxmFzMTuKazoQ9sch6pM0p5oA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/compress-commons": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-6.0.2.tgz",
+ "integrity": "sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "crc-32": "^1.2.0",
+ "crc32-stream": "^6.0.0",
+ "is-stream": "^2.0.1",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/compress-commons/node_modules/is-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+ "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/confbox": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.2.tgz",
+ "integrity": "sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/consola": {
+ "version": "3.4.2",
+ "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz",
+ "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^14.18.0 || >=16.10.0"
+ }
+ },
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cookie": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz",
+ "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/cookie-es": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-2.0.0.tgz",
+ "integrity": "sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/copy-anything": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-3.0.5.tgz",
+ "integrity": "sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-what": "^4.1.8"
+ },
+ "engines": {
+ "node": ">=12.13"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mesqueeb"
+ }
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/crc-32": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
+ "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "crc32": "bin/crc32.njs"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/crc32-stream": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-6.0.0.tgz",
+ "integrity": "sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "crc-32": "^1.2.0",
+ "readable-stream": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/croner": {
+ "version": "9.1.0",
+ "resolved": "https://registry.npmjs.org/croner/-/croner-9.1.0.tgz",
+ "integrity": "sha512-p9nwwR4qyT5W996vBZhdvBCnMhicY5ytZkR4D1Xj0wuTDEiMnjwR57Q3RXYY/s0EpX6Ay3vgIcfaR+ewGHsi+g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
+ "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/cross-spawn/node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/cross-spawn/node_modules/which": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+ "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/crossws": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/crossws/-/crossws-0.3.5.tgz",
+ "integrity": "sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "uncrypto": "^0.1.3"
+ }
+ },
+ "node_modules/css-declaration-sorter": {
+ "version": "7.3.0",
+ "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.3.0.tgz",
+ "integrity": "sha512-LQF6N/3vkAMYF4xoHLJfG718HRJh34Z8BnNhd6bosOMIVjMlhuZK5++oZa3uYAgrI5+7x2o27gUqTR2U/KjUOQ==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^14 || ^16 || >=18"
+ },
+ "peerDependencies": {
+ "postcss": "^8.0.9"
+ }
+ },
+ "node_modules/css-select": {
+ "version": "5.2.2",
+ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
+ "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0",
+ "css-what": "^6.1.0",
+ "domhandler": "^5.0.2",
+ "domutils": "^3.0.1",
+ "nth-check": "^2.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/css-tree": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz",
+ "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mdn-data": "2.12.2",
+ "source-map-js": "^1.0.1"
+ },
+ "engines": {
+ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0"
+ }
+ },
+ "node_modules/css-what": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
+ "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">= 6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/fb55"
+ }
+ },
+ "node_modules/cssesc": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+ "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "cssesc": "bin/cssesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/cssnano": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-7.1.1.tgz",
+ "integrity": "sha512-fm4D8ti0dQmFPeF8DXSAA//btEmqCOgAc/9Oa3C1LW94h5usNrJEfrON7b4FkPZgnDEn6OUs5NdxiJZmAtGOpQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cssnano-preset-default": "^7.0.9",
+ "lilconfig": "^3.1.3"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/cssnano"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/cssnano-preset-default": {
+ "version": "7.0.9",
+ "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-7.0.9.tgz",
+ "integrity": "sha512-tCD6AAFgYBOVpMBX41KjbvRh9c2uUjLXRyV7KHSIrwHiq5Z9o0TFfUCoM3TwVrRsRteN3sVXGNvjVNxYzkpTsA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "browserslist": "^4.25.1",
+ "css-declaration-sorter": "^7.2.0",
+ "cssnano-utils": "^5.0.1",
+ "postcss-calc": "^10.1.1",
+ "postcss-colormin": "^7.0.4",
+ "postcss-convert-values": "^7.0.7",
+ "postcss-discard-comments": "^7.0.4",
+ "postcss-discard-duplicates": "^7.0.2",
+ "postcss-discard-empty": "^7.0.1",
+ "postcss-discard-overridden": "^7.0.1",
+ "postcss-merge-longhand": "^7.0.5",
+ "postcss-merge-rules": "^7.0.6",
+ "postcss-minify-font-values": "^7.0.1",
+ "postcss-minify-gradients": "^7.0.1",
+ "postcss-minify-params": "^7.0.4",
+ "postcss-minify-selectors": "^7.0.5",
+ "postcss-normalize-charset": "^7.0.1",
+ "postcss-normalize-display-values": "^7.0.1",
+ "postcss-normalize-positions": "^7.0.1",
+ "postcss-normalize-repeat-style": "^7.0.1",
+ "postcss-normalize-string": "^7.0.1",
+ "postcss-normalize-timing-functions": "^7.0.1",
+ "postcss-normalize-unicode": "^7.0.4",
+ "postcss-normalize-url": "^7.0.1",
+ "postcss-normalize-whitespace": "^7.0.1",
+ "postcss-ordered-values": "^7.0.2",
+ "postcss-reduce-initial": "^7.0.4",
+ "postcss-reduce-transforms": "^7.0.1",
+ "postcss-svgo": "^7.1.0",
+ "postcss-unique-selectors": "^7.0.4"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/cssnano-utils": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-5.0.1.tgz",
+ "integrity": "sha512-ZIP71eQgG9JwjVZsTPSqhc6GHgEr53uJ7tK5///VfyWj6Xp2DBmixWHqJgPno+PqATzn48pL42ww9x5SSGmhZg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/csso": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz",
+ "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "css-tree": "~2.2.0"
+ },
+ "engines": {
+ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0",
+ "npm": ">=7.0.0"
+ }
+ },
+ "node_modules/csso/node_modules/css-tree": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz",
+ "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mdn-data": "2.0.28",
+ "source-map-js": "^1.0.1"
+ },
+ "engines": {
+ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0",
+ "npm": ">=7.0.0"
+ }
+ },
+ "node_modules/csso/node_modules/mdn-data": {
+ "version": "2.0.28",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz",
+ "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==",
+ "dev": true,
+ "license": "CC0-1.0"
+ },
+ "node_modules/csstype": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
+ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
+ "license": "MIT"
+ },
+ "node_modules/db0": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/db0/-/db0-0.3.2.tgz",
+ "integrity": "sha512-xzWNQ6jk/+NtdfLyXEipbX55dmDSeteLFt/ayF+wZUU5bzKgmrDOxmInUTbyVRp46YwnJdkDA1KhB7WIXFofJw==",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "@electric-sql/pglite": "*",
+ "@libsql/client": "*",
+ "better-sqlite3": "*",
+ "drizzle-orm": "*",
+ "mysql2": "*",
+ "sqlite3": "*"
+ },
+ "peerDependenciesMeta": {
+ "@electric-sql/pglite": {
+ "optional": true
+ },
+ "@libsql/client": {
+ "optional": true
+ },
+ "better-sqlite3": {
+ "optional": true
+ },
+ "drizzle-orm": {
+ "optional": true
+ },
+ "mysql2": {
+ "optional": true
+ },
+ "sqlite3": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/de-indent": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
+ "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/decache": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/decache/-/decache-4.6.2.tgz",
+ "integrity": "sha512-2LPqkLeu8XWHU8qNCS3kcF6sCcb5zIzvWaAHYSvPfwhdd7mHuah29NssMzrTYyHN4F5oFy2ko9OBYxegtU0FEw==",
+ "license": "MIT",
+ "dependencies": {
+ "callsite": "^1.0.0"
+ }
+ },
+ "node_modules/deepmerge": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/default-browser": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz",
+ "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "bundle-name": "^4.1.0",
+ "default-browser-id": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/default-browser-id": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz",
+ "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/define-lazy-prop": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
+ "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/defu": {
+ "version": "6.1.4",
+ "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz",
+ "integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/denque": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
+ "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/destr": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz",
+ "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "detect-libc": "bin/detect-libc.js"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/devalue": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.3.2.tgz",
+ "integrity": "sha512-UDsjUbpQn9kvm68slnrs+mfxwFkIflOhkanmyabZ8zOYk8SMEIbJ3TK+88g70hSIeytu4y18f0z/hYHMTrXIWw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/diff": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz",
+ "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/dom-serializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+ "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "entities": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
+ "node_modules/domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/domhandler": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+ "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "domelementtype": "^2.3.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
+ "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "dom-serializer": "^2.0.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
+ "node_modules/dot-prop": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-9.0.0.tgz",
+ "integrity": "sha512-1gxPBJpI/pcjQhKgIU91II6Wkay+dLcN3M6rf2uwP8hRur3HtQXjVrdAK3sjC0piaEuxzMwjXChcETiJl47lAQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "type-fest": "^4.18.2"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/dotenv": {
+ "version": "16.6.1",
+ "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz",
+ "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://dotenvx.com"
+ }
+ },
+ "node_modules/duplexer": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
+ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/eastasianwidth": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.222",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.222.tgz",
+ "integrity": "sha512-gA7psSwSwQRE60CEoLz6JBCQPIxNeuzB2nL8vE03GK/OHxlvykbLyeiumQy1iH5C2f3YbRAZpGCMT12a/9ih9w==",
+ "license": "ISC"
+ },
+ "node_modules/emoji-regex": {
+ "version": "9.2.2",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/emojis-list": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
+ "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/encodeurl": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
+ "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/enhanced-resolve": {
+ "version": "5.18.3",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz",
+ "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==",
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
+ "node_modules/error-stack-parser-es": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/error-stack-parser-es/-/error-stack-parser-es-1.0.5.tgz",
+ "integrity": "sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/errx": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/errx/-/errx-0.1.0.tgz",
+ "integrity": "sha512-fZmsRiDNv07K6s2KkKFTiD2aIvECa7++PKyD5NC32tpRw46qZA3sOz+aM+/V9V0GDHxVTKLziveV4JhzBHDp9Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/es-module-lexer": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz",
+ "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==",
+ "license": "MIT"
+ },
+ "node_modules/esbuild": {
+ "version": "0.25.10",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.10.tgz",
+ "integrity": "sha512-9RiGKvCwaqxO2owP61uQ4BgNborAQskMR6QusfWzQqv7AZOg5oGehdY2pRJMTKuwxd1IDBP4rSbI5lHzU7SMsQ==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.10",
+ "@esbuild/android-arm": "0.25.10",
+ "@esbuild/android-arm64": "0.25.10",
+ "@esbuild/android-x64": "0.25.10",
+ "@esbuild/darwin-arm64": "0.25.10",
+ "@esbuild/darwin-x64": "0.25.10",
+ "@esbuild/freebsd-arm64": "0.25.10",
+ "@esbuild/freebsd-x64": "0.25.10",
+ "@esbuild/linux-arm": "0.25.10",
+ "@esbuild/linux-arm64": "0.25.10",
+ "@esbuild/linux-ia32": "0.25.10",
+ "@esbuild/linux-loong64": "0.25.10",
+ "@esbuild/linux-mips64el": "0.25.10",
+ "@esbuild/linux-ppc64": "0.25.10",
+ "@esbuild/linux-riscv64": "0.25.10",
+ "@esbuild/linux-s390x": "0.25.10",
+ "@esbuild/linux-x64": "0.25.10",
+ "@esbuild/netbsd-arm64": "0.25.10",
+ "@esbuild/netbsd-x64": "0.25.10",
+ "@esbuild/openbsd-arm64": "0.25.10",
+ "@esbuild/openbsd-x64": "0.25.10",
+ "@esbuild/openharmony-arm64": "0.25.10",
+ "@esbuild/sunos-x64": "0.25.10",
+ "@esbuild/win32-arm64": "0.25.10",
+ "@esbuild/win32-ia32": "0.25.10",
+ "@esbuild/win32-x64": "0.25.10"
+ }
+ },
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
+ "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+ "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+ "license": "BSD-2-Clause",
+ "peer": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+ "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+ "license": "BSD-2-Clause",
+ "peer": true,
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esrecurse/node_modules/estraverse": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+ "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+ "license": "BSD-2-Clause",
+ "peer": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+ "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+ "license": "BSD-2-Clause",
+ "peer": true,
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estree-walker": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
+ "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.0"
+ }
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+ "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/event-target-shim": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+ "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.x"
+ }
+ },
+ "node_modules/events-universal": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
+ "integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "bare-events": "^2.7.0"
+ }
+ },
+ "node_modules/execa": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
+ "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cross-spawn": "^7.0.3",
+ "get-stream": "^8.0.1",
+ "human-signals": "^5.0.0",
+ "is-stream": "^3.0.0",
+ "merge-stream": "^2.0.0",
+ "npm-run-path": "^5.1.0",
+ "onetime": "^6.0.0",
+ "signal-exit": "^4.1.0",
+ "strip-final-newline": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=16.17"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/execa?sponsor=1"
+ }
+ },
+ "node_modules/exsolve": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.7.tgz",
+ "integrity": "sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/externality": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/externality/-/externality-1.0.2.tgz",
+ "integrity": "sha512-LyExtJWKxtgVzmgtEHyQtLFpw1KFhQphF9nTG8TpAIVkiI/xQ3FJh75tRFLYl4hkn7BNIIdLJInuDAavX35pMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "enhanced-resolve": "^5.14.1",
+ "mlly": "^1.3.0",
+ "pathe": "^1.1.1",
+ "ufo": "^1.1.2"
+ }
+ },
+ "node_modules/externality/node_modules/pathe": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz",
+ "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+ "license": "MIT"
+ },
+ "node_modules/fast-fifo": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
+ "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-glob": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
+ "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.8"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+ "license": "MIT"
+ },
+ "node_modules/fast-npm-meta": {
+ "version": "0.4.6",
+ "resolved": "https://registry.npmjs.org/fast-npm-meta/-/fast-npm-meta-0.4.6.tgz",
+ "integrity": "sha512-zbBBOAOlzxfrU4WSnbCHk/nR6Vf32lSEPxDEvNOR08Z5DSZ/A6qJu0rqrHVcexBTd1hc2gim998xnqF/R1PuEw==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/fast-uri": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz",
+ "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fastify"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/fastify"
+ }
+ ],
+ "license": "BSD-3-Clause",
+ "peer": true
+ },
+ "node_modules/fastq": {
+ "version": "1.19.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
+ "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/file-loader": {
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz",
+ "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==",
+ "license": "MIT",
+ "dependencies": {
+ "loader-utils": "^2.0.0",
+ "schema-utils": "^3.0.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ },
+ "peerDependencies": {
+ "webpack": "^4.0.0 || ^5.0.0"
+ }
+ },
+ "node_modules/file-uri-to-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
+ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/foreground-child": {
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
+ "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "cross-spawn": "^7.0.6",
+ "signal-exit": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/fraction.js": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
+ "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "type": "patreon",
+ "url": "https://github.com/sponsors/rawify"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
+ "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/fuse.js": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.1.0.tgz",
+ "integrity": "sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+ "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-port-please": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/get-port-please/-/get-port-please-3.2.0.tgz",
+ "integrity": "sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/get-stream": {
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
+ "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/giget": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/giget/-/giget-2.0.0.tgz",
+ "integrity": "sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "citty": "^0.1.6",
+ "consola": "^3.4.0",
+ "defu": "^6.1.4",
+ "node-fetch-native": "^1.6.6",
+ "nypm": "^0.6.0",
+ "pathe": "^2.0.3"
+ },
+ "bin": {
+ "giget": "dist/cli.mjs"
+ }
+ },
+ "node_modules/git-up": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/git-up/-/git-up-8.1.1.tgz",
+ "integrity": "sha512-FDenSF3fVqBYSaJoYy1KSc2wosx0gCvKP+c+PRBht7cAaiCeQlBtfBDX9vgnNOHmdePlSFITVcn4pFfcgNvx3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-ssh": "^1.4.0",
+ "parse-url": "^9.2.0"
+ }
+ },
+ "node_modules/git-url-parse": {
+ "version": "16.1.0",
+ "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-16.1.0.tgz",
+ "integrity": "sha512-cPLz4HuK86wClEW7iDdeAKcCVlWXmrLpb2L+G9goW0Z1dtpNS6BXXSOckUTlJT/LDQViE1QZKstNORzHsLnobw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "git-up": "^8.1.0"
+ }
+ },
+ "node_modules/glob": {
+ "version": "10.4.5",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
+ "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "foreground-child": "^3.1.0",
+ "jackspeak": "^3.1.2",
+ "minimatch": "^9.0.4",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^1.11.1"
+ },
+ "bin": {
+ "glob": "dist/esm/bin.mjs"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/glob-to-regexp": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
+ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
+ "license": "BSD-2-Clause",
+ "peer": true
+ },
+ "node_modules/global-directory": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz",
+ "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ini": "4.1.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/globby": {
+ "version": "14.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz",
+ "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@sindresorhus/merge-streams": "^2.1.0",
+ "fast-glob": "^3.3.3",
+ "ignore": "^7.0.3",
+ "path-type": "^6.0.0",
+ "slash": "^5.1.0",
+ "unicorn-magic": "^0.3.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "license": "ISC"
+ },
+ "node_modules/gzip-size": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-7.0.0.tgz",
+ "integrity": "sha512-O1Ld7Dr+nqPnmGpdhzLmMTQ4vAsD+rHwMm1NLUmoUFFymBOMKxCCrtDxqdBRYXdeEPEi3SyoR4TizJLQrnKBNA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "duplexer": "^0.1.2"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/h3": {
+ "version": "1.15.4",
+ "resolved": "https://registry.npmjs.org/h3/-/h3-1.15.4.tgz",
+ "integrity": "sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cookie-es": "^1.2.2",
+ "crossws": "^0.3.5",
+ "defu": "^6.1.4",
+ "destr": "^2.0.5",
+ "iron-webcrypto": "^1.2.1",
+ "node-mock-http": "^1.0.2",
+ "radix3": "^1.1.2",
+ "ufo": "^1.6.1",
+ "uncrypto": "^0.1.3"
+ }
+ },
+ "node_modules/h3/node_modules/cookie-es": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/cookie-es/-/cookie-es-1.2.2.tgz",
+ "integrity": "sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "he": "bin/he"
+ }
+ },
+ "node_modules/highlight.js": {
+ "version": "11.11.1",
+ "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz",
+ "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/hookable": {
+ "version": "5.5.3",
+ "resolved": "https://registry.npmjs.org/hookable/-/hookable-5.5.3.tgz",
+ "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/http-errors": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+ "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "depd": "2.0.0",
+ "inherits": "2.0.4",
+ "setprototypeof": "1.2.0",
+ "statuses": "2.0.1",
+ "toidentifier": "1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/http-errors/node_modules/statuses": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+ "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/http-shutdown": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/http-shutdown/-/http-shutdown-1.2.2.tgz",
+ "integrity": "sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "iojs": ">= 1.0.0",
+ "node": ">= 0.12.0"
+ }
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
+ "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "agent-base": "^7.1.2",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/httpxy": {
+ "version": "0.1.7",
+ "resolved": "https://registry.npmjs.org/httpxy/-/httpxy-0.1.7.tgz",
+ "integrity": "sha512-pXNx8gnANKAndgga5ahefxc++tJvNL87CXoRwxn1cJE2ZkWEojF3tNfQIEhZX/vfpt+wzeAzpUI4qkediX1MLQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/human-signals": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
+ "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=16.17.0"
+ }
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/ignore": {
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz",
+ "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/image-meta": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/image-meta/-/image-meta-0.2.1.tgz",
+ "integrity": "sha512-K6acvFaelNxx8wc2VjbIzXKDVB0Khs0QT35U6NkGfTdCmjLNcO2945m7RFNR9/RPVFm48hq7QPzK8uGH18HCGw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/immutable": {
+ "version": "5.1.3",
+ "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.3.tgz",
+ "integrity": "sha512-+chQdDfvscSF1SJqv2gn4SRO2ZyS3xL3r7IW/wWEEzrzLisnOlKiQu5ytC/BVNcS15C39WT2Hg/bjKjDMcu+zg==",
+ "license": "MIT",
+ "optional": true,
+ "peer": true
+ },
+ "node_modules/impound": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/impound/-/impound-1.0.0.tgz",
+ "integrity": "sha512-8lAJ+1Arw2sMaZ9HE2ZmL5zOcMnt18s6+7Xqgq2aUVy4P1nlzAyPtzCDxsk51KVFwHEEdc6OWvUyqwHwhRYaug==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "exsolve": "^1.0.5",
+ "mocked-exports": "^0.1.1",
+ "pathe": "^2.0.3",
+ "unplugin": "^2.3.2",
+ "unplugin-utils": "^0.2.4"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/ini": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz",
+ "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+ }
+ },
+ "node_modules/ioredis": {
+ "version": "5.7.0",
+ "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.7.0.tgz",
+ "integrity": "sha512-NUcA93i1lukyXU+riqEyPtSEkyFq8tX90uL659J+qpCZ3rEdViB/APC58oAhIh3+bJln2hzdlZbBZsGNrlsR8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@ioredis/commands": "^1.3.0",
+ "cluster-key-slot": "^1.1.0",
+ "debug": "^4.3.4",
+ "denque": "^2.1.0",
+ "lodash.defaults": "^4.2.0",
+ "lodash.isarguments": "^3.1.0",
+ "redis-errors": "^1.2.0",
+ "redis-parser": "^3.0.0",
+ "standard-as-callback": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=12.22.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/ioredis"
+ }
+ },
+ "node_modules/iron-webcrypto": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/iron-webcrypto/-/iron-webcrypto-1.2.1.tgz",
+ "integrity": "sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/brc-dd"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "license": "MIT",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.16.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
+ "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-docker": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
+ "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "is-docker": "cli.js"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-inside-container": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
+ "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-docker": "^3.0.0"
+ },
+ "bin": {
+ "is-inside-container": "cli.js"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-installed-globally": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-1.0.0.tgz",
+ "integrity": "sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "global-directory": "^4.0.1",
+ "is-path-inside": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-module": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
+ "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-path-inside": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz",
+ "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-reference": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
+ "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "*"
+ }
+ },
+ "node_modules/is-ssh": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.4.1.tgz",
+ "integrity": "sha512-JNeu1wQsHjyHgn9NcWTaXq6zWSR6hqE0++zhfZlkFBbScNkyvxCdeV8sRkSBaeLKxmbpR21brail63ACNxJ0Tg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "protocols": "^2.0.1"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
+ "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-what": {
+ "version": "4.1.16",
+ "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.16.tgz",
+ "integrity": "sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.13"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mesqueeb"
+ }
+ },
+ "node_modules/is-wsl": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz",
+ "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-inside-container": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is64bit": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is64bit/-/is64bit-2.0.0.tgz",
+ "integrity": "sha512-jv+8jaWCl0g2lSBkNSVXdzfBA0npK1HGC2KtWM9FumFRoGS94g3NbCCLVnCYHLjp4GrW2KZeeSTMo5ddtznmGw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "system-architecture": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/isexe": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz",
+ "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/jackspeak": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+ "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "@isaacs/cliui": "^8.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ },
+ "optionalDependencies": {
+ "@pkgjs/parseargs": "^0.11.0"
+ }
+ },
+ "node_modules/jest-worker": {
+ "version": "27.5.1",
+ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
+ "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@types/node": "*",
+ "merge-stream": "^2.0.0",
+ "supports-color": "^8.0.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/jest-worker/node_modules/supports-color": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+ "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/jiti": {
+ "version": "2.6.0",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.0.tgz",
+ "integrity": "sha512-VXe6RjJkBPj0ohtqaO8vSWP3ZhAKo66fKrFNCll4BTcwljPLz03pCbaNKfzGP5MbrCYcbJ7v0nOYYwUzTEIdXQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jiti": "lib/jiti-cli.mjs"
+ }
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+ "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/jsesc": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz",
+ "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/json-parse-even-better-errors": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+ "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+ "license": "MIT"
+ },
+ "node_modules/json5": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+ "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+ "license": "MIT",
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/kleur": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz",
+ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/klona": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz",
+ "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/knitwork": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/knitwork/-/knitwork-1.2.0.tgz",
+ "integrity": "sha512-xYSH7AvuQ6nXkq42x0v5S8/Iry+cfulBz/DJQzhIyESdLD7425jXsPy4vn5cCXU+HhRN2kVw51Vd1K6/By4BQg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/launch-editor": {
+ "version": "2.11.1",
+ "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.11.1.tgz",
+ "integrity": "sha512-SEET7oNfgSaB6Ym0jufAdCeo3meJVeCaaDyzRygy0xsp2BFKCprcfHljTq4QkzTLUxEKkFK6OK4811YM2oSrRg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "picocolors": "^1.1.1",
+ "shell-quote": "^1.8.3"
+ }
+ },
+ "node_modules/lazystream": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz",
+ "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "readable-stream": "^2.0.5"
+ },
+ "engines": {
+ "node": ">= 0.6.3"
+ }
+ },
+ "node_modules/lazystream/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/lazystream/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lazystream/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/lightningcss": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz",
+ "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==",
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-darwin-arm64": "1.30.1",
+ "lightningcss-darwin-x64": "1.30.1",
+ "lightningcss-freebsd-x64": "1.30.1",
+ "lightningcss-linux-arm-gnueabihf": "1.30.1",
+ "lightningcss-linux-arm64-gnu": "1.30.1",
+ "lightningcss-linux-arm64-musl": "1.30.1",
+ "lightningcss-linux-x64-gnu": "1.30.1",
+ "lightningcss-linux-x64-musl": "1.30.1",
+ "lightningcss-win32-arm64-msvc": "1.30.1",
+ "lightningcss-win32-x64-msvc": "1.30.1"
+ }
+ },
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz",
+ "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz",
+ "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz",
+ "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz",
+ "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz",
+ "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz",
+ "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz",
+ "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz",
+ "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz",
+ "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz",
+ "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MPL-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "peer": true,
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss/node_modules/detect-libc": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.0.tgz",
+ "integrity": "sha512-vEtk+OcP7VBRtQZ1EJ3bdgzSfBjgnEalLTp5zjJrS+2Z1w2KZly4SBdac/WDU3hhsNAZ9E8SC96ME4Ey8MZ7cg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "peer": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/lilconfig": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
+ "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antonk52"
+ }
+ },
+ "node_modules/listhen": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/listhen/-/listhen-1.9.0.tgz",
+ "integrity": "sha512-I8oW2+QL5KJo8zXNWX046M134WchxsXC7SawLPvRQpogCbkyQIaFxPE89A2HiwR7vAK2Dm2ERBAmyjTYGYEpBg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@parcel/watcher": "^2.4.1",
+ "@parcel/watcher-wasm": "^2.4.1",
+ "citty": "^0.1.6",
+ "clipboardy": "^4.0.0",
+ "consola": "^3.2.3",
+ "crossws": ">=0.2.0 <0.4.0",
+ "defu": "^6.1.4",
+ "get-port-please": "^3.1.2",
+ "h3": "^1.12.0",
+ "http-shutdown": "^1.2.2",
+ "jiti": "^2.1.2",
+ "mlly": "^1.7.1",
+ "node-forge": "^1.3.1",
+ "pathe": "^1.1.2",
+ "std-env": "^3.7.0",
+ "ufo": "^1.5.4",
+ "untun": "^0.1.3",
+ "uqr": "^0.1.2"
+ },
+ "bin": {
+ "listen": "bin/listhen.mjs",
+ "listhen": "bin/listhen.mjs"
+ }
+ },
+ "node_modules/listhen/node_modules/pathe": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz",
+ "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/loader-runner": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
+ "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=6.11.5"
+ }
+ },
+ "node_modules/loader-utils": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
+ "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
+ "license": "MIT",
+ "dependencies": {
+ "big.js": "^5.2.2",
+ "emojis-list": "^3.0.0",
+ "json5": "^2.1.2"
+ },
+ "engines": {
+ "node": ">=8.9.0"
+ }
+ },
+ "node_modules/local-pkg": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.1.2.tgz",
+ "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mlly": "^1.7.4",
+ "pkg-types": "^2.3.0",
+ "quansync": "^0.2.11"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.defaults": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
+ "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.isarguments": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
+ "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.memoize": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
+ "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.uniq": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
+ "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lru-cache": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+ "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^3.0.2"
+ }
+ },
+ "node_modules/magic-regexp": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/magic-regexp/-/magic-regexp-0.10.0.tgz",
+ "integrity": "sha512-Uly1Bu4lO1hwHUW0CQeSWuRtzCMNO00CmXtS8N6fyvB3B979GOEEeAkiTUDsmbYLAbvpUS/Kt5c4ibosAzVyVg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "estree-walker": "^3.0.3",
+ "magic-string": "^0.30.12",
+ "mlly": "^1.7.2",
+ "regexp-tree": "^0.1.27",
+ "type-level-regexp": "~0.1.17",
+ "ufo": "^1.5.4",
+ "unplugin": "^2.0.0"
+ }
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.19",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
+ "integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "node_modules/magic-string-ast": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/magic-string-ast/-/magic-string-ast-1.0.2.tgz",
+ "integrity": "sha512-8ngQgLhcT0t3YBdn9CGkZqCYlvwW9pm7aWJwd7AxseVWf1RU8ZHCQvG1mt3N5vvUme+pXTcHB8G/7fE666U8Vw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "magic-string": "^0.30.17"
+ },
+ "engines": {
+ "node": ">=20.18.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sxzz"
+ }
+ },
+ "node_modules/magicast": {
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz",
+ "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/parser": "^7.25.4",
+ "@babel/types": "^7.25.4",
+ "source-map-js": "^1.2.0"
+ }
+ },
+ "node_modules/mdn-data": {
+ "version": "2.12.2",
+ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz",
+ "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==",
+ "dev": true,
+ "license": "CC0-1.0"
+ },
+ "node_modules/merge-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+ "license": "MIT"
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/micromatch/node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/mime": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-4.1.0.tgz",
+ "integrity": "sha512-X5ju04+cAzsojXKes0B/S4tcYtFAJ6tTMuSPBEn9CPGlrWr8Fiw7qYeLT0XyH80HSoAoqWCaz+MWKh22P7G1cw==",
+ "dev": true,
+ "funding": [
+ "https://github.com/sponsors/broofa"
+ ],
+ "license": "MIT",
+ "bin": {
+ "mime": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.54.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
+ "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
+ "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "^1.54.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mimic-fn": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz",
+ "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/minipass": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/minizlib": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz",
+ "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "minipass": "^7.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/mitt": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
+ "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/mlly": {
+ "version": "1.8.0",
+ "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.0.tgz",
+ "integrity": "sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.15.0",
+ "pathe": "^2.0.3",
+ "pkg-types": "^1.3.1",
+ "ufo": "^1.6.1"
+ }
+ },
+ "node_modules/mlly/node_modules/confbox": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz",
+ "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/mlly/node_modules/pkg-types": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz",
+ "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "confbox": "^0.1.8",
+ "mlly": "^1.7.4",
+ "pathe": "^2.0.1"
+ }
+ },
+ "node_modules/mocked-exports": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/mocked-exports/-/mocked-exports-0.1.1.tgz",
+ "integrity": "sha512-aF7yRQr/Q0O2/4pIXm6PZ5G+jAd7QS4Yu8m+WEeEHGnbo+7mE36CbLSDQiXYV8bVL3NfmdeqPJct0tUlnjVSnA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/mrmime": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz",
+ "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/muggle-string": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz",
+ "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz",
+ "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.js"
+ },
+ "engines": {
+ "node": "^18 || >=20"
+ }
+ },
+ "node_modules/nanotar": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/nanotar/-/nanotar-0.2.0.tgz",
+ "integrity": "sha512-9ca1h0Xjvo9bEkE4UOxgAzLV0jHKe6LMaxo37ND2DAhhAtd0j8pR1Wxz+/goMrZO8AEZTWCmyaOsFI/W5AdpCQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/neo-async": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+ "license": "MIT"
+ },
+ "node_modules/nitropack": {
+ "version": "2.12.6",
+ "resolved": "https://registry.npmjs.org/nitropack/-/nitropack-2.12.6.tgz",
+ "integrity": "sha512-DEq31s0SP4/Z5DIoVBRo9DbWFPWwIoYD4cQMEz7eE+iJMiAP+1k9A3B9kcc6Ihc0jDJmfUcHYyh6h2XlynCx6g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@cloudflare/kv-asset-handler": "^0.4.0",
+ "@rollup/plugin-alias": "^5.1.1",
+ "@rollup/plugin-commonjs": "^28.0.6",
+ "@rollup/plugin-inject": "^5.0.5",
+ "@rollup/plugin-json": "^6.1.0",
+ "@rollup/plugin-node-resolve": "^16.0.1",
+ "@rollup/plugin-replace": "^6.0.2",
+ "@rollup/plugin-terser": "^0.4.4",
+ "@vercel/nft": "^0.30.1",
+ "archiver": "^7.0.1",
+ "c12": "^3.2.0",
+ "chokidar": "^4.0.3",
+ "citty": "^0.1.6",
+ "compatx": "^0.2.0",
+ "confbox": "^0.2.2",
+ "consola": "^3.4.2",
+ "cookie-es": "^2.0.0",
+ "croner": "^9.1.0",
+ "crossws": "^0.3.5",
+ "db0": "^0.3.2",
+ "defu": "^6.1.4",
+ "destr": "^2.0.5",
+ "dot-prop": "^9.0.0",
+ "esbuild": "^0.25.9",
+ "escape-string-regexp": "^5.0.0",
+ "etag": "^1.8.1",
+ "exsolve": "^1.0.7",
+ "globby": "^14.1.0",
+ "gzip-size": "^7.0.0",
+ "h3": "^1.15.4",
+ "hookable": "^5.5.3",
+ "httpxy": "^0.1.7",
+ "ioredis": "^5.7.0",
+ "jiti": "^2.5.1",
+ "klona": "^2.0.6",
+ "knitwork": "^1.2.0",
+ "listhen": "^1.9.0",
+ "magic-string": "^0.30.19",
+ "magicast": "^0.3.5",
+ "mime": "^4.0.7",
+ "mlly": "^1.8.0",
+ "node-fetch-native": "^1.6.7",
+ "node-mock-http": "^1.0.3",
+ "ofetch": "^1.4.1",
+ "ohash": "^2.0.11",
+ "pathe": "^2.0.3",
+ "perfect-debounce": "^2.0.0",
+ "pkg-types": "^2.3.0",
+ "pretty-bytes": "^7.0.1",
+ "radix3": "^1.1.2",
+ "rollup": "^4.50.1",
+ "rollup-plugin-visualizer": "^6.0.3",
+ "scule": "^1.3.0",
+ "semver": "^7.7.2",
+ "serve-placeholder": "^2.0.2",
+ "serve-static": "^2.2.0",
+ "source-map": "^0.7.6",
+ "std-env": "^3.9.0",
+ "ufo": "^1.6.1",
+ "ultrahtml": "^1.6.0",
+ "uncrypto": "^0.1.3",
+ "unctx": "^2.4.1",
+ "unenv": "^2.0.0-rc.21",
+ "unimport": "^5.2.0",
+ "unplugin-utils": "^0.3.0",
+ "unstorage": "^1.17.1",
+ "untyped": "^2.0.0",
+ "unwasm": "^0.3.11",
+ "youch": "^4.1.0-beta.11",
+ "youch-core": "^0.3.3"
+ },
+ "bin": {
+ "nitro": "dist/cli/index.mjs",
+ "nitropack": "dist/cli/index.mjs"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "peerDependencies": {
+ "xml2js": "^0.6.2"
+ },
+ "peerDependenciesMeta": {
+ "xml2js": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/nitropack/node_modules/unplugin-utils": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.0.tgz",
+ "integrity": "sha512-JLoggz+PvLVMJo+jZt97hdIIIZ2yTzGgft9e9q8iMrC4ewufl62ekeW7mixBghonn2gVb/ICjyvlmOCUBnJLQg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pathe": "^2.0.3",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=20.19.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sxzz"
+ }
+ },
+ "node_modules/node-addon-api": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz",
+ "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/node-fetch": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
+ "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/node-fetch-native": {
+ "version": "1.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz",
+ "integrity": "sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/node-forge": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
+ "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
+ "dev": true,
+ "license": "(BSD-3-Clause OR GPL-2.0)",
+ "engines": {
+ "node": ">= 6.13.0"
+ }
+ },
+ "node_modules/node-gyp-build": {
+ "version": "4.8.4",
+ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz",
+ "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "node-gyp-build": "bin.js",
+ "node-gyp-build-optional": "optional.js",
+ "node-gyp-build-test": "build-test.js"
+ }
+ },
+ "node_modules/node-mock-http": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/node-mock-http/-/node-mock-http-1.0.3.tgz",
+ "integrity": "sha512-jN8dK25fsfnMrVsEhluUTPkBFY+6ybu7jSB1n+ri/vOGjJxU8J9CZhpSGkHXSkFjtUhbmoncG/YG9ta5Ludqog==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.21",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.21.tgz",
+ "integrity": "sha512-5b0pgg78U3hwXkCM8Z9b2FJdPZlr9Psr9V2gQPESdGHqbntyFJKFW4r5TeWGFzafGY3hzs1JC62VEQMbl1JFkw==",
+ "license": "MIT"
+ },
+ "node_modules/nopt": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz",
+ "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "abbrev": "^3.0.0"
+ },
+ "bin": {
+ "nopt": "bin/nopt.js"
+ },
+ "engines": {
+ "node": "^18.17.0 || >=20.5.0"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/normalize-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-run-path": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz",
+ "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^4.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/npm-run-path/node_modules/path-key": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
+ "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/nth-check": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+ "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "boolbase": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/nth-check?sponsor=1"
+ }
+ },
+ "node_modules/nuxt": {
+ "version": "3.19.2",
+ "resolved": "https://registry.npmjs.org/nuxt/-/nuxt-3.19.2.tgz",
+ "integrity": "sha512-z4ouGRMOWqZ1xaZ+HdRBRVlZcKSoDBpRxQ30GJ2dllraZMC/gNpTGuY32H3xP5b4R29b8uYcK+B8LFQoRHpO8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nuxt/cli": "^3.28.0",
+ "@nuxt/devalue": "^2.0.2",
+ "@nuxt/devtools": "^2.6.3",
+ "@nuxt/kit": "3.19.2",
+ "@nuxt/schema": "3.19.2",
+ "@nuxt/telemetry": "^2.6.6",
+ "@nuxt/vite-builder": "3.19.2",
+ "@unhead/vue": "^2.0.14",
+ "@vue/shared": "^3.5.21",
+ "c12": "^3.2.0",
+ "chokidar": "^4.0.3",
+ "compatx": "^0.2.0",
+ "consola": "^3.4.2",
+ "cookie-es": "^2.0.0",
+ "defu": "^6.1.4",
+ "destr": "^2.0.5",
+ "devalue": "^5.3.2",
+ "errx": "^0.1.0",
+ "esbuild": "^0.25.9",
+ "escape-string-regexp": "^5.0.0",
+ "estree-walker": "^3.0.3",
+ "exsolve": "^1.0.7",
+ "h3": "^1.15.4",
+ "hookable": "^5.5.3",
+ "ignore": "^7.0.5",
+ "impound": "^1.0.0",
+ "jiti": "^2.5.1",
+ "klona": "^2.0.6",
+ "knitwork": "^1.2.0",
+ "magic-string": "^0.30.19",
+ "mlly": "^1.8.0",
+ "mocked-exports": "^0.1.1",
+ "nanotar": "^0.2.0",
+ "nitropack": "^2.12.5",
+ "nypm": "^0.6.1",
+ "ofetch": "^1.4.1",
+ "ohash": "^2.0.11",
+ "on-change": "^5.0.1",
+ "oxc-minify": "^0.87.0",
+ "oxc-parser": "^0.87.0",
+ "oxc-transform": "^0.87.0",
+ "oxc-walker": "^0.5.2",
+ "pathe": "^2.0.3",
+ "perfect-debounce": "^2.0.0",
+ "pkg-types": "^2.3.0",
+ "radix3": "^1.1.2",
+ "scule": "^1.3.0",
+ "semver": "^7.7.2",
+ "std-env": "^3.9.0",
+ "tinyglobby": "^0.2.15",
+ "ufo": "^1.6.1",
+ "ultrahtml": "^1.6.0",
+ "uncrypto": "^0.1.3",
+ "unctx": "^2.4.1",
+ "unimport": "^5.2.0",
+ "unplugin": "^2.3.10",
+ "unplugin-vue-router": "^0.15.0",
+ "unstorage": "^1.17.1",
+ "untyped": "^2.0.0",
+ "vue": "^3.5.21",
+ "vue-bundle-renderer": "^2.1.2",
+ "vue-devtools-stub": "^0.1.0",
+ "vue-router": "^4.5.1"
+ },
+ "bin": {
+ "nuxi": "bin/nuxt.mjs",
+ "nuxt": "bin/nuxt.mjs"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "peerDependencies": {
+ "@parcel/watcher": "^2.1.0",
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@parcel/watcher": {
+ "optional": true
+ },
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/nuxt/node_modules/@nuxt/schema": {
+ "version": "3.19.2",
+ "resolved": "https://registry.npmjs.org/@nuxt/schema/-/schema-3.19.2.tgz",
+ "integrity": "sha512-kMN2oIfrsMc8ACrRweYRG7Q44/KuHG5y7L+4szQhfOgN78OiYkxiM/nSsLH0K2bJq8Eavg+WGfgACj4Lsy+YqQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vue/shared": "^3.5.21",
+ "consola": "^3.4.2",
+ "defu": "^6.1.4",
+ "pathe": "^2.0.3",
+ "pkg-types": "^2.3.0",
+ "std-env": "^3.9.0",
+ "ufo": "1.6.1"
+ },
+ "engines": {
+ "node": "^14.18.0 || >=16.10.0"
+ }
+ },
+ "node_modules/nypm": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/nypm/-/nypm-0.6.2.tgz",
+ "integrity": "sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "citty": "^0.1.6",
+ "consola": "^3.4.2",
+ "pathe": "^2.0.3",
+ "pkg-types": "^2.3.0",
+ "tinyexec": "^1.0.1"
+ },
+ "bin": {
+ "nypm": "dist/cli.mjs"
+ },
+ "engines": {
+ "node": "^14.16.0 || >=16.10.0"
+ }
+ },
+ "node_modules/ofetch": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/ofetch/-/ofetch-1.4.1.tgz",
+ "integrity": "sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "destr": "^2.0.3",
+ "node-fetch-native": "^1.6.4",
+ "ufo": "^1.5.4"
+ }
+ },
+ "node_modules/ohash": {
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz",
+ "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/on-change": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/on-change/-/on-change-5.0.1.tgz",
+ "integrity": "sha512-n7THCP7RkyReRSLkJb8kUWoNsxUIBxTkIp3JKno+sEz6o/9AJ3w3P9fzQkITEkMwyTKJjZciF3v/pVoouxZZMg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/on-change?sponsor=1"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+ "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/onetime": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz",
+ "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "mimic-fn": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/open": {
+ "version": "8.4.2",
+ "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
+ "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-lazy-prop": "^2.0.0",
+ "is-docker": "^2.1.1",
+ "is-wsl": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/open/node_modules/is-docker": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
+ "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "is-docker": "cli.js"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/open/node_modules/is-wsl": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+ "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-docker": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/oxc-minify": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/oxc-minify/-/oxc-minify-0.87.0.tgz",
+ "integrity": "sha512-+UHWp6+0mdq0S2rEsZx9mqgL6JnG9ogO+CU17XccVrPUFtISFcZzk/biTn1JdBYFQ3kztof19pv8blMtgStQ2g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/Boshen"
+ },
+ "optionalDependencies": {
+ "@oxc-minify/binding-android-arm64": "0.87.0",
+ "@oxc-minify/binding-darwin-arm64": "0.87.0",
+ "@oxc-minify/binding-darwin-x64": "0.87.0",
+ "@oxc-minify/binding-freebsd-x64": "0.87.0",
+ "@oxc-minify/binding-linux-arm-gnueabihf": "0.87.0",
+ "@oxc-minify/binding-linux-arm-musleabihf": "0.87.0",
+ "@oxc-minify/binding-linux-arm64-gnu": "0.87.0",
+ "@oxc-minify/binding-linux-arm64-musl": "0.87.0",
+ "@oxc-minify/binding-linux-riscv64-gnu": "0.87.0",
+ "@oxc-minify/binding-linux-s390x-gnu": "0.87.0",
+ "@oxc-minify/binding-linux-x64-gnu": "0.87.0",
+ "@oxc-minify/binding-linux-x64-musl": "0.87.0",
+ "@oxc-minify/binding-wasm32-wasi": "0.87.0",
+ "@oxc-minify/binding-win32-arm64-msvc": "0.87.0",
+ "@oxc-minify/binding-win32-x64-msvc": "0.87.0"
+ }
+ },
+ "node_modules/oxc-parser": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/oxc-parser/-/oxc-parser-0.87.0.tgz",
+ "integrity": "sha512-uc47XrtHwkBoES4HFgwgfH9sqwAtJXgAIBq4fFBMZ4hWmgVZoExyn+L4g4VuaecVKXkz1bvlaHcfwHAJPQb5Gw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@oxc-project/types": "^0.87.0"
+ },
+ "engines": {
+ "node": ">=20.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/Boshen"
+ },
+ "optionalDependencies": {
+ "@oxc-parser/binding-android-arm64": "0.87.0",
+ "@oxc-parser/binding-darwin-arm64": "0.87.0",
+ "@oxc-parser/binding-darwin-x64": "0.87.0",
+ "@oxc-parser/binding-freebsd-x64": "0.87.0",
+ "@oxc-parser/binding-linux-arm-gnueabihf": "0.87.0",
+ "@oxc-parser/binding-linux-arm-musleabihf": "0.87.0",
+ "@oxc-parser/binding-linux-arm64-gnu": "0.87.0",
+ "@oxc-parser/binding-linux-arm64-musl": "0.87.0",
+ "@oxc-parser/binding-linux-riscv64-gnu": "0.87.0",
+ "@oxc-parser/binding-linux-s390x-gnu": "0.87.0",
+ "@oxc-parser/binding-linux-x64-gnu": "0.87.0",
+ "@oxc-parser/binding-linux-x64-musl": "0.87.0",
+ "@oxc-parser/binding-wasm32-wasi": "0.87.0",
+ "@oxc-parser/binding-win32-arm64-msvc": "0.87.0",
+ "@oxc-parser/binding-win32-x64-msvc": "0.87.0"
+ }
+ },
+ "node_modules/oxc-transform": {
+ "version": "0.87.0",
+ "resolved": "https://registry.npmjs.org/oxc-transform/-/oxc-transform-0.87.0.tgz",
+ "integrity": "sha512-dt6INKWY2DKbSc8yR9VQoqBsCjPQ3z/SKv882UqlwFve+K38xtpi2avDlvNd35SpHUwDLDFoV3hMX0U3qOSaaQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/Boshen"
+ },
+ "optionalDependencies": {
+ "@oxc-transform/binding-android-arm64": "0.87.0",
+ "@oxc-transform/binding-darwin-arm64": "0.87.0",
+ "@oxc-transform/binding-darwin-x64": "0.87.0",
+ "@oxc-transform/binding-freebsd-x64": "0.87.0",
+ "@oxc-transform/binding-linux-arm-gnueabihf": "0.87.0",
+ "@oxc-transform/binding-linux-arm-musleabihf": "0.87.0",
+ "@oxc-transform/binding-linux-arm64-gnu": "0.87.0",
+ "@oxc-transform/binding-linux-arm64-musl": "0.87.0",
+ "@oxc-transform/binding-linux-riscv64-gnu": "0.87.0",
+ "@oxc-transform/binding-linux-s390x-gnu": "0.87.0",
+ "@oxc-transform/binding-linux-x64-gnu": "0.87.0",
+ "@oxc-transform/binding-linux-x64-musl": "0.87.0",
+ "@oxc-transform/binding-wasm32-wasi": "0.87.0",
+ "@oxc-transform/binding-win32-arm64-msvc": "0.87.0",
+ "@oxc-transform/binding-win32-x64-msvc": "0.87.0"
+ }
+ },
+ "node_modules/oxc-walker": {
+ "version": "0.5.2",
+ "resolved": "https://registry.npmjs.org/oxc-walker/-/oxc-walker-0.5.2.tgz",
+ "integrity": "sha512-XYoZqWwApSKUmSDEFeOKdy3Cdh95cOcSU8f7yskFWE4Rl3cfL5uwyY+EV7Brk9mdNLy+t5SseJajd6g7KncvlA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "magic-regexp": "^0.10.0"
+ },
+ "peerDependencies": {
+ "oxc-parser": ">=0.72.0"
+ }
+ },
+ "node_modules/package-json-from-dist": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+ "dev": true,
+ "license": "BlueOak-1.0.0"
+ },
+ "node_modules/package-manager-detector": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.3.0.tgz",
+ "integrity": "sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/parse-path": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-7.1.0.tgz",
+ "integrity": "sha512-EuCycjZtfPcjWk7KTksnJ5xPMvWGA/6i4zrLYhRG0hGvC3GPU/jGUj3Cy+ZR0v30duV3e23R95T1lE2+lsndSw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "protocols": "^2.0.0"
+ }
+ },
+ "node_modules/parse-url": {
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-9.2.0.tgz",
+ "integrity": "sha512-bCgsFI+GeGWPAvAiUv63ZorMeif3/U0zaXABGJbOWt5OH2KCaPHF6S+0ok4aqM9RuIPGyZdx9tR9l13PsW4AYQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/parse-path": "^7.0.0",
+ "parse-path": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=14.13.0"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+ "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/path-browserify": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
+ "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/path-scurry": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "lru-cache": "^10.2.0",
+ "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/path-scurry/node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/path-type": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz",
+ "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/pathe": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz",
+ "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/perfect-debounce": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.0.0.tgz",
+ "integrity": "sha512-fkEH/OBiKrqqI/yIgjR92lMfs2K8105zt/VT6+7eTjNwisrsh47CeIED9z58zI7DfKdH3uHAn25ziRZn3kgAow==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pinia": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/pinia/-/pinia-2.3.1.tgz",
+ "integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/devtools-api": "^6.6.3",
+ "vue-demi": "^0.14.10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/posva"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.4.4",
+ "vue": "^2.7.0 || ^3.5.11"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/pkg-types": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.0.tgz",
+ "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "confbox": "^0.2.2",
+ "exsolve": "^1.0.7",
+ "pathe": "^2.0.3"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.6",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
+ "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.11",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/postcss-calc": {
+ "version": "10.1.1",
+ "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-10.1.1.tgz",
+ "integrity": "sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "postcss-selector-parser": "^7.0.0",
+ "postcss-value-parser": "^4.2.0"
+ },
+ "engines": {
+ "node": "^18.12 || ^20.9 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.38"
+ }
+ },
+ "node_modules/postcss-colormin": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-7.0.4.tgz",
+ "integrity": "sha512-ziQuVzQZBROpKpfeDwmrG+Vvlr0YWmY/ZAk99XD+mGEBuEojoFekL41NCsdhyNUtZI7DPOoIWIR7vQQK9xwluw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "browserslist": "^4.25.1",
+ "caniuse-api": "^3.0.0",
+ "colord": "^2.9.3",
+ "postcss-value-parser": "^4.2.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-convert-values": {
+ "version": "7.0.7",
+ "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-7.0.7.tgz",
+ "integrity": "sha512-HR9DZLN04Xbe6xugRH6lS4ZQH2zm/bFh/ZyRkpedZozhvh+awAfbA0P36InO4fZfDhvYfNJeNvlTf1sjwGbw/A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "browserslist": "^4.25.1",
+ "postcss-value-parser": "^4.2.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-discard-comments": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-7.0.4.tgz",
+ "integrity": "sha512-6tCUoql/ipWwKtVP/xYiFf1U9QgJ0PUvxN7pTcsQ8Ns3Fnwq1pU5D5s1MhT/XySeLq6GXNvn37U46Ded0TckWg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "postcss-selector-parser": "^7.1.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-discard-duplicates": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-7.0.2.tgz",
+ "integrity": "sha512-eTonaQvPZ/3i1ASDHOKkYwAybiM45zFIc7KXils4mQmHLqIswXD9XNOKEVxtTFnsmwYzF66u4LMgSr0abDlh5w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-discard-empty": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-7.0.1.tgz",
+ "integrity": "sha512-cFrJKZvcg/uxB6Ijr4l6qmn3pXQBna9zyrPC+sK0zjbkDUZew+6xDltSF7OeB7rAtzaaMVYSdbod+sZOCWnMOg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-discard-overridden": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-7.0.1.tgz",
+ "integrity": "sha512-7c3MMjjSZ/qYrx3uc1940GSOzN1Iqjtlqe8uoSg+qdVPYyRb0TILSqqmtlSFuE4mTDECwsm397Ya7iXGzfF7lg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-merge-longhand": {
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-7.0.5.tgz",
+ "integrity": "sha512-Kpu5v4Ys6QI59FxmxtNB/iHUVDn9Y9sYw66D6+SZoIk4QTz1prC4aYkhIESu+ieG1iylod1f8MILMs1Em3mmIw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "postcss-value-parser": "^4.2.0",
+ "stylehacks": "^7.0.5"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-merge-rules": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-7.0.6.tgz",
+ "integrity": "sha512-2jIPT4Tzs8K87tvgCpSukRQ2jjd+hH6Bb8rEEOUDmmhOeTcqDg5fEFK8uKIu+Pvc3//sm3Uu6FRqfyv7YF7+BQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "browserslist": "^4.25.1",
+ "caniuse-api": "^3.0.0",
+ "cssnano-utils": "^5.0.1",
+ "postcss-selector-parser": "^7.1.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-minify-font-values": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-7.0.1.tgz",
+ "integrity": "sha512-2m1uiuJeTplll+tq4ENOQSzB8LRnSUChBv7oSyFLsJRtUgAAJGP6LLz0/8lkinTgxrmJSPOEhgY1bMXOQ4ZXhQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "postcss-value-parser": "^4.2.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-minify-gradients": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-7.0.1.tgz",
+ "integrity": "sha512-X9JjaysZJwlqNkJbUDgOclyG3jZEpAMOfof6PUZjPnPrePnPG62pS17CjdM32uT1Uq1jFvNSff9l7kNbmMSL2A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "colord": "^2.9.3",
+ "cssnano-utils": "^5.0.1",
+ "postcss-value-parser": "^4.2.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-minify-params": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-7.0.4.tgz",
+ "integrity": "sha512-3OqqUddfH8c2e7M35W6zIwv7jssM/3miF9cbCSb1iJiWvtguQjlxZGIHK9JRmc8XAKmE2PFGtHSM7g/VcW97sw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "browserslist": "^4.25.1",
+ "cssnano-utils": "^5.0.1",
+ "postcss-value-parser": "^4.2.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-minify-selectors": {
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-7.0.5.tgz",
+ "integrity": "sha512-x2/IvofHcdIrAm9Q+p06ZD1h6FPcQ32WtCRVodJLDR+WMn8EVHI1kvLxZuGKz/9EY5nAmI6lIQIrpo4tBy5+ug==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "postcss-selector-parser": "^7.1.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-normalize-charset": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-7.0.1.tgz",
+ "integrity": "sha512-sn413ofhSQHlZFae//m9FTOfkmiZ+YQXsbosqOWRiVQncU2BA3daX3n0VF3cG6rGLSFVc5Di/yns0dFfh8NFgQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-normalize-display-values": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-7.0.1.tgz",
+ "integrity": "sha512-E5nnB26XjSYz/mGITm6JgiDpAbVuAkzXwLzRZtts19jHDUBFxZ0BkXAehy0uimrOjYJbocby4FVswA/5noOxrQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "postcss-value-parser": "^4.2.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-normalize-positions": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-7.0.1.tgz",
+ "integrity": "sha512-pB/SzrIP2l50ZIYu+yQZyMNmnAcwyYb9R1fVWPRxm4zcUFCY2ign7rcntGFuMXDdd9L2pPNUgoODDk91PzRZuQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "postcss-value-parser": "^4.2.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-normalize-repeat-style": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-7.0.1.tgz",
+ "integrity": "sha512-NsSQJ8zj8TIDiF0ig44Byo3Jk9e4gNt9x2VIlJudnQQ5DhWAHJPF4Tr1ITwyHio2BUi/I6Iv0HRO7beHYOloYQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "postcss-value-parser": "^4.2.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-normalize-string": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-7.0.1.tgz",
+ "integrity": "sha512-QByrI7hAhsoze992kpbMlJSbZ8FuCEc1OT9EFbZ6HldXNpsdpZr+YXC5di3UEv0+jeZlHbZcoCADgb7a+lPmmQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "postcss-value-parser": "^4.2.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-normalize-timing-functions": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-7.0.1.tgz",
+ "integrity": "sha512-bHifyuuSNdKKsnNJ0s8fmfLMlvsQwYVxIoUBnowIVl2ZAdrkYQNGVB4RxjfpvkMjipqvbz0u7feBZybkl/6NJg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "postcss-value-parser": "^4.2.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-normalize-unicode": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-7.0.4.tgz",
+ "integrity": "sha512-LvIURTi1sQoZqj8mEIE8R15yvM+OhbR1avynMtI9bUzj5gGKR/gfZFd8O7VMj0QgJaIFzxDwxGl/ASMYAkqO8g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "browserslist": "^4.25.1",
+ "postcss-value-parser": "^4.2.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-normalize-url": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-7.0.1.tgz",
+ "integrity": "sha512-sUcD2cWtyK1AOL/82Fwy1aIVm/wwj5SdZkgZ3QiUzSzQQofrbq15jWJ3BA7Z+yVRwamCjJgZJN0I9IS7c6tgeQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "postcss-value-parser": "^4.2.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-normalize-whitespace": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-7.0.1.tgz",
+ "integrity": "sha512-vsbgFHMFQrJBJKrUFJNZ2pgBeBkC2IvvoHjz1to0/0Xk7sII24T0qFOiJzG6Fu3zJoq/0yI4rKWi7WhApW+EFA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "postcss-value-parser": "^4.2.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-ordered-values": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-7.0.2.tgz",
+ "integrity": "sha512-AMJjt1ECBffF7CEON/Y0rekRLS6KsePU6PRP08UqYW4UGFRnTXNrByUzYK1h8AC7UWTZdQ9O3Oq9kFIhm0SFEw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cssnano-utils": "^5.0.1",
+ "postcss-value-parser": "^4.2.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-reduce-initial": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-7.0.4.tgz",
+ "integrity": "sha512-rdIC9IlMBn7zJo6puim58Xd++0HdbvHeHaPgXsimMfG1ijC5A9ULvNLSE0rUKVJOvNMcwewW4Ga21ngyJjY/+Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "browserslist": "^4.25.1",
+ "caniuse-api": "^3.0.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-reduce-transforms": {
+ "version": "7.0.1",
+ "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-7.0.1.tgz",
+ "integrity": "sha512-MhyEbfrm+Mlp/36hvZ9mT9DaO7dbncU0CvWI8V93LRkY6IYlu38OPg3FObnuKTUxJ4qA8HpurdQOo5CyqqO76g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "postcss-value-parser": "^4.2.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-selector-parser": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz",
+ "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cssesc": "^3.0.0",
+ "util-deprecate": "^1.0.2"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/postcss-svgo": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-7.1.0.tgz",
+ "integrity": "sha512-KnAlfmhtoLz6IuU3Sij2ycusNs4jPW+QoFE5kuuUOK8awR6tMxZQrs5Ey3BUz7nFCzT3eqyFgqkyrHiaU2xx3w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "postcss-value-parser": "^4.2.0",
+ "svgo": "^4.0.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >= 18"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-unique-selectors": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-7.0.4.tgz",
+ "integrity": "sha512-pmlZjsmEAG7cHd7uK3ZiNSW6otSZ13RHuZ/4cDN/bVglS5EpF2r2oxY99SuOHa8m7AWoBCelTS3JPpzsIs8skQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "postcss-selector-parser": "^7.1.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/postcss/node_modules/nanoid": {
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/prettier": {
+ "version": "2.8.8",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
+ "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
+ "license": "MIT",
+ "optional": true,
+ "peer": true,
+ "bin": {
+ "prettier": "bin-prettier.js"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/pretty-bytes": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-7.1.0.tgz",
+ "integrity": "sha512-nODzvTiYVRGRqAOvE84Vk5JDPyyxsVk0/fbA/bq7RqlnhksGpset09XTxbpvLTIjoaF7K8Z8DG8yHtKGTPSYRw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/prompts": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz",
+ "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "kleur": "^3.0.3",
+ "sisteransi": "^1.0.5"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/protocols": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/protocols/-/protocols-2.0.2.tgz",
+ "integrity": "sha512-hHVTzba3wboROl0/aWRRG9dMytgH6ow//STBZh43l/wQgmMhYhOFi0EHWAPtoCz9IAUymsyP0TSBHkhgMEGNnQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/punycode": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
+ "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/quansync": {
+ "version": "0.2.11",
+ "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz",
+ "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/antfu"
+ },
+ {
+ "type": "individual",
+ "url": "https://github.com/sponsors/sxzz"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/radix3": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/radix3/-/radix3-1.1.2.tgz",
+ "integrity": "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/randombytes": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+ "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/rc9": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/rc9/-/rc9-2.1.2.tgz",
+ "integrity": "sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "defu": "^6.1.4",
+ "destr": "^2.0.3"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
+ "integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "abort-controller": "^3.0.0",
+ "buffer": "^6.0.3",
+ "events": "^3.3.0",
+ "process": "^0.11.10",
+ "string_decoder": "^1.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/readdir-glob": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz",
+ "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "minimatch": "^5.1.0"
+ }
+ },
+ "node_modules/readdir-glob/node_modules/minimatch": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
+ "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
+ "devOptional": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 14.18.0"
+ },
+ "funding": {
+ "type": "individual",
+ "url": "https://paulmillr.com/funding/"
+ }
+ },
+ "node_modules/redis-errors": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
+ "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/redis-parser": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
+ "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "redis-errors": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/regexp-tree": {
+ "version": "0.1.27",
+ "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.27.tgz",
+ "integrity": "sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "regexp-tree": "bin/regexp-tree"
+ }
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.22.10",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
+ "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-core-module": "^2.16.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-from": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+ "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rfdc": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
+ "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/rollup": {
+ "version": "4.52.1",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.52.1.tgz",
+ "integrity": "sha512-/vFSi3I+ya/D75UZh5GxLc/6UQ+KoKPEvL9autr1yGcaeWzXBQr1tTXmNDS4FImFCPwBAvVe7j9YzR8PQ5rfqw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.8"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.52.1",
+ "@rollup/rollup-android-arm64": "4.52.1",
+ "@rollup/rollup-darwin-arm64": "4.52.1",
+ "@rollup/rollup-darwin-x64": "4.52.1",
+ "@rollup/rollup-freebsd-arm64": "4.52.1",
+ "@rollup/rollup-freebsd-x64": "4.52.1",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.52.1",
+ "@rollup/rollup-linux-arm-musleabihf": "4.52.1",
+ "@rollup/rollup-linux-arm64-gnu": "4.52.1",
+ "@rollup/rollup-linux-arm64-musl": "4.52.1",
+ "@rollup/rollup-linux-loong64-gnu": "4.52.1",
+ "@rollup/rollup-linux-ppc64-gnu": "4.52.1",
+ "@rollup/rollup-linux-riscv64-gnu": "4.52.1",
+ "@rollup/rollup-linux-riscv64-musl": "4.52.1",
+ "@rollup/rollup-linux-s390x-gnu": "4.52.1",
+ "@rollup/rollup-linux-x64-gnu": "4.52.1",
+ "@rollup/rollup-linux-x64-musl": "4.52.1",
+ "@rollup/rollup-openharmony-arm64": "4.52.1",
+ "@rollup/rollup-win32-arm64-msvc": "4.52.1",
+ "@rollup/rollup-win32-ia32-msvc": "4.52.1",
+ "@rollup/rollup-win32-x64-gnu": "4.52.1",
+ "@rollup/rollup-win32-x64-msvc": "4.52.1",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/rollup-plugin-visualizer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/rollup-plugin-visualizer/-/rollup-plugin-visualizer-6.0.3.tgz",
+ "integrity": "sha512-ZU41GwrkDcCpVoffviuM9Clwjy5fcUxlz0oMoTXTYsK+tcIFzbdacnrr2n8TXcHxbGKKXtOdjxM2HUS4HjkwIw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "open": "^8.0.0",
+ "picomatch": "^4.0.2",
+ "source-map": "^0.7.4",
+ "yargs": "^17.5.1"
+ },
+ "bin": {
+ "rollup-plugin-visualizer": "dist/bin/cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "rolldown": "1.x || ^1.0.0-beta",
+ "rollup": "2.x || 3.x || 4.x"
+ },
+ "peerDependenciesMeta": {
+ "rolldown": {
+ "optional": true
+ },
+ "rollup": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/run-applescript": {
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz",
+ "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+ "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/sass": {
+ "version": "1.93.1",
+ "resolved": "https://registry.npmjs.org/sass/-/sass-1.93.1.tgz",
+ "integrity": "sha512-wLAeLB7IksO2u+cCfhHqcy7/2ZUMPp/X2oV6+LjmweTqgjhOKrkaE/Q1wljxtco5EcOcupZ4c981X0gpk5Tiag==",
+ "license": "MIT",
+ "optional": true,
+ "peer": true,
+ "dependencies": {
+ "chokidar": "^4.0.0",
+ "immutable": "^5.0.2",
+ "source-map-js": ">=0.6.2 <2.0.0"
+ },
+ "bin": {
+ "sass": "sass.js"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "optionalDependencies": {
+ "@parcel/watcher": "^2.4.1"
+ }
+ },
+ "node_modules/sass-loader": {
+ "version": "10.5.2",
+ "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-10.5.2.tgz",
+ "integrity": "sha512-vMUoSNOUKJILHpcNCCyD23X34gve1TS7Rjd9uXHeKqhvBG39x6XbswFDtpbTElj6XdMFezoWhkh5vtKudf2cgQ==",
+ "license": "MIT",
+ "dependencies": {
+ "klona": "^2.0.4",
+ "loader-utils": "^2.0.0",
+ "neo-async": "^2.6.2",
+ "schema-utils": "^3.0.0",
+ "semver": "^7.3.2"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ },
+ "peerDependencies": {
+ "fibers": ">= 3.1.0",
+ "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0",
+ "sass": "^1.3.0",
+ "webpack": "^4.36.0 || ^5.0.0"
+ },
+ "peerDependenciesMeta": {
+ "fibers": {
+ "optional": true
+ },
+ "node-sass": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/sax": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
+ "integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/schema-utils": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
+ "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/json-schema": "^7.0.8",
+ "ajv": "^6.12.5",
+ "ajv-keywords": "^3.5.2"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/scule": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/scule/-/scule-1.3.0.tgz",
+ "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/send": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
+ "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.5",
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "etag": "^1.8.1",
+ "fresh": "^2.0.0",
+ "http-errors": "^2.0.0",
+ "mime-types": "^3.0.1",
+ "ms": "^2.1.3",
+ "on-finished": "^2.4.1",
+ "range-parser": "^1.2.1",
+ "statuses": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/serialize-javascript": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
+ "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "randombytes": "^2.1.0"
+ }
+ },
+ "node_modules/serve-placeholder": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/serve-placeholder/-/serve-placeholder-2.0.2.tgz",
+ "integrity": "sha512-/TMG8SboeiQbZJWRlfTCqMs2DD3SZgWp0kDQePz9yUuCnDfDh/92gf7/PxGhzXTKBIPASIHxFcZndoNbp6QOLQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "defu": "^6.1.4"
+ }
+ },
+ "node_modules/serve-static": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz",
+ "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "^2.0.0",
+ "escape-html": "^1.0.3",
+ "parseurl": "^1.3.3",
+ "send": "^1.2.0"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+ "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+ "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shell-quote": {
+ "version": "1.8.3",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz",
+ "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/simple-git": {
+ "version": "3.28.0",
+ "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.28.0.tgz",
+ "integrity": "sha512-Rs/vQRwsn1ILH1oBUy8NucJlXmnnLeLCfcvbSehkPzbv3wwoFWIdtfd6Ndo6ZPhlPsCZ60CPI4rxurnwAa+a2w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@kwsites/file-exists": "^1.1.1",
+ "@kwsites/promise-deferred": "^1.1.1",
+ "debug": "^4.4.0"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/steveukx/git-js?sponsor=1"
+ }
+ },
+ "node_modules/sirv": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz",
+ "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@polka/url": "^1.0.0-next.24",
+ "mrmime": "^2.0.0",
+ "totalist": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/sisteransi": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
+ "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/slash": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz",
+ "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/smob": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz",
+ "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/source-map": {
+ "version": "0.7.6",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz",
+ "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-support": {
+ "version": "0.5.21",
+ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+ "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+ "license": "MIT",
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/source-map-support/node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/speakingurl": {
+ "version": "14.0.1",
+ "resolved": "https://registry.npmjs.org/speakingurl/-/speakingurl-14.0.1.tgz",
+ "integrity": "sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/standard-as-callback": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
+ "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/statuses": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
+ "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/std-env": {
+ "version": "3.9.0",
+ "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz",
+ "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/streamx": {
+ "version": "2.23.0",
+ "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.23.0.tgz",
+ "integrity": "sha512-kn+e44esVfn2Fa/O0CPFcex27fjIL6MkVae0Mm6q+E6f0hWv578YCERbv+4m02cjxvDsPKLnmxral/rR6lBMAg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "events-universal": "^1.0.0",
+ "fast-fifo": "^1.3.2",
+ "text-decoder": "^1.1.0"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/string-width": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
+ "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eastasianwidth": "^0.2.0",
+ "emoji-regex": "^9.2.2",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/string-width-cjs": {
+ "name": "string-width",
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width-cjs/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width-cjs/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/string-width-cjs/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
+ "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
+ "node_modules/strip-ansi-cjs": {
+ "name": "strip-ansi",
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-final-newline": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
+ "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/strip-literal": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-3.0.0.tgz",
+ "integrity": "sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "js-tokens": "^9.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
+ "node_modules/strip-literal/node_modules/js-tokens": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz",
+ "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/structured-clone-es": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/structured-clone-es/-/structured-clone-es-1.0.0.tgz",
+ "integrity": "sha512-FL8EeKFFyNQv5cMnXI31CIMCsFarSVI2bF0U0ImeNE3g/F1IvJQyqzOXxPBRXiwQfyBTlbNe88jh1jFW0O/jiQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/stylehacks": {
+ "version": "7.0.6",
+ "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-7.0.6.tgz",
+ "integrity": "sha512-iitguKivmsueOmTO0wmxURXBP8uqOO+zikLGZ7Mm9e/94R4w5T999Js2taS/KBOnQ/wdC3jN3vNSrkGDrlnqQg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "browserslist": "^4.25.1",
+ "postcss-selector-parser": "^7.1.0"
+ },
+ "engines": {
+ "node": "^18.12.0 || ^20.9.0 || >=22.0"
+ },
+ "peerDependencies": {
+ "postcss": "^8.4.32"
+ }
+ },
+ "node_modules/superjson": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/superjson/-/superjson-2.2.2.tgz",
+ "integrity": "sha512-5JRxVqC8I8NuOUjzBbvVJAKNM8qoVuH0O77h4WInc/qC2q5IreqKxYwgkga3PfA22OayK2ikceb/B26dztPl+Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "copy-anything": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "10.2.2",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz",
+ "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/svgo": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.0.tgz",
+ "integrity": "sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "commander": "^11.1.0",
+ "css-select": "^5.1.0",
+ "css-tree": "^3.0.1",
+ "css-what": "^6.1.0",
+ "csso": "^5.0.5",
+ "picocolors": "^1.1.1",
+ "sax": "^1.4.1"
+ },
+ "bin": {
+ "svgo": "bin/svgo.js"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/svgo"
+ }
+ },
+ "node_modules/system-architecture": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/system-architecture/-/system-architecture-0.1.0.tgz",
+ "integrity": "sha512-ulAk51I9UVUyJgxlv9M6lFot2WP3e7t8Kz9+IS6D4rVba1tR9kON+Ey69f+1R4Q8cd45Lod6a4IcJIxnzGc/zA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/tapable": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.3.tgz",
+ "integrity": "sha512-ZL6DDuAlRlLGghwcfmSn9sK3Hr6ArtyudlSAiCqQ6IfE+b+HHbydbYDIG15IfS5do+7XQQBdBiubF/cV2dnDzg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/tar": {
+ "version": "7.4.4",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.4.tgz",
+ "integrity": "sha512-O1z7ajPkjTgEgmTGz0v9X4eqeEXTDREPTO77pVC1Nbs86feBU1Zhdg+edzavPmYW1olxkwsqA2v4uOw6E8LeDg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@isaacs/fs-minipass": "^4.0.0",
+ "chownr": "^3.0.0",
+ "minipass": "^7.1.2",
+ "minizlib": "^3.1.0",
+ "yallist": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tar-stream": {
+ "version": "3.1.7",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz",
+ "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "b4a": "^1.6.4",
+ "fast-fifo": "^1.2.0",
+ "streamx": "^2.15.0"
+ }
+ },
+ "node_modules/tar/node_modules/yallist": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
+ "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/terser": {
+ "version": "5.44.0",
+ "resolved": "https://registry.npmjs.org/terser/-/terser-5.44.0.tgz",
+ "integrity": "sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@jridgewell/source-map": "^0.3.3",
+ "acorn": "^8.15.0",
+ "commander": "^2.20.0",
+ "source-map-support": "~0.5.20"
+ },
+ "bin": {
+ "terser": "bin/terser"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/terser-webpack-plugin": {
+ "version": "5.3.14",
+ "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz",
+ "integrity": "sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@jridgewell/trace-mapping": "^0.3.25",
+ "jest-worker": "^27.4.5",
+ "schema-utils": "^4.3.0",
+ "serialize-javascript": "^6.0.2",
+ "terser": "^5.31.1"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ },
+ "peerDependencies": {
+ "webpack": "^5.1.0"
+ },
+ "peerDependenciesMeta": {
+ "@swc/core": {
+ "optional": true
+ },
+ "esbuild": {
+ "optional": true
+ },
+ "uglify-js": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/terser-webpack-plugin/node_modules/ajv": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+ "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3"
+ },
+ "peerDependencies": {
+ "ajv": "^8.8.2"
+ }
+ },
+ "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/terser-webpack-plugin/node_modules/schema-utils": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz",
+ "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@types/json-schema": "^7.0.9",
+ "ajv": "^8.9.0",
+ "ajv-formats": "^2.1.1",
+ "ajv-keywords": "^5.1.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/terser/node_modules/commander": {
+ "version": "2.20.3",
+ "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+ "license": "MIT"
+ },
+ "node_modules/text-decoder": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz",
+ "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "b4a": "^1.6.4"
+ }
+ },
+ "node_modules/tiny-invariant": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz",
+ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tinyexec": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.1.tgz",
+ "integrity": "sha512-5uC6DDlmeqiOwCPmK9jMSdOuZTh8bU39Ys6yidB+UTt5hfZUPGAypSgFRiEp+jbi9qH40BLDvy85jIU88wKSqw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.15",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+ "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/totalist": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz",
+ "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/tslib": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
+ "dev": true,
+ "license": "0BSD",
+ "optional": true
+ },
+ "node_modules/type-fest": {
+ "version": "4.41.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz",
+ "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/type-level-regexp": {
+ "version": "0.1.17",
+ "resolved": "https://registry.npmjs.org/type-level-regexp/-/type-level-regexp-0.1.17.tgz",
+ "integrity": "sha512-wTk4DH3cxwk196uGLK/E9pE45aLfeKJacKmcEgEOA/q5dnPGNxXt0cfYdFxb57L+sEpf1oJH4Dnx/pnRcku9jg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/typescript": {
+ "version": "5.9.2",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
+ "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
+ "devOptional": true,
+ "license": "Apache-2.0",
+ "peer": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/ufo": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz",
+ "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/ultrahtml": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.6.0.tgz",
+ "integrity": "sha512-R9fBn90VTJrqqLDwyMph+HGne8eqY1iPfYhPzZrvKpIfwkWZbcYlfpsb8B9dTvBfpy1/hqAD7Wi8EKfP9e8zdw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/uncrypto": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/uncrypto/-/uncrypto-0.1.3.tgz",
+ "integrity": "sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/unctx": {
+ "version": "2.4.1",
+ "resolved": "https://registry.npmjs.org/unctx/-/unctx-2.4.1.tgz",
+ "integrity": "sha512-AbaYw0Nm4mK4qjhns67C+kgxR2YWiwlDBPzxrN8h8C6VtAdCgditAY5Dezu3IJy4XVqAnbrXt9oQJvsn3fyozg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.14.0",
+ "estree-walker": "^3.0.3",
+ "magic-string": "^0.30.17",
+ "unplugin": "^2.1.0"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "7.12.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.12.0.tgz",
+ "integrity": "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/unenv": {
+ "version": "2.0.0-rc.21",
+ "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.21.tgz",
+ "integrity": "sha512-Wj7/AMtE9MRnAXa6Su3Lk0LNCfqDYgfwVjwRFVum9U7wsto1imuHqk4kTm7Jni+5A0Hn7dttL6O/zjvUvoo+8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "defu": "^6.1.4",
+ "exsolve": "^1.0.7",
+ "ohash": "^2.0.11",
+ "pathe": "^2.0.3",
+ "ufo": "^1.6.1"
+ }
+ },
+ "node_modules/unhead": {
+ "version": "2.0.17",
+ "resolved": "https://registry.npmjs.org/unhead/-/unhead-2.0.17.tgz",
+ "integrity": "sha512-xX3PCtxaE80khRZobyWCVxeFF88/Tg9eJDcJWY9us727nsTC7C449B8BUfVBmiF2+3LjPcmqeoB2iuMs0U4oJQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hookable": "^5.5.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/harlan-zw"
+ }
+ },
+ "node_modules/unicorn-magic": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz",
+ "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/unimport": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/unimport/-/unimport-5.3.0.tgz",
+ "integrity": "sha512-cty7t1DESgm0OPfCy9oyn5u9B5t0tMW6tH6bXTjAGIO3SkJsbg/DXYHjrPrUKqultqbAAoltAfYsuu/FEDocjg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "acorn": "^8.15.0",
+ "escape-string-regexp": "^5.0.0",
+ "estree-walker": "^3.0.3",
+ "local-pkg": "^1.1.2",
+ "magic-string": "^0.30.19",
+ "mlly": "^1.8.0",
+ "pathe": "^2.0.3",
+ "picomatch": "^4.0.3",
+ "pkg-types": "^2.3.0",
+ "scule": "^1.3.0",
+ "strip-literal": "^3.0.0",
+ "tinyglobby": "^0.2.15",
+ "unplugin": "^2.3.10",
+ "unplugin-utils": "^0.3.0"
+ },
+ "engines": {
+ "node": ">=18.12.0"
+ }
+ },
+ "node_modules/unimport/node_modules/unplugin-utils": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.0.tgz",
+ "integrity": "sha512-JLoggz+PvLVMJo+jZt97hdIIIZ2yTzGgft9e9q8iMrC4ewufl62ekeW7mixBghonn2gVb/ICjyvlmOCUBnJLQg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pathe": "^2.0.3",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=20.19.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sxzz"
+ }
+ },
+ "node_modules/unplugin": {
+ "version": "2.3.10",
+ "resolved": "https://registry.npmjs.org/unplugin/-/unplugin-2.3.10.tgz",
+ "integrity": "sha512-6NCPkv1ClwH+/BGE9QeoTIl09nuiAt0gS28nn1PvYXsGKRwM2TCbFA2QiilmehPDTXIe684k4rZI1yl3A1PCUw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/remapping": "^2.3.5",
+ "acorn": "^8.15.0",
+ "picomatch": "^4.0.3",
+ "webpack-virtual-modules": "^0.6.2"
+ },
+ "engines": {
+ "node": ">=18.12.0"
+ }
+ },
+ "node_modules/unplugin-utils": {
+ "version": "0.2.5",
+ "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.2.5.tgz",
+ "integrity": "sha512-gwXJnPRewT4rT7sBi/IvxKTjsms7jX7QIDLOClApuZwR49SXbrB1z2NLUZ+vDHyqCj/n58OzRRqaW+B8OZi8vg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pathe": "^2.0.3",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=18.12.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sxzz"
+ }
+ },
+ "node_modules/unplugin-vue-router": {
+ "version": "0.15.0",
+ "resolved": "https://registry.npmjs.org/unplugin-vue-router/-/unplugin-vue-router-0.15.0.tgz",
+ "integrity": "sha512-PyGehCjd9Ny9h+Uer4McbBjjib3lHihcyUEILa7pHKl6+rh8N7sFyw4ZkV+N30Oq2zmIUG7iKs3qpL0r+gXAaQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vue-macros/common": "3.0.0-beta.16",
+ "@vue/language-core": "^3.0.1",
+ "ast-walker-scope": "^0.8.1",
+ "chokidar": "^4.0.3",
+ "json5": "^2.2.3",
+ "local-pkg": "^1.1.1",
+ "magic-string": "^0.30.17",
+ "mlly": "^1.7.4",
+ "muggle-string": "^0.4.1",
+ "pathe": "^2.0.3",
+ "picomatch": "^4.0.3",
+ "scule": "^1.3.0",
+ "tinyglobby": "^0.2.14",
+ "unplugin": "^2.3.5",
+ "unplugin-utils": "^0.2.4",
+ "yaml": "^2.8.0"
+ },
+ "peerDependencies": {
+ "@vue/compiler-sfc": "^3.5.17",
+ "vue-router": "^4.5.1"
+ },
+ "peerDependenciesMeta": {
+ "vue-router": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/unstorage": {
+ "version": "1.17.1",
+ "resolved": "https://registry.npmjs.org/unstorage/-/unstorage-1.17.1.tgz",
+ "integrity": "sha512-KKGwRTT0iVBCErKemkJCLs7JdxNVfqTPc/85ae1XES0+bsHbc/sFBfVi5kJp156cc51BHinIH2l3k0EZ24vOBQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "anymatch": "^3.1.3",
+ "chokidar": "^4.0.3",
+ "destr": "^2.0.5",
+ "h3": "^1.15.4",
+ "lru-cache": "^10.4.3",
+ "node-fetch-native": "^1.6.7",
+ "ofetch": "^1.4.1",
+ "ufo": "^1.6.1"
+ },
+ "peerDependencies": {
+ "@azure/app-configuration": "^1.8.0",
+ "@azure/cosmos": "^4.2.0",
+ "@azure/data-tables": "^13.3.0",
+ "@azure/identity": "^4.6.0",
+ "@azure/keyvault-secrets": "^4.9.0",
+ "@azure/storage-blob": "^12.26.0",
+ "@capacitor/preferences": "^6.0.3 || ^7.0.0",
+ "@deno/kv": ">=0.9.0",
+ "@netlify/blobs": "^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0",
+ "@planetscale/database": "^1.19.0",
+ "@upstash/redis": "^1.34.3",
+ "@vercel/blob": ">=0.27.1",
+ "@vercel/functions": "^2.2.12 || ^3.0.0",
+ "@vercel/kv": "^1.0.1",
+ "aws4fetch": "^1.0.20",
+ "db0": ">=0.2.1",
+ "idb-keyval": "^6.2.1",
+ "ioredis": "^5.4.2",
+ "uploadthing": "^7.4.4"
+ },
+ "peerDependenciesMeta": {
+ "@azure/app-configuration": {
+ "optional": true
+ },
+ "@azure/cosmos": {
+ "optional": true
+ },
+ "@azure/data-tables": {
+ "optional": true
+ },
+ "@azure/identity": {
+ "optional": true
+ },
+ "@azure/keyvault-secrets": {
+ "optional": true
+ },
+ "@azure/storage-blob": {
+ "optional": true
+ },
+ "@capacitor/preferences": {
+ "optional": true
+ },
+ "@deno/kv": {
+ "optional": true
+ },
+ "@netlify/blobs": {
+ "optional": true
+ },
+ "@planetscale/database": {
+ "optional": true
+ },
+ "@upstash/redis": {
+ "optional": true
+ },
+ "@vercel/blob": {
+ "optional": true
+ },
+ "@vercel/functions": {
+ "optional": true
+ },
+ "@vercel/kv": {
+ "optional": true
+ },
+ "aws4fetch": {
+ "optional": true
+ },
+ "db0": {
+ "optional": true
+ },
+ "idb-keyval": {
+ "optional": true
+ },
+ "ioredis": {
+ "optional": true
+ },
+ "uploadthing": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/unstorage/node_modules/lru-cache": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/untun": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/untun/-/untun-0.1.3.tgz",
+ "integrity": "sha512-4luGP9LMYszMRZwsvyUd9MrxgEGZdZuZgpVQHEEX0lCYFESasVRvZd0EYpCkOIbJKHMuv0LskpXc/8Un+MJzEQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "citty": "^0.1.5",
+ "consola": "^3.2.3",
+ "pathe": "^1.1.1"
+ },
+ "bin": {
+ "untun": "bin/untun.mjs"
+ }
+ },
+ "node_modules/untun/node_modules/pathe": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz",
+ "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/untyped": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/untyped/-/untyped-2.0.0.tgz",
+ "integrity": "sha512-nwNCjxJTjNuLCgFr42fEak5OcLuB3ecca+9ksPFNvtfYSLpjf+iJqSIaSnIile6ZPbKYxI5k2AfXqeopGudK/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "citty": "^0.1.6",
+ "defu": "^6.1.4",
+ "jiti": "^2.4.2",
+ "knitwork": "^1.2.0",
+ "scule": "^1.3.0"
+ },
+ "bin": {
+ "untyped": "dist/cli.mjs"
+ }
+ },
+ "node_modules/unwasm": {
+ "version": "0.3.11",
+ "resolved": "https://registry.npmjs.org/unwasm/-/unwasm-0.3.11.tgz",
+ "integrity": "sha512-Vhp5gb1tusSQw5of/g3Q697srYgMXvwMgXMjcG4ZNga02fDX9coxJ9fAb0Ci38hM2Hv/U1FXRPGgjP2BYqhNoQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "knitwork": "^1.2.0",
+ "magic-string": "^0.30.17",
+ "mlly": "^1.7.4",
+ "pathe": "^2.0.3",
+ "pkg-types": "^2.2.0",
+ "unplugin": "^2.3.6"
+ }
+ },
+ "node_modules/update-browserslist-db": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+ "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
+ "node_modules/uqr": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/uqr/-/uqr-0.1.2.tgz",
+ "integrity": "sha512-MJu7ypHq6QasgF5YRTjqscSzQp/W11zoUk6kvmlH+fmWEs63Y0Eib13hYFwAzagRJcVY8WVnlV+eBDUGMJ5IbA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
+ "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/vite": {
+ "version": "7.1.7",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.7.tgz",
+ "integrity": "sha512-VbA8ScMvAISJNJVbRDTJdCwqQoAareR/wutevKanhR2/1EkoXVZVkkORaYm/tNVCjP/UDTKtcw3bAkwOUdedmA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "esbuild": "^0.25.0",
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3",
+ "postcss": "^8.5.6",
+ "rollup": "^4.43.0",
+ "tinyglobby": "^0.2.15"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^20.19.0 || >=22.12.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^20.19.0 || >=22.12.0",
+ "jiti": ">=1.21.0",
+ "less": "^4.0.0",
+ "lightningcss": "^1.21.0",
+ "sass": "^1.70.0",
+ "sass-embedded": "^1.70.0",
+ "stylus": ">=0.54.8",
+ "sugarss": "^5.0.0",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "jiti": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite-dev-rpc": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/vite-dev-rpc/-/vite-dev-rpc-1.1.0.tgz",
+ "integrity": "sha512-pKXZlgoXGoE8sEKiKJSng4hI1sQ4wi5YT24FCrwrLt6opmkjlqPPVmiPWWJn8M8byMxRGzp1CrFuqQs4M/Z39A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "birpc": "^2.4.0",
+ "vite-hot-client": "^2.1.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "vite": "^2.9.0 || ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 || ^6.0.1 || ^7.0.0-0"
+ }
+ },
+ "node_modules/vite-hot-client": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/vite-hot-client/-/vite-hot-client-2.1.0.tgz",
+ "integrity": "sha512-7SpgZmU7R+dDnSmvXE1mfDtnHLHQSisdySVR7lO8ceAXvM0otZeuQQ6C8LrS5d/aYyP/QZ0hI0L+dIPrm4YlFQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "vite": "^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0"
+ }
+ },
+ "node_modules/vite-node": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz",
+ "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cac": "^6.7.14",
+ "debug": "^4.4.1",
+ "es-module-lexer": "^1.7.0",
+ "pathe": "^2.0.3",
+ "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0"
+ },
+ "bin": {
+ "vite-node": "vite-node.mjs"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/vitest"
+ }
+ },
+ "node_modules/vite-plugin-checker": {
+ "version": "0.10.3",
+ "resolved": "https://registry.npmjs.org/vite-plugin-checker/-/vite-plugin-checker-0.10.3.tgz",
+ "integrity": "sha512-f4sekUcDPF+T+GdbbE8idb1i2YplBAoH+SfRS0e/WRBWb2rYb1Jf5Pimll0Rj+3JgIYWwG2K5LtBPCXxoibkLg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.27.1",
+ "chokidar": "^4.0.3",
+ "npm-run-path": "^6.0.0",
+ "picocolors": "^1.1.1",
+ "picomatch": "^4.0.3",
+ "strip-ansi": "^7.1.0",
+ "tiny-invariant": "^1.3.3",
+ "tinyglobby": "^0.2.14",
+ "vscode-uri": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "peerDependencies": {
+ "@biomejs/biome": ">=1.7",
+ "eslint": ">=7",
+ "meow": "^13.2.0",
+ "optionator": "^0.9.4",
+ "stylelint": ">=16",
+ "typescript": "*",
+ "vite": ">=2.0.0",
+ "vls": "*",
+ "vti": "*",
+ "vue-tsc": "~2.2.10 || ^3.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@biomejs/biome": {
+ "optional": true
+ },
+ "eslint": {
+ "optional": true
+ },
+ "meow": {
+ "optional": true
+ },
+ "optionator": {
+ "optional": true
+ },
+ "stylelint": {
+ "optional": true
+ },
+ "typescript": {
+ "optional": true
+ },
+ "vls": {
+ "optional": true
+ },
+ "vti": {
+ "optional": true
+ },
+ "vue-tsc": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite-plugin-checker/node_modules/npm-run-path": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz",
+ "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^4.0.0",
+ "unicorn-magic": "^0.3.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/vite-plugin-checker/node_modules/path-key": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
+ "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/vite-plugin-inspect": {
+ "version": "11.3.3",
+ "resolved": "https://registry.npmjs.org/vite-plugin-inspect/-/vite-plugin-inspect-11.3.3.tgz",
+ "integrity": "sha512-u2eV5La99oHoYPHE6UvbwgEqKKOQGz86wMg40CCosP6q8BkB6e5xPneZfYagK4ojPJSj5anHCrnvC20DpwVdRA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansis": "^4.1.0",
+ "debug": "^4.4.1",
+ "error-stack-parser-es": "^1.0.5",
+ "ohash": "^2.0.11",
+ "open": "^10.2.0",
+ "perfect-debounce": "^2.0.0",
+ "sirv": "^3.0.1",
+ "unplugin-utils": "^0.3.0",
+ "vite-dev-rpc": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "vite": "^6.0.0 || ^7.0.0-0"
+ },
+ "peerDependenciesMeta": {
+ "@nuxt/kit": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vite-plugin-inspect/node_modules/define-lazy-prop": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz",
+ "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/vite-plugin-inspect/node_modules/open": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz",
+ "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "default-browser": "^5.2.1",
+ "define-lazy-prop": "^3.0.0",
+ "is-inside-container": "^1.0.0",
+ "wsl-utils": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/vite-plugin-inspect/node_modules/unplugin-utils": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/unplugin-utils/-/unplugin-utils-0.3.0.tgz",
+ "integrity": "sha512-JLoggz+PvLVMJo+jZt97hdIIIZ2yTzGgft9e9q8iMrC4ewufl62ekeW7mixBghonn2gVb/ICjyvlmOCUBnJLQg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "pathe": "^2.0.3",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=20.19.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sxzz"
+ }
+ },
+ "node_modules/vite-plugin-vue-tracer": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/vite-plugin-vue-tracer/-/vite-plugin-vue-tracer-1.0.0.tgz",
+ "integrity": "sha512-a+UB9IwGx5uwS4uG/a9kM6fCMnxONDkOTbgCUbhFpiGhqfxrrC1+9BibV7sWwUnwj1Dg6MnRxG0trLgUZslDXA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "estree-walker": "^3.0.3",
+ "exsolve": "^1.0.7",
+ "magic-string": "^0.30.17",
+ "pathe": "^2.0.3",
+ "source-map-js": "^1.2.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "vite": "^6.0.0 || ^7.0.0",
+ "vue": "^3.5.0"
+ }
+ },
+ "node_modules/vscode-uri": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz",
+ "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/vue": {
+ "version": "3.5.21",
+ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.21.tgz",
+ "integrity": "sha512-xxf9rum9KtOdwdRkiApWL+9hZEMWE90FHh8yS1+KJAiWYh+iGWV1FquPjoO9VUHQ+VIhsCXNNyZ5Sf4++RVZBA==",
+ "license": "MIT",
+ "dependencies": {
+ "@vue/compiler-dom": "3.5.21",
+ "@vue/compiler-sfc": "3.5.21",
+ "@vue/runtime-dom": "3.5.21",
+ "@vue/server-renderer": "3.5.21",
+ "@vue/shared": "3.5.21"
+ },
+ "peerDependencies": {
+ "typescript": "*"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vue-bundle-renderer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/vue-bundle-renderer/-/vue-bundle-renderer-2.1.2.tgz",
+ "integrity": "sha512-M4WRBO/O/7G9phGaGH9AOwOnYtY9ZpPoDVpBpRzR2jO5rFL9mgIlQIgums2ljCTC2HL1jDXFQc//CzWcAQHgAw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ufo": "^1.6.1"
+ }
+ },
+ "node_modules/vue-demi": {
+ "version": "0.14.10",
+ "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
+ "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "vue-demi-fix": "bin/vue-demi-fix.js",
+ "vue-demi-switch": "bin/vue-demi-switch.js"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "@vue/composition-api": "^1.0.0-rc.1",
+ "vue": "^3.0.0-0 || ^2.6.0"
+ },
+ "peerDependenciesMeta": {
+ "@vue/composition-api": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vue-devtools-stub": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/vue-devtools-stub/-/vue-devtools-stub-0.1.0.tgz",
+ "integrity": "sha512-RutnB7X8c5hjq39NceArgXg28WZtZpGc3+J16ljMiYnFhKvd8hITxSWQSQ5bvldxMDU6gG5mkxl1MTQLXckVSQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/vue-router": {
+ "version": "4.5.1",
+ "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.5.1.tgz",
+ "integrity": "sha512-ogAF3P97NPm8fJsE4by9dwSYtDwXIY1nFY9T6DyQnGHd1E2Da94w9JIolpe42LJGIl0DwOHBi8TcRPlPGwbTtw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@vue/devtools-api": "^6.6.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/posva"
+ },
+ "peerDependencies": {
+ "vue": "^3.2.0"
+ }
+ },
+ "node_modules/vue-tsc": {
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.0.8.tgz",
+ "integrity": "sha512-H9yg/m6ywykmWS+pIAEs65v2FrVm5uOA0a0dHkX6Sx8dNg1a1m4iudt/6eGa9fAenmNHGlLFN9XpWQb8i5sU1w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@volar/typescript": "2.4.23",
+ "@vue/language-core": "3.0.8"
+ },
+ "bin": {
+ "vue-tsc": "bin/vue-tsc.js"
+ },
+ "peerDependencies": {
+ "typescript": ">=5.0.0"
+ }
+ },
+ "node_modules/vue3-highlightjs": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/vue3-highlightjs/-/vue3-highlightjs-1.0.5.tgz",
+ "integrity": "sha512-Q4YNPXu0X5VMBnwPVOk+IQf1Ohp9jFdMitEAmzaz8qVVefcQpN6Dx4BnDGKxja3TLDVF+EgL136wC8YzmoCX9w==",
+ "license": "ISC",
+ "dependencies": {
+ "highlight.js": "^10.3.2"
+ },
+ "peerDependencies": {
+ "vue": "^3.0.0"
+ }
+ },
+ "node_modules/vue3-highlightjs/node_modules/highlight.js": {
+ "version": "10.7.3",
+ "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
+ "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/vuetify": {
+ "version": "3.10.2",
+ "resolved": "https://registry.npmjs.org/vuetify/-/vuetify-3.10.2.tgz",
+ "integrity": "sha512-uuAm+uj170ZWdS0aiomhgtdYOR3/I2yzynskBfYyFB1Fn/HKvlvPDaU3ISZnf0GHIJQENdj7eLg/wTChrIwEQw==",
+ "license": "MIT",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/johnleider"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.7",
+ "vite-plugin-vuetify": ">=2.1.0",
+ "vue": "^3.5.0",
+ "webpack-plugin-vuetify": ">=3.1.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ },
+ "vite-plugin-vuetify": {
+ "optional": true
+ },
+ "webpack-plugin-vuetify": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/watchpack": {
+ "version": "2.4.4",
+ "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.4.tgz",
+ "integrity": "sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "glob-to-regexp": "^0.4.1",
+ "graceful-fs": "^4.1.2"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
+ "dev": true,
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/webpack": {
+ "version": "5.101.3",
+ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.101.3.tgz",
+ "integrity": "sha512-7b0dTKR3Ed//AD/6kkx/o7duS8H3f1a4w3BYpIriX4BzIhjkn4teo05cptsxvLesHFKK5KObnadmCHBwGc+51A==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@types/eslint-scope": "^3.7.7",
+ "@types/estree": "^1.0.8",
+ "@types/json-schema": "^7.0.15",
+ "@webassemblyjs/ast": "^1.14.1",
+ "@webassemblyjs/wasm-edit": "^1.14.1",
+ "@webassemblyjs/wasm-parser": "^1.14.1",
+ "acorn": "^8.15.0",
+ "acorn-import-phases": "^1.0.3",
+ "browserslist": "^4.24.0",
+ "chrome-trace-event": "^1.0.2",
+ "enhanced-resolve": "^5.17.3",
+ "es-module-lexer": "^1.2.1",
+ "eslint-scope": "5.1.1",
+ "events": "^3.2.0",
+ "glob-to-regexp": "^0.4.1",
+ "graceful-fs": "^4.2.11",
+ "json-parse-even-better-errors": "^2.3.1",
+ "loader-runner": "^4.2.0",
+ "mime-types": "^2.1.27",
+ "neo-async": "^2.6.2",
+ "schema-utils": "^4.3.2",
+ "tapable": "^2.1.1",
+ "terser-webpack-plugin": "^5.3.11",
+ "watchpack": "^2.4.1",
+ "webpack-sources": "^3.3.3"
+ },
+ "bin": {
+ "webpack": "bin/webpack.js"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ },
+ "peerDependenciesMeta": {
+ "webpack-cli": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/webpack-sources": {
+ "version": "3.3.3",
+ "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.3.3.tgz",
+ "integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/webpack-virtual-modules": {
+ "version": "0.6.2",
+ "resolved": "https://registry.npmjs.org/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz",
+ "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/webpack/node_modules/ajv": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
+ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3",
+ "fast-uri": "^3.0.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/webpack/node_modules/ajv-keywords": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+ "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3"
+ },
+ "peerDependencies": {
+ "ajv": "^8.8.2"
+ }
+ },
+ "node_modules/webpack/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "license": "MIT",
+ "peer": true
+ },
+ "node_modules/webpack/node_modules/mime-db": {
+ "version": "1.52.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/webpack/node_modules/mime-types": {
+ "version": "2.1.35",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "mime-db": "1.52.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/webpack/node_modules/schema-utils": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.3.2.tgz",
+ "integrity": "sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@types/json-schema": "^7.0.9",
+ "ajv": "^8.9.0",
+ "ajv-formats": "^2.1.1",
+ "ajv-keywords": "^5.1.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
+ "node_modules/which": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz",
+ "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^3.1.1"
+ },
+ "bin": {
+ "node-which": "bin/which.js"
+ },
+ "engines": {
+ "node": "^18.17.0 || >=20.5.0"
+ }
+ },
+ "node_modules/wrap-ansi": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
+ "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^6.1.0",
+ "string-width": "^5.0.1",
+ "strip-ansi": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi-cjs": {
+ "name": "wrap-ansi",
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ws": {
+ "version": "8.18.3",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
+ "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/wsl-utils": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz",
+ "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-wsl": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/yaml": {
+ "version": "2.8.1",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz",
+ "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "yaml": "bin.mjs"
+ },
+ "engines": {
+ "node": ">= 14.6"
+ }
+ },
+ "node_modules/yargs": {
+ "version": "17.7.2",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
+ "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^8.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.3",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^21.1.1"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "21.1.1",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
+ "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/yargs/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/yargs/node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/yargs/node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/yargs/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/youch": {
+ "version": "4.1.0-beta.11",
+ "resolved": "https://registry.npmjs.org/youch/-/youch-4.1.0-beta.11.tgz",
+ "integrity": "sha512-sQi6PERyO/mT8w564ojOVeAlYTtVQmC2GaktQAf+IdI75/GKIggosBuvyVXvEV+FATAT6RbLdIjFoiIId4ozoQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@poppinss/colors": "^4.1.5",
+ "@poppinss/dumper": "^0.6.4",
+ "@speed-highlight/core": "^1.2.7",
+ "cookie": "^1.0.2",
+ "youch-core": "^0.3.3"
+ }
+ },
+ "node_modules/youch-core": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/youch-core/-/youch-core-0.3.3.tgz",
+ "integrity": "sha512-ho7XuGjLaJ2hWHoK8yFnsUGy2Y5uDpqSTq1FkHLK4/oqKtyUU1AFbOOxY4IpC9f0fTLjwYbslUz0Po5BpD1wrA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@poppinss/exception": "^1.2.2",
+ "error-stack-parser-es": "^1.0.5"
+ }
+ },
+ "node_modules/zip-stream": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-6.0.1.tgz",
+ "integrity": "sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "archiver-utils": "^5.0.0",
+ "compress-commons": "^6.0.2",
+ "readable-stream": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ }
+ }
+}
diff --git a/examples/clientsocket/package.json b/examples/clientsocket/package.json
new file mode 100644
index 0000000..8a35587
--- /dev/null
+++ b/examples/clientsocket/package.json
@@ -0,0 +1,27 @@
+{
+ "name": "nuxt3-websocket-client",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "build": "nuxt build",
+ "dev": "nuxt dev",
+ "generate": "nuxt generate",
+ "preview": "nuxt preview",
+ "postinstall": "nuxt prepare"
+ },
+ "devDependencies": {
+ "@nuxt/devtools": "latest",
+ "nuxt": "^3.8.0",
+ "vue": "^3.3.8",
+ "vue-router": "^4.2.5",
+ "vue-tsc": "^3.0.8"
+ },
+ "dependencies": {
+ "@mdi/font": "^7.3.67",
+ "@nuxtjs/vuetify": "^1.12.3",
+ "highlight.js": "^11.9.0",
+ "pinia": "^2.1.7",
+ "vue3-highlightjs": "^1.0.5",
+ "vuetify": "^3.4.0"
+ }
+}
diff --git a/examples/clientsocket/pages/index.vue b/examples/clientsocket/pages/index.vue
new file mode 100644
index 0000000..536c44d
--- /dev/null
+++ b/examples/clientsocket/pages/index.vue
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
diff --git a/examples/clientsocket/plugins/vuetify.js b/examples/clientsocket/plugins/vuetify.js
new file mode 100644
index 0000000..a1aa056
--- /dev/null
+++ b/examples/clientsocket/plugins/vuetify.js
@@ -0,0 +1,15 @@
+import { createVuetify } from 'vuetify'
+import * as components from 'vuetify/components'
+import * as directives from 'vuetify/directives'
+
+export default defineNuxtPlugin((nuxtApp) => {
+ const vuetify = createVuetify({
+ components,
+ directives,
+ theme: {
+ defaultTheme: 'light'
+ }
+ })
+
+ nuxtApp.vueApp.use(vuetify)
+})
diff --git a/examples/clientsocket/public/favicon.ico b/examples/clientsocket/public/favicon.ico
new file mode 100644
index 0000000..18993ad
Binary files /dev/null and b/examples/clientsocket/public/favicon.ico differ
diff --git a/examples/clientsocket/public/robots.txt b/examples/clientsocket/public/robots.txt
new file mode 100644
index 0000000..0ad279c
--- /dev/null
+++ b/examples/clientsocket/public/robots.txt
@@ -0,0 +1,2 @@
+User-Agent: *
+Disallow:
diff --git a/examples/clientsocket/tsconfig.json b/examples/clientsocket/tsconfig.json
new file mode 100644
index 0000000..4b34df1
--- /dev/null
+++ b/examples/clientsocket/tsconfig.json
@@ -0,0 +1,3 @@
+{
+ "extends": "./.nuxt/tsconfig.json"
+}
diff --git a/examples/clientsocket/types/websocket.ts b/examples/clientsocket/types/websocket.ts
new file mode 100644
index 0000000..98720db
--- /dev/null
+++ b/examples/clientsocket/types/websocket.ts
@@ -0,0 +1,182 @@
+export interface WebSocketMessage {
+ type: string;
+ data: any;
+ timestamp?: number;
+ client_id?: string;
+ message_id?: string;
+}
+
+export interface ConnectionInfo {
+ client_id: string;
+ static_id: string;
+ ip_address: string;
+ room: string;
+ user_id: string;
+ connected_at: number;
+ id_type: string;
+}
+
+export interface ClientInfo {
+ id: string;
+ static_id: string;
+ ip_address: string;
+ user_id: string;
+ room: string;
+ connected_at: number;
+ last_ping: number;
+ is_active?: boolean;
+}
+
+export interface OnlineUser {
+ client_id: string;
+ static_id: string;
+ user_id: string;
+ room: string;
+ ip_address: string;
+ connected_at: number;
+ last_ping: number;
+}
+
+export interface ConnectionStats {
+ connected_clients: number;
+ unique_ips: number;
+ static_clients: number;
+ active_rooms: number;
+ ip_distribution: Record;
+ room_distribution: Record;
+ message_queue_size: number;
+ queue_workers: number;
+ uptime: number;
+ timestamp: number;
+}
+
+export interface SystemHealth {
+ databases: any;
+ available_dbs: string[];
+ websocket_status: string;
+ uptime_seconds: number;
+}
+
+export interface PerformanceMetrics {
+ messages_per_second: number;
+ average_latency_ms: number;
+ error_rate_percent: number;
+ memory_usage_bytes: number;
+}
+
+export interface MonitoringData {
+ stats: ConnectionStats;
+ recent_activity: ActivityLog[];
+ system_health: SystemHealth;
+ performance: PerformanceMetrics;
+}
+
+export interface ActivityLog {
+ timestamp: number;
+ event: string;
+ client_id: string;
+ details: string;
+}
+
+export interface MessageHistory {
+ timestamp: Date;
+ type: string;
+ data: any;
+ messageId?: string;
+ size: number;
+ icon?: string;
+ timeString?: string;
+}
+
+export interface ConnectionState {
+ isConnected: boolean;
+ isConnecting: boolean;
+ connectionStatus: "disconnected" | "connecting" | "connected" | "error";
+ clientId: string | null;
+ staticId: string | null;
+ currentRoom: string | null;
+ userId: string;
+ ipAddress: string | null;
+ connectionStartTime: number | null;
+ lastPingTime: number | null;
+ connectionLatency: number;
+ connectionHealth: "poor" | "warning" | "good" | "excellent";
+ reconnectAttempts: number;
+ messagesReceived: number;
+ messagesSent: number;
+ uptime: string;
+}
+
+export interface WebSocketConfig {
+ wsUrl: string;
+ userId: string;
+ room: string;
+ staticId?: string;
+ useIPBasedId?: boolean;
+ autoReconnect: boolean;
+ heartbeatEnabled: boolean;
+ maxReconnectAttempts: number;
+ reconnectDelay: number;
+ maxReconnectDelay: number;
+ heartbeatInterval: number;
+ heartbeatTimeout: number;
+ maxMissedHeartbeats: number;
+ maxMessages: number;
+ messageWarningThreshold: number;
+ actionThrottle: number;
+}
+
+export type MessageType =
+ | "welcome"
+ | "broadcast"
+ | "direct_message"
+ | "room_message"
+ | "ping"
+ | "pong"
+ | "heartbeat"
+ | "heartbeat_ack"
+ | "connection_test"
+ | "connection_test_result"
+ | "get_online_users"
+ | "online_users"
+ | "get_server_info"
+ | "server_info"
+ | "error"
+ | "message_received"
+ | "broadcast_sent"
+ | "direct_message_sent"
+ | "room_message_sent"
+ | "db_insert"
+ | "db_query"
+ | "db_custom_query"
+ | "query_result"
+ | "admin_kick_client"
+ | "admin_kill_server"
+ | "get_server_stats"
+ | "get_system_health"
+ | "admin_clear_logs"
+ | "get_stats"
+ | "get_room_info"
+ | "join_room"
+ | "leave_room"
+ | "database_change"
+ | "data_stream"
+ | "server_heartbeat"
+ | "system_status"
+ | "clients_by_ip"
+ | "client_info"
+ | "get_clients_by_ip"
+ | "get_client_info"
+ | "health_check"
+ | "database_list"
+ | "connection_stats"
+ | "trigger_notification"
+ | "notification_sent"
+ | "API_TEST"
+ | "manual_test"
+ | "retribusi_created"
+ | "retribusi_updated"
+ | "retribusi_deleted"
+ | "peserta_changes"
+ | "retribusi_changes"
+ | "system_changes";
diff --git a/go.mod b/go.mod
index 6477df7..9dfc2b9 100644
--- a/go.mod
+++ b/go.mod
@@ -20,6 +20,7 @@ require (
github.com/gin-contrib/cors v1.7.6
github.com/go-playground/validator/v10 v10.27.0
github.com/go-redis/redis_rate/v10 v10.0.1
+ github.com/gorilla/websocket v1.5.1
github.com/jmoiron/sqlx v1.4.0
github.com/joho/godotenv v1.5.1
github.com/lib/pq v1.10.9
diff --git a/go.sum b/go.sum
index 4fc4172..5725319 100644
--- a/go.sum
+++ b/go.sum
@@ -106,6 +106,8 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
+github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
+github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
diff --git a/internal/config/config.go b/internal/config/config.go
index 0c6c7c5..94e5152 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -26,6 +26,7 @@ type Config struct {
Bpjs BpjsConfig
SatuSehat SatuSehatConfig
Swagger SwaggerConfig
+ WebSocket WebSocketConfig // Tambahkan ini
Security SecurityConfig
Validator *validator.Validate
}
@@ -128,6 +129,38 @@ type SatuSehatConfig struct {
Timeout time.Duration `json:"timeout"`
}
+type WebSocketConfig struct {
+ // Timeout configurations
+ ReadTimeout time.Duration `json:"read_timeout"`
+ WriteTimeout time.Duration `json:"write_timeout"`
+ PingInterval time.Duration `json:"ping_interval"`
+ PongTimeout time.Duration `json:"pong_timeout"`
+ HandshakeTimeout time.Duration `json:"handshake_timeout"`
+
+ // Buffer sizes
+ ReadBufferSize int `json:"read_buffer_size"`
+ WriteBufferSize int `json:"write_buffer_size"`
+ ChannelBufferSize int `json:"channel_buffer_size"`
+ MessageQueueSize int `json:"message_queue_size"`
+
+ // Connection limits
+ MaxMessageSize int `json:"max_message_size"`
+ QueueWorkers int `json:"queue_workers"`
+
+ // Monitoring
+ ActivityLogSize int `json:"activity_log_size"`
+ CleanupInterval time.Duration `json:"cleanup_interval"`
+ InactiveTimeout time.Duration `json:"inactive_timeout"`
+
+ // Server info
+ ServerID string `json:"server_id"`
+
+ // Features
+ EnableCompression bool `json:"enable_compression"`
+ EnableMetrics bool `json:"enable_metrics"`
+ EnableMonitoring bool `json:"enable_monitoring"`
+}
+
// SecurityConfig berisi semua pengaturan untuk middleware keamanan
type SecurityConfig struct {
// CORS
@@ -222,6 +255,38 @@ func LoadConfig() *Config {
KFAURL: getEnv("BRIDGING_SATUSEHAT_KFA_URL", "https://api-satusehat.kemkes.go.id/kfa-v2"),
Timeout: parseDuration(getEnv("BRIDGING_SATUSEHAT_TIMEOUT", "30s")),
},
+ // Configuration for WebSocket server
+ WebSocket: WebSocketConfig{ // Tambahkan ini
+ // Timeout configurations
+ ReadTimeout: parseDuration(getEnv("WS_READ_TIMEOUT", "300s")),
+ WriteTimeout: parseDuration(getEnv("WS_WRITE_TIMEOUT", "30s")),
+ PingInterval: parseDuration(getEnv("WS_PING_INTERVAL", "60s")),
+ PongTimeout: parseDuration(getEnv("WS_PONG_TIMEOUT", "70s")),
+ HandshakeTimeout: parseDuration(getEnv("WS_HANDSHAKE_TIMEOUT", "45s")),
+
+ // Buffer sizes
+ ReadBufferSize: getEnvAsInt("WS_READ_BUFFER_SIZE", 8192),
+ WriteBufferSize: getEnvAsInt("WS_WRITE_BUFFER_SIZE", 8192),
+ ChannelBufferSize: getEnvAsInt("WS_CHANNEL_BUFFER_SIZE", 512),
+ MessageQueueSize: getEnvAsInt("WS_MESSAGE_QUEUE_SIZE", 5000),
+
+ // Connection limits
+ MaxMessageSize: getEnvAsInt("WS_MAX_MESSAGE_SIZE", 8192),
+ QueueWorkers: getEnvAsInt("WS_QUEUE_WORKERS", 10),
+
+ // Monitoring
+ ActivityLogSize: getEnvAsInt("WS_ACTIVITY_LOG_SIZE", 1000),
+ CleanupInterval: parseDuration(getEnv("WS_CLEANUP_INTERVAL", "2m")),
+ InactiveTimeout: parseDuration(getEnv("WS_INACTIVE_TIMEOUT", "5m")),
+
+ // Server info
+ ServerID: getEnv("WS_SERVER_ID", "api-service-v1"),
+
+ // Features
+ EnableCompression: getEnvAsBool("WS_ENABLE_COMPRESSION", true),
+ EnableMetrics: getEnvAsBool("WS_ENABLE_METRICS", true),
+ EnableMonitoring: getEnvAsBool("WS_ENABLE_MONITORING", true),
+ },
Swagger: SwaggerConfig{
Title: getEnv("SWAGGER_TITLE", "SERVICE API"),
Description: getEnv("SWAGGER_DESCRIPTION", "CUSTUM SERVICE API"),
@@ -1314,5 +1379,194 @@ func (c *Config) Validate() error {
if len(errs) > 0 {
return fmt.Errorf("configuration validation failed: %s", strings.Join(errs, "; "))
}
+
+ // Validate WebSocket configuration
+ if c.WebSocket.ReadTimeout <= 0 {
+ log.Fatal("WebSocket Read Timeout must be greater than 0")
+ }
+ if c.WebSocket.WriteTimeout <= 0 {
+ log.Fatal("WebSocket Write Timeout must be greater than 0")
+ }
+ if c.WebSocket.PingInterval <= 0 {
+ log.Fatal("WebSocket Ping Interval must be greater than 0")
+ }
+ if c.WebSocket.PongTimeout <= 0 {
+ log.Fatal("WebSocket Pong Timeout must be greater than 0")
+ }
+ if c.WebSocket.ReadBufferSize <= 0 {
+ log.Fatal("WebSocket Read Buffer Size must be greater than 0")
+ }
+ if c.WebSocket.WriteBufferSize <= 0 {
+ log.Fatal("WebSocket Write Buffer Size must be greater than 0")
+ }
+ if c.WebSocket.ChannelBufferSize <= 0 {
+ log.Fatal("WebSocket Channel Buffer Size must be greater than 0")
+ }
+ if c.WebSocket.MessageQueueSize <= 0 {
+ log.Fatal("WebSocket Message Queue Size must be greater than 0")
+ }
+ if c.WebSocket.MaxMessageSize <= 0 {
+ log.Fatal("WebSocket Max Message Size must be greater than 0")
+ }
+ if c.WebSocket.QueueWorkers <= 0 {
+ log.Fatal("WebSocket Queue Workers must be greater than 0")
+ }
+ if c.WebSocket.ActivityLogSize <= 0 {
+ log.Fatal("WebSocket Activity Log Size must be greater than 0")
+ }
+ if c.WebSocket.CleanupInterval <= 0 {
+ log.Fatal("WebSocket Cleanup Interval must be greater than 0")
+ }
+ if c.WebSocket.InactiveTimeout <= 0 {
+ log.Fatal("WebSocket Inactive Timeout must be greater than 0")
+ }
+ if c.WebSocket.ServerID == "" {
+ log.Fatal("WebSocket Server ID is required")
+ }
+
return nil
}
+
+//** WebSocket **//
+
+// DefaultWebSocketConfig mengembalikan konfigurasi default untuk WebSocket
+func DefaultWebSocketConfig() WebSocketConfig {
+ return WebSocketConfig{
+ // Timeout configurations
+ ReadTimeout: 300 * time.Second,
+ WriteTimeout: 30 * time.Second,
+ PingInterval: 60 * time.Second,
+ PongTimeout: 70 * time.Second,
+ HandshakeTimeout: 45 * time.Second,
+
+ // Buffer sizes
+ ReadBufferSize: 8192,
+ WriteBufferSize: 8192,
+ ChannelBufferSize: 512,
+ MessageQueueSize: 5000,
+
+ // Connection limits
+ MaxMessageSize: 8192,
+ QueueWorkers: 10,
+
+ // Monitoring
+ ActivityLogSize: 1000,
+ CleanupInterval: 2 * time.Minute,
+ InactiveTimeout: 5 * time.Minute,
+
+ // Server info
+ ServerID: "api-service-v1",
+
+ // Features
+ EnableCompression: true,
+ EnableMetrics: true,
+ EnableMonitoring: true,
+ }
+}
+
+// HighPerformanceWebSocketConfig mengembalikan konfigurasi untuk performa tinggi
+func HighPerformanceWebSocketConfig() WebSocketConfig {
+ return WebSocketConfig{
+ // Timeout configurations
+ ReadTimeout: 300 * time.Second,
+ WriteTimeout: 30 * time.Second,
+ PingInterval: 30 * time.Second,
+ PongTimeout: 40 * time.Second,
+ HandshakeTimeout: 30 * time.Second,
+
+ // Buffer sizes
+ ReadBufferSize: 16384,
+ WriteBufferSize: 16384,
+ ChannelBufferSize: 1024,
+ MessageQueueSize: 10000,
+
+ // Connection limits
+ MaxMessageSize: 16384,
+ QueueWorkers: 20,
+
+ // Monitoring
+ ActivityLogSize: 2000,
+ CleanupInterval: 1 * time.Minute,
+ InactiveTimeout: 3 * time.Minute,
+
+ // Server info
+ ServerID: "api-service-hp",
+
+ // Features
+ EnableCompression: true,
+ EnableMetrics: true,
+ EnableMonitoring: true,
+ }
+}
+
+// LowResourceWebSocketConfig mengembalikan konfigurasi untuk sumber daya terbatas
+func LowResourceWebSocketConfig() WebSocketConfig {
+ return WebSocketConfig{
+ // Timeout configurations
+ ReadTimeout: 300 * time.Second,
+ WriteTimeout: 30 * time.Second,
+ PingInterval: 120 * time.Second,
+ PongTimeout: 130 * time.Second,
+ HandshakeTimeout: 60 * time.Second,
+
+ // Buffer sizes
+ ReadBufferSize: 4096,
+ WriteBufferSize: 4096,
+ ChannelBufferSize: 256,
+ MessageQueueSize: 2500,
+
+ // Connection limits
+ MaxMessageSize: 4096,
+ QueueWorkers: 5,
+
+ // Monitoring
+ ActivityLogSize: 500,
+ CleanupInterval: 5 * time.Minute,
+ InactiveTimeout: 10 * time.Minute,
+
+ // Server info
+ ServerID: "api-service-lr",
+
+ // Features
+ EnableCompression: false,
+ EnableMetrics: false,
+ EnableMonitoring: true,
+ }
+}
+
+// CustomWebSocketConfig memungkinkan kustomisasi konfigurasi
+func CustomWebSocketConfig(
+ readTimeout, writeTimeout, pingInterval, pongTimeout time.Duration,
+ readBufferSize, writeBufferSize, channelBufferSize, messageQueueSize int,
+ maxMessageSize, queueWorkers int,
+ activityLogSize int,
+ cleanupInterval, inactiveTimeout time.Duration,
+ serverID string,
+ enableCompression, enableMetrics, enableMonitoring bool,
+) WebSocketConfig {
+ return WebSocketConfig{
+ ReadTimeout: readTimeout,
+ WriteTimeout: writeTimeout,
+ PingInterval: pingInterval,
+ PongTimeout: pongTimeout,
+ HandshakeTimeout: 45 * time.Second,
+
+ ReadBufferSize: readBufferSize,
+ WriteBufferSize: writeBufferSize,
+ ChannelBufferSize: channelBufferSize,
+ MessageQueueSize: messageQueueSize,
+
+ MaxMessageSize: maxMessageSize,
+ QueueWorkers: queueWorkers,
+
+ ActivityLogSize: activityLogSize,
+ CleanupInterval: cleanupInterval,
+ InactiveTimeout: inactiveTimeout,
+
+ ServerID: serverID,
+
+ EnableCompression: enableCompression,
+ EnableMetrics: enableMetrics,
+ EnableMonitoring: enableMonitoring,
+ }
+}
diff --git a/internal/handlers/patient/ms_patient.go b/internal/handlers/patient/ms_patient.go
index e60093e..2ac6ca0 100644
--- a/internal/handlers/patient/ms_patient.go
+++ b/internal/handlers/patient/ms_patient.go
@@ -6,13 +6,13 @@ import (
models "api-service/internal/models"
patientModels "api-service/internal/models/patient"
queryUtils "api-service/internal/utils/query"
- "api-service/internal/utils/validation"
"api-service/pkg/logger"
"context"
"database/sql"
"fmt"
"net/http"
"strconv"
+ "strings"
"sync"
"time"
@@ -36,7 +36,7 @@ func init() {
patientonce.Do(func() {
patientdb = database.New(config.LoadConfig())
patientvalidate = validator.New()
- patientvalidate.RegisterValidation("ms_patient_status", validatePatientStatus)
+ patientvalidate.RegisterValidation("patient_status", validatePatientStatus)
if patientdb == nil {
logger.Fatal("Failed to initialize database connection")
}
@@ -63,12 +63,12 @@ func (e *CacheEntry) IsExpired() bool {
return time.Now().After(e.ExpiresAt)
}
-// PatientInMemoryCache implements a simple in-memory cache with TTL
+// InMemoryCache implements a simple in-memory cache with TTL
type InMemoryCache struct {
items sync.Map
}
-// NewPatientInMemoryCache creates a new in-memory cache
+// NewInMemoryCache creates a new in-memory cache
func NewInMemoryCache() *InMemoryCache {
return &InMemoryCache{}
}
@@ -91,11 +91,10 @@ func (c *InMemoryCache) Get(key string) (interface{}, bool) {
// Set stores an item in the cache with a TTL
func (c *InMemoryCache) Set(key string, value interface{}, ttl time.Duration) {
- entry := &CacheEntry{
+ c.items.Store(key, &CacheEntry{
Data: value,
ExpiresAt: time.Now().Add(ttl),
- }
- c.items.Store(key, entry)
+ })
}
// Delete removes an item from the cache
@@ -106,7 +105,7 @@ func (c *InMemoryCache) Delete(key string) {
// DeleteByPrefix removes all items with a specific prefix
func (c *InMemoryCache) DeleteByPrefix(prefix string) {
c.items.Range(func(key, value interface{}) bool {
- if keyStr, ok := key.(string); ok && len(keyStr) >= len(prefix) && keyStr[:len(prefix)] == prefix {
+ if keyStr, ok := key.(string); ok && strings.HasPrefix(keyStr, prefix) {
c.items.Delete(key)
}
return true
@@ -121,7 +120,6 @@ func (c *InMemoryCache) DeleteByPrefix(prefix string) {
type PatientHandler struct {
db database.Service
queryBuilder *queryUtils.QueryBuilder
- validator *validation.DynamicValidator
cache *InMemoryCache
}
@@ -134,39 +132,43 @@ func NewPatientHandler() *PatientHandler {
"birth_date", "address", "active", "fk_sd_provinsi_id",
"fk_sd_kabupaten_kota_id", "fk_sd_kecamatan_id", "fk_sd_kelurahan_id",
"ds_sd_provinsi", "ds_sd_kabupaten_kota", "ds_sd_kecamatan", "ds_sd_kelurahan",
+ // Attachment fields
+ "id", "name", "file_name", "directory", "active", "fk_ms_patient_id",
+ // Payment type fields
+ "id", "name", "number", "active", "fk_ms_patient_id", "fk_ref_payment_type",
})
return &PatientHandler{
db: patientdb,
queryBuilder: queryBuilder,
- validator: validation.NewDynamicValidator(queryBuilder),
cache: NewInMemoryCache(),
}
}
// =============================================================================
-// HANDLER ENDPOINTS
+// HANDLER ENDPOINTS (READ-ONLY)
// =============================================================================
// GetPatient godoc
-// @Summary Get patient with pagination and optional aggregation
-// @Description Returns a paginated list of patients with optional summary statistics
+// @Summary Get Patients List
+// @Description Get list of patients with pagination and filters, including their attachments and payment types.
// @Tags Patient
// @Accept json
// @Produce json
// @Param limit query int false "Limit (max 100)" default(10)
// @Param offset query int false "Offset" default(0)
+// @Param active query string false "Filter by active status (true/false)"
+// @Param search query string false "Search in medical_record_number, name, or phone_number"
// @Param include_summary query bool false "Include aggregation summary" default(false)
-// @Param status query string false "Filter by status"
-// @Param search query string false "Search in multiple fields"
// @Success 200 {object} patientModels.PatientGetResponse "Success response"
// @Failure 400 {object} models.ErrorResponse "Bad request"
// @Failure 500 {object} models.ErrorResponse "Internal server error"
// @Router /patient [get]
-func (h *PatientHandler) GetMs_patient(c *gin.Context) {
+func (h *PatientHandler) GetPatient(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), 120*time.Second)
defer cancel()
+ // Build base query with LEFT JOINs to fetch related data in a single trip
query := queryUtils.DynamicQuery{
From: "master.ms_patient",
Aliases: "mp",
@@ -187,20 +189,49 @@ func (h *PatientHandler) GetMs_patient(c *gin.Context) {
{Expression: "mp.ds_sd_kabupaten_kota", Alias: "ds_sd_kabupaten_kota"},
{Expression: "mp.ds_sd_kecamatan", Alias: "ds_sd_kecamatan"},
{Expression: "mp.ds_sd_kelurahan", Alias: "ds_sd_kelurahan"},
+ // Attachment fields
+ {Expression: "ma.id", Alias: "attachment_id"},
+ {Expression: "ma.name", Alias: "attachment_name"},
+ {Expression: "ma.file_name", Alias: "attachment_file_name"},
+ {Expression: "ma.directory", Alias: "attachment_directory"},
+ {Expression: "ma.active", Alias: "attachment_active"},
+ // Payment type fields
+ {Expression: "mpt.id", Alias: "payment_type_id"},
+ {Expression: "mpt.name", Alias: "payment_type_name"},
+ {Expression: "mpt.number", Alias: "payment_type_number"},
+ {Expression: "mpt.active", Alias: "payment_type_active"},
},
Sort: []queryUtils.SortField{
- {Column: "mp.id", Order: "ASC"},
+ {Column: "mp.name", Order: "ASC"},
+ },
+ Joins: []queryUtils.Join{
+ {
+ Type: "LEFT",
+ Table: "master.ms_patient_attachment",
+ Alias: "ma",
+ OnConditions: queryUtils.FilterGroup{
+ Filters: []queryUtils.DynamicFilter{
+ {Column: "ma.fk_ms_patient_id", Operator: queryUtils.OpEqual, Value: "mp.id"},
+ },
+ },
+ },
+ {
+ Type: "LEFT",
+ Table: "master.ms_patient_payment_type",
+ Alias: "mpt",
+ OnConditions: queryUtils.FilterGroup{
+ Filters: []queryUtils.DynamicFilter{
+ {Column: "mpt.fk_ms_patient_id", Operator: queryUtils.OpEqual, Value: "mp.id"},
+ },
+ },
+ },
},
}
// Parse pagination
- if limit, err := strconv.Atoi(c.DefaultQuery("limit", "10")); err == nil && limit > 0 && limit <= 100 {
- query.Limit = limit
- }
- if offset, err := strconv.Atoi(c.DefaultQuery("offset", "0")); err == nil && offset >= 0 {
- query.Offset = offset
- }
+ h.parsePagination(c, &query)
+ // Get database connection
dbConn, err := h.db.GetSQLXDB("db_antrean")
if err != nil {
h.logAndRespondError(c, "Database connection failed", err, http.StatusInternalServerError)
@@ -209,8 +240,13 @@ func (h *PatientHandler) GetMs_patient(c *gin.Context) {
// Parse filters
var filters []queryUtils.DynamicFilter
- if active := c.Query("active"); active != "" && models.IsValidStatus(active) {
- filters = append(filters, queryUtils.DynamicFilter{Column: "active", Operator: queryUtils.OpEqual, Value: active})
+ if active := c.Query("active"); active != "" {
+ if b, err := strconv.ParseBool(active); err == nil {
+ filters = append(filters, queryUtils.DynamicFilter{Column: "mp.active", Operator: queryUtils.OpEqual, Value: b})
+ } else {
+ h.respondError(c, "Invalid 'active' value; must be true or false", fmt.Errorf("invalid active value: %s", active), http.StatusBadRequest)
+ return
+ }
}
// Handle search with caching
@@ -224,9 +260,9 @@ func (h *PatientHandler) GetMs_patient(c *gin.Context) {
search = search[:50]
}
- cacheKey = fmt.Sprintf("ms_patient:search:%s:%d:%d", search, query.Limit, query.Offset)
+ cacheKey = fmt.Sprintf("patient:search:%s:%d:%d", search, query.Limit, query.Offset)
searchFilters = []queryUtils.DynamicFilter{
- {Column: "mp.medical_record_number", Operator: queryUtils.OpEqual, Value: "" + search + ""},
+ {Column: "mp.medical_record_number", Operator: queryUtils.OpILike, Value: "%" + search + "%"},
{Column: "mp.name", Operator: queryUtils.OpILike, Value: "%" + search + "%"},
{Column: "mp.phone_number", Operator: queryUtils.OpILike, Value: "%" + search + "%"},
}
@@ -252,7 +288,7 @@ func (h *PatientHandler) GetMs_patient(c *gin.Context) {
meta := h.calculateMeta(query.Limit, query.Offset, len(patients))
response := patientModels.PatientGetResponse{
- Message: "Data ms_patient berhasil diambil (dari cache)",
+ Message: "Data patient berhasil diambil (dari cache)",
Data: patients,
Meta: meta,
}
@@ -282,20 +318,20 @@ func (h *PatientHandler) GetMs_patient(c *gin.Context) {
return
}
- // Process results
- ms_patient := h.processQueryResults(results)
+ // Process results into structured format
+ patients := h.processQueryResults(results)
- // Get total count
+ // Get total count for pagination metadata
total, err := h.getTotalCount(ctx, dbConn, query)
if err != nil {
h.logAndRespondError(c, "Failed to get total count", err, http.StatusInternalServerError)
return
}
- // Cache results if search
- if useCache && len(ms_patient) > 0 {
- h.cache.Set(cacheKey, ms_patient, 15*time.Minute)
- logger.Info("Cached search results", map[string]interface{}{"search": search, "count": len(ms_patient)})
+ // Cache results if this was a search query
+ if useCache && len(patients) > 0 {
+ h.cache.Set(cacheKey, patients, 15*time.Minute)
+ logger.Info("Cached search results", map[string]interface{}{"search": search, "count": len(patients)})
}
// Get aggregate data if requested
@@ -308,11 +344,11 @@ func (h *PatientHandler) GetMs_patient(c *gin.Context) {
}
}
- // Build response
+ // Build and send response
meta := h.calculateMeta(query.Limit, query.Offset, total)
response := patientModels.PatientGetResponse{
- Message: "Data ms_patient berhasil diambil",
- Data: ms_patient,
+ Message: "Data patient berhasil diambil",
+ Data: patients,
Meta: meta,
}
@@ -324,8 +360,8 @@ func (h *PatientHandler) GetMs_patient(c *gin.Context) {
}
// GetPatientByIDPost godoc
-// @Summary Get patient by ID using POST request
-// @Description Retrieves a patient record by ID using POST request
+// @Summary Get Patient by ID
+// @Description Retrieves a single patient record by its ID, including attachments and payment types.
// @Tags Patient
// @Accept json
// @Produce json
@@ -335,111 +371,13 @@ func (h *PatientHandler) GetMs_patient(c *gin.Context) {
// @Failure 404 {object} models.ErrorResponse "Patient not found"
// @Failure 500 {object} models.ErrorResponse "Internal server error"
// @Router /patient/detail [post]
-// func (h *PatientHandler) GetPatientByIDPost(c *gin.Context) {
-// var req patientModels.PatientPostRequest
-// if err := c.ShouldBindJSON(&req); err != nil {
-// h.respondError(c, "Invalid request body", err, http.StatusBadRequest)
-// return
-// }
-
-// if err := patientvalidate.Struct(&req); err != nil {
-// h.respondError(c, "Validation failed", err, http.StatusBadRequest)
-// return
-// }
-
-// dbConn, err := h.db.GetSQLXDB("db_antrean")
-// if err != nil {
-// h.logAndRespondError(c, "Database connection failed", err, http.StatusInternalServerError)
-// return
-// }
-
-// ctx, cancel := context.WithTimeout(c.Request.Context(), 15*time.Second)
-// defer cancel()
-
-// // Check cache first
-// cacheKey := fmt.Sprintf("patient:id:%d", req.ID)
-// if cachedData, found := h.cache.Get(cacheKey); found {
-// if patient, ok := cachedData.(*patientModels.Patient); ok {
-// response := patientModels.PatientCreateResponse{
-// Message: "patient details retrieved successfully (dari cache)",
-// Data: patient,
-// }
-// c.JSON(http.StatusOK, response)
-// return
-// }
-// }
-
-// query := queryUtils.DynamicQuery{
-// From: "master.ms_patient",
-// Aliases: "mp",
-// Fields: []queryUtils.SelectField{
-// {Expression: "mp.id", Alias: "id"},
-// {Expression: "mp.name", Alias: "name"},
-// {Expression: "mp.medical_record_number", Alias: "medical_record_number"},
-// {Expression: "mp.phone_number", Alias: "phone_number"},
-// {Expression: "mp.gender", Alias: "gender"},
-// {Expression: "mp.birth_date", Alias: "birth_date"},
-// {Expression: "mp.address", Alias: "address"},
-// {Expression: "mp.active", Alias: "active"},
-// {Expression: "mp.fk_sd_provinsi_id", Alias: "fk_sd_provinsi_id"},
-// {Expression: "mp.fk_sd_kabupaten_kota_id", Alias: "fk_sd_kabupaten_kota_id"},
-// {Expression: "mp.fk_sd_kecamatan_id", Alias: "fk_sd_kecamatan_id"},
-// {Expression: "mp.fk_sd_kelurahan_id", Alias: "fk_sd_kelurahan_id"},
-// {Expression: "mp.ds_sd_provinsi", Alias: "ds_sd_provinsi"},
-// {Expression: "mp.ds_sd_kabupaten_kota", Alias: "ds_sd_kabupaten_kota"},
-// {Expression: "mp.ds_sd_kecamatan", Alias: "ds_sd_kecamatan"},
-// {Expression: "mp.ds_sd_kelurahan", Alias: "ds_sd_kelurahan"},
-// },
-// Filters: []queryUtils.FilterGroup{{
-// Filters: []queryUtils.DynamicFilter{
-// {Column: "mp.id", Operator: queryUtils.OpEqual, Value: req.ID},
-// },
-// LogicOp: "AND",
-// }},
-// Limit: 1,
-// }
-
-// var patient patientModels.Patient
-// err = h.queryBuilder.ExecuteQueryRow(ctx, dbConn, query, &patient)
-// if err != nil {
-// if err.Error() == "sql: no rows in result set" {
-// h.respondError(c, "Patient not found", err, http.StatusNotFound)
-// } else {
-// h.logAndRespondError(c, "Failed to get patient", err, http.StatusInternalServerError)
-// }
-// return
-// }
-
-// // Cache the result
-// h.cache.Set(cacheKey, &patient, 30*time.Minute)
-
-// response := patientModels.PatientCreateResponse{
-// Message: "patient details retrieved successfully",
-// Data: &patient,
-// }
-
-// c.JSON(http.StatusOK, response)
-// }
-
-// CreatePatient godoc
-// @Summary Create patient
-// @Description Creates a new patient record
-// @Tags Patient
-// @Accept json
-// @Produce json
-// @Param request body patientModels.PatientCreateRequest true "Patient creation request"
-// @Success 201 {object} patientModels.PatientCreateResponse "Patient created successfully"
-// @Failure 400 {object} models.ErrorResponse "Bad request or validation error"
-// @Failure 500 {object} models.ErrorResponse "Internal server error"
-// @Router /patient [post]
-func (h *PatientHandler) CreateMs_patient(c *gin.Context) {
- var req patientModels.PatientCreateRequest
+func (h *PatientHandler) GetPatientByIDPost(c *gin.Context) {
+ var req patientModels.PatientPostRequest
if err := c.ShouldBindJSON(&req); err != nil {
h.respondError(c, "Invalid request body", err, http.StatusBadRequest)
return
}
- // Validate request
if err := patientvalidate.Struct(&req); err != nil {
h.respondError(c, "Validation failed", err, http.StatusBadRequest)
return
@@ -454,650 +392,221 @@ func (h *PatientHandler) CreateMs_patient(c *gin.Context) {
ctx, cancel := context.WithTimeout(c.Request.Context(), 15*time.Second)
defer cancel()
- // Validate id must be unique
- if req.ID != nil {
- rule := validation.NewUniqueFieldRule(
- "master.ms_patient",
- "id",
- queryUtils.DynamicFilter{
- Column: "active",
- Operator: queryUtils.OpNotEqual,
- Value: false,
- },
- )
-
- dataToValidate := map[string]interface{}{"id": *req.ID}
- isDuplicate, err := h.validator.Validate(ctx, dbConn, rule, dataToValidate)
- if err != nil {
- h.logAndRespondError(c, "Failed to validate id", err, http.StatusInternalServerError)
- return
- }
-
- if isDuplicate {
- h.respondError(c, "id already exists", fmt.Errorf("duplicate id: %d", *req.ID), http.StatusConflict)
+ // Check cache first for fast lookups
+ cacheKey := fmt.Sprintf("patient:medical_record_number:%s", req.MedicalRecordNumber)
+ if cachedData, found := h.cache.Get(cacheKey); found {
+ if patient, ok := cachedData.(*patientModels.Patient); ok {
+ response := patientModels.PatientCreateResponse{
+ Message: "Patient details retrieved successfully (dari cache)",
+ Data: patient,
+ }
+ c.JSON(http.StatusOK, response)
return
}
}
- // Validate medical_record_number must be unique
- if req.MedicalRecordNumber != nil {
- rule := validation.NewUniqueFieldRule(
- "master.ms_patient",
- "medical_record_number",
- queryUtils.DynamicFilter{
- Column: "active",
- Operator: queryUtils.OpNotEqual,
- Value: false,
- },
- )
-
- dataToValidate := map[string]interface{}{"medical_record_number": req.MedicalRecordNumber}
- isDuplicate, err := h.validator.Validate(ctx, dbConn, rule, dataToValidate)
- if err != nil {
- h.logAndRespondError(c, "Failed to validate medical_record_number", err, http.StatusInternalServerError)
- return
- }
-
- if isDuplicate {
- h.respondError(c, "medical_record_number already exists", fmt.Errorf("duplicate medical_record_number: %s", *req.MedicalRecordNumber), http.StatusConflict)
- return
- }
- }
-
- data := queryUtils.InsertData{
- Columns: []string{
- "name", "medical_record_number", "phone_number", "gender",
- "birth_date", "address", "active", "fk_sd_provinsi_id",
- "fk_sd_kabupaten_kota_id", "fk_sd_kecamatan_id", "fk_sd_kelurahan_id",
- "ds_sd_provinsi", "ds_sd_kabupaten_kota", "ds_sd_kecamatan", "ds_sd_kelurahan",
+ // Build query with joins to get all related data in one go
+ query := queryUtils.DynamicQuery{
+ From: "master.ms_patient",
+ Aliases: "mp",
+ Fields: []queryUtils.SelectField{
+ {Expression: "mp.id", Alias: "id"},
+ {Expression: "mp.name", Alias: "name"},
+ {Expression: "mp.medical_record_number", Alias: "medical_record_number"},
+ {Expression: "mp.phone_number", Alias: "phone_number"},
+ {Expression: "mp.gender", Alias: "gender"},
+ {Expression: "mp.birth_date", Alias: "birth_date"},
+ {Expression: "mp.address", Alias: "address"},
+ {Expression: "mp.active", Alias: "active"},
+ {Expression: "mp.fk_sd_provinsi_id", Alias: "fk_sd_provinsi_id"},
+ {Expression: "mp.fk_sd_kabupaten_kota_id", Alias: "fk_sd_kabupaten_kota_id"},
+ {Expression: "mp.fk_sd_kecamatan_id", Alias: "fk_sd_kecamatan_id"},
+ {Expression: "mp.fk_sd_kelurahan_id", Alias: "fk_sd_kelurahan_id"},
+ {Expression: "mp.ds_sd_provinsi", Alias: "ds_sd_provinsi"},
+ {Expression: "mp.ds_sd_kabupaten_kota", Alias: "ds_sd_kabupaten_kota"},
+ {Expression: "mp.ds_sd_kecamatan", Alias: "ds_sd_kecamatan"},
+ {Expression: "mp.ds_sd_kelurahan", Alias: "ds_sd_kelurahan"},
+ // Attachment fields
+ {Expression: "ma.id", Alias: "attachment_id"},
+ {Expression: "ma.name", Alias: "attachment_name"},
+ {Expression: "ma.file_name", Alias: "attachment_file_name"},
+ {Expression: "ma.directory", Alias: "attachment_directory"},
+ {Expression: "ma.active", Alias: "attachment_active"},
+ // Payment type fields
+ {Expression: "mpt.id", Alias: "payment_type_id"},
+ {Expression: "mpt.name", Alias: "payment_type_name"},
+ {Expression: "mpt.number", Alias: "payment_type_number"},
+ {Expression: "mpt.active", Alias: "payment_type_active"},
},
- Values: []interface{}{
- req.Name, req.MedicalRecordNumber, req.PhoneNumber, req.Gender,
- req.BirthDate, req.Address, req.Active, req.FKSdProvinsiID,
- req.FKSdKabupatenKotaID, req.FKSdKecamatanID, req.FKSdKelurahanID,
- req.DsSdProvinsi, req.DsSdKabupatenKota, req.DsSdKecamatan, req.DsSdKelurahan,
- },
- }
- returningCols := []string{
- "id", "name", "medical_record_number", "phone_number", "gender",
- "birth_date", "address", "active", "fk_sd_provinsi_id",
- "fk_sd_kabupaten_kota_id", "fk_sd_kecamatan_id", "fk_sd_kelurahan_id",
- "ds_sd_provinsi", "ds_sd_kabupaten_kota", "ds_sd_kecamatan", "ds_sd_kelurahan",
- }
-
- sql, args, err := h.queryBuilder.BuildInsertQuery("master.ms_patient", data, returningCols...)
- if err != nil {
- h.logAndRespondError(c, "Failed to build insert query", err, http.StatusInternalServerError)
- return
- }
-
- var dataMs_patient patientModels.Patient
- err = dbConn.GetContext(ctx, &dataMs_patient, sql, args...)
- if err != nil {
- h.logAndRespondError(c, "Failed to create patient", err, http.StatusInternalServerError)
- return
- }
-
- h.invalidateRelatedCache()
- response := patientModels.PatientCreateResponse{
- Message: "Patient berhasil dibuat",
- Data: &dataMs_patient,
- }
-
- c.JSON(http.StatusCreated, response)
-}
-
-// UpdatePatient godoc
-// @Summary Update patient
-// @Description Updates an existing patient record
-// @Tags Patient
-// @Accept json
-// @Produce json
-// @Param id path string true "Medical Record Number"
-// @Param request body patientModels.PatientUpdateRequest true "Patient update request"
-// @Success 200 {object} patientModels.PatientUpdateResponse "Patient updated successfully"
-// @Failure 400 {object} models.ErrorResponse "Bad request or validation error"
-// @Failure 404 {object} models.ErrorResponse "Patient not found"
-// @Failure 500 {object} models.ErrorResponse "Internal server error"
-// @Router /patient/{id} [put]
-func (h *PatientHandler) UpdateMs_patient(c *gin.Context) {
- medical_record_number := c.Param("medical_record_number")
- if medical_record_number == "" {
- h.respondError(c, "Invalid medical_record_number format", fmt.Errorf("medical_record_number cannot be empty"), http.StatusBadRequest)
- return
- }
-
- var req patientModels.PatientUpdateRequest
- if err := c.ShouldBindJSON(&req); err != nil {
- h.respondError(c, "Invalid request body", err, http.StatusBadRequest)
- return
- }
-
- // Set medical_record_number from path parameter (string)
- req.MedicalRecordNumber = &medical_record_number
-
- // Validate request
- if err := patientvalidate.Struct(&req); err != nil {
- h.respondError(c, "Validation failed", err, http.StatusBadRequest)
- return
- }
-
- // Get old data for cache invalidation
- var oldData patientModels.Patient
- dbConn, err := h.db.GetSQLXDB("db_antrean")
- if err == nil {
- ctx, cancel := context.WithTimeout(c.Request.Context(), 5*time.Second)
- defer cancel()
-
- query := queryUtils.DynamicQuery{
- From: "master.ms_patient",
- Aliases: "mp",
- Fields: []queryUtils.SelectField{{Expression: "*"}},
- Filters: []queryUtils.FilterGroup{{
- Filters: []queryUtils.DynamicFilter{
- {Column: "mp.medical_record_number", Operator: queryUtils.OpEqual, Value: medical_record_number},
+ Joins: []queryUtils.Join{
+ {
+ Type: "LEFT",
+ Table: "master.ms_patient_attachment",
+ Alias: "ma",
+ OnConditions: queryUtils.FilterGroup{
+ Filters: []queryUtils.DynamicFilter{
+ {Column: "ma.fk_ms_patient_id", Operator: queryUtils.OpEqual, Value: "mp.id"},
+ },
+ },
+ },
+ {
+ Type: "LEFT",
+ Table: "master.ms_patient_payment_type",
+ Alias: "mpt",
+ OnConditions: queryUtils.FilterGroup{
+ Filters: []queryUtils.DynamicFilter{
+ {Column: "mpt.fk_ms_patient_id", Operator: queryUtils.OpEqual, Value: "mp.id"},
+ },
},
- LogicOp: "AND",
- }},
- Limit: 1,
- }
-
- err = h.queryBuilder.ExecuteQueryRow(ctx, dbConn, query, &oldData)
- if err != nil {
- logger.Error("Failed to fetch old data for cache invalidation", map[string]interface{}{"error": err.Error(), "medical_record_number": medical_record_number})
- }
- }
-
- dbConn, err = h.db.GetSQLXDB("db_antrean")
- if err != nil {
- h.logAndRespondError(c, "Database connection failed", err, http.StatusInternalServerError)
- return
- }
-
- ctx, cancel := context.WithTimeout(c.Request.Context(), 15*time.Second)
- defer cancel()
-
- // Validate medical_record_number must be unique
- if req.MedicalRecordNumber != nil {
- rule := validation.ValidationRule{
- TableName: "role_access.rol_pages",
- UniqueColumns: []string{"medical_record_number"},
- Conditions: []queryUtils.DynamicFilter{
- {Column: "active", Operator: queryUtils.OpNotEqual, Value: false},
},
- ExcludeIDColumn: "medical_record_number",
- ExcludeIDValue: medical_record_number,
- }
-
- dataToValidate := map[string]interface{}{"medical_record_number": req.MedicalRecordNumber}
- isDuplicate, err := h.validator.Validate(ctx, dbConn, rule, dataToValidate)
- if err != nil {
- h.logAndRespondError(c, "Failed to validate medical_record_number", err, http.StatusInternalServerError)
- return
- }
-
- if isDuplicate {
- h.respondError(c, "medical_record_number already exists", fmt.Errorf("duplicate medical_record_number: %s", *req.MedicalRecordNumber), http.StatusConflict)
- return
- }
- }
-
- updateData := queryUtils.UpdateData{
- Columns: []string{
- "name", "medical_record_number", "phone_number", "gender",
- "birth_date", "address", "active", "fk_sd_provinsi_id",
- "fk_sd_kabupaten_kota_id", "fk_sd_kecamatan_id", "fk_sd_kelurahan_id",
- "ds_sd_provinsi", "ds_sd_kabupaten_kota", "ds_sd_kecamatan", "ds_sd_kelurahan",
},
- Values: []interface{}{
- req.Name, req.MedicalRecordNumber, req.PhoneNumber, req.Gender,
- req.BirthDate, req.Address, req.Active, req.FKSdProvinsiID,
- req.FKSdKabupatenKotaID, req.FKSdKecamatanID, req.FKSdKelurahanID,
- req.DsSdProvinsi, req.DsSdKabupatenKota, req.DsSdKecamatan, req.DsSdKelurahan,
- },
- }
- filters := []queryUtils.FilterGroup{{
- Filters: []queryUtils.DynamicFilter{
- {Column: "medical_record_number", Operator: queryUtils.OpEqual, Value: req.MedicalRecordNumber},
- },
- LogicOp: "AND",
- }}
- returningCols := []string{
- "id", "name", "medical_record_number", "phone_number", "gender",
- "birth_date", "address", "active", "fk_sd_provinsi_id",
- "fk_sd_kabupaten_kota_id", "fk_sd_kecamatan_id", "fk_sd_kelurahan_id",
- "ds_sd_provinsi", "ds_sd_kabupaten_kota", "ds_sd_kecamatan", "ds_sd_kelurahan",
+ Filters: []queryUtils.FilterGroup{{
+ Filters: []queryUtils.DynamicFilter{
+ {Column: "mp.medical_record_number", Operator: queryUtils.OpEqual, Value: req.MedicalRecordNumber},
+ },
+ LogicOp: "AND",
+ }},
+ Limit: 1,
}
- sql, args, err := h.queryBuilder.BuildUpdateQuery("master.ms_patient", updateData, filters, returningCols...)
- if err != nil {
- h.logAndRespondError(c, "Failed to build update query", err, http.StatusInternalServerError)
- return
- }
-
- var dataMs_patient patientModels.Patient
- err = dbConn.GetContext(ctx, &dataMs_patient, sql, args...)
- if err != nil {
- if err.Error() == "sql: no rows in result set" {
+ var results []map[string]interface{}
+ if err := h.queryBuilder.ExecuteQuery(ctx, dbConn, query, &results); err != nil {
+ if err == sql.ErrNoRows {
h.respondError(c, "Patient not found", err, http.StatusNotFound)
} else {
- h.logAndRespondError(c, "Failed to update patient", err, http.StatusInternalServerError)
+ h.logAndRespondError(c, "Failed to get patient", err, http.StatusInternalServerError)
}
return
}
- // Invalidate cache
- cacheKey := fmt.Sprintf("patient:medical_record_number:%s", medical_record_number)
- h.cache.Delete(cacheKey)
-
- if oldData.ID != 0 {
- h.invalidateRelatedCache()
+ patients := h.processQueryResults(results)
+ if len(patients) == 0 {
+ h.respondError(c, "Patient not found", fmt.Errorf("no rows"), http.StatusNotFound)
+ return
}
- response := patientModels.PatientUpdateResponse{
- Message: "Patient berhasil diperbarui",
- Data: &dataMs_patient,
+ patient := patients[0]
+
+ // Cache the result for future requests
+ h.cache.Set(cacheKey, &patient, 30*time.Minute)
+
+ response := patientModels.PatientCreateResponse{
+ Message: "Patient details retrieved successfully",
+ Data: &patient,
}
c.JSON(http.StatusOK, response)
}
-// DeletePatient godoc
-// @Summary Delete patient
-// @Description Soft deletes a patient by setting status to 'deleted'
-// @Tags Patient
-// @Accept json
-// @Produce json
-// @Param id path string true "Medical Record Number"
-// @Success 200 {object} patientModels.PatientDeleteResponse "Patient deleted successfully"
-// @Failure 400 {object} models.ErrorResponse "Invalid ID format"
-// @Failure 404 {object} models.ErrorResponse "Patient not found"
-// @Failure 500 {object} models.ErrorResponse "Internal server error"
-// @Router /patient/{id} [delete]
-func (h *PatientHandler) DeleteMs_patient(c *gin.Context) {
- medical_record_number := c.Param("medical_record_number")
- if medical_record_number == "" {
- h.respondError(c, "Invalid medical_record_number format", fmt.Errorf("medical_record_number cannot be empty"), http.StatusBadRequest)
- return
+// =============================================================================
+// HELPER FUNCTIONS (READ-ONLY)
+// =============================================================================
+
+// parsePagination parses pagination parameters from the request
+func (h *PatientHandler) parsePagination(c *gin.Context, query *queryUtils.DynamicQuery) {
+ if limit, err := strconv.Atoi(c.DefaultQuery("limit", "10")); err == nil && limit > 0 && limit <= 100 {
+ query.Limit = limit
}
-
- // Get data for cache invalidation
- var dataToDelete patientModels.Patient
- dbConn, err := h.db.GetSQLXDB("db_antrean")
- if err == nil {
- ctx, cancel := context.WithTimeout(c.Request.Context(), 5*time.Second)
- defer cancel()
-
- query := queryUtils.DynamicQuery{
- From: "master.ms_patient",
- Aliases: "mp",
- Fields: []queryUtils.SelectField{{Expression: "*"}},
- Filters: []queryUtils.FilterGroup{{
- Filters: []queryUtils.DynamicFilter{
- {Column: "mp.medical_record_number", Operator: queryUtils.OpEqual, Value: medical_record_number},
- },
- LogicOp: "AND",
- }},
- Limit: 1,
- }
-
- err = h.queryBuilder.ExecuteQueryRow(ctx, dbConn, query, &dataToDelete)
- if err != nil {
- logger.Error("Failed to fetch data for cache invalidation", map[string]interface{}{"error": err.Error(), "medical_record_number": medical_record_number})
- }
+ if offset, err := strconv.Atoi(c.DefaultQuery("offset", "0")); err == nil && offset >= 0 {
+ query.Offset = offset
}
-
- dbConn, err = h.db.GetSQLXDB("db_antrean")
- if err != nil {
- h.logAndRespondError(c, "Database connection failed", err, http.StatusInternalServerError)
- return
- }
-
- ctx, cancel := context.WithTimeout(c.Request.Context(), 15*time.Second)
- defer cancel()
-
- // Soft delete by changing active status
- updateData := queryUtils.UpdateData{
- Columns: []string{"active"},
- Values: []interface{}{false},
- }
- filters := []queryUtils.FilterGroup{{
- Filters: []queryUtils.DynamicFilter{
- {Column: "medical_record_number", Operator: queryUtils.OpEqual, Value: medical_record_number},
- {Column: "active", Operator: queryUtils.OpNotEqual, Value: false},
- },
- LogicOp: "AND",
- }}
-
- result, err := h.queryBuilder.ExecuteUpdate(ctx, dbConn, "master.ms_patient", updateData, filters)
- if err != nil {
- h.logAndRespondError(c, "Failed to delete patient", err, http.StatusInternalServerError)
- return
- }
-
- rowsAffected, err := result.RowsAffected()
- if err != nil {
- h.logAndRespondError(c, "Failed to get affected rows", err, http.StatusInternalServerError)
- return
- }
- if rowsAffected == 0 {
- h.respondError(c, "Patient not found", sql.ErrNoRows, http.StatusNotFound)
- return
- }
-
- // Invalidate cache
- cacheKey := fmt.Sprintf("patient:medical_record_number:%s", medical_record_number)
- h.cache.Delete(cacheKey)
-
- if dataToDelete.ID != 0 {
- h.invalidateRelatedCache()
- }
-
- response := patientModels.PatientDeleteResponse{
- Message: "Patient berhasil dihapus",
- MedicalRecordNumber: medical_record_number,
- }
-
- c.JSON(http.StatusOK, response)
}
-// GetPatientStats godoc
-// @Summary Get patient statistics
-// @Description Returns comprehensive statistics about patient data
-// @Tags Patient
-// @Accept json
-// @Produce json
-// @Param status query string false "Filter statistics by status"
-// @Success 200 {object} models.AggregateData "Statistics data"
-// @Failure 500 {object} models.ErrorResponse "Internal server error"
-// @Router /api/v1/patients/stats [get]
-// func (h *PatientHandler) GetPatientStats(c *gin.Context) {
-// dbConn, err := h.db.GetSQLXDB("db_antrean")
-// if err != nil {
-// h.logAndRespondError(c, "Database connection failed", err, http.StatusInternalServerError)
-// return
-// }
-
-// ctx, cancel := context.WithTimeout(c.Request.Context(), 15*time.Second)
-// defer cancel()
-
-// // Parse filters
-// var filters []queryUtils.DynamicFilter
-// if status := c.Query("status"); status != "" && models.IsValidStatus(status) {
-// filters = append(filters, queryUtils.DynamicFilter{Column: "active", Operator: queryUtils.OpEqual, Value: status})
-// }
-
-// var filterGroups []queryUtils.FilterGroup
-// if len(filters) > 0 {
-// filterGroups = append(filterGroups, queryUtils.FilterGroup{Filters: filters, LogicOp: "AND"})
-// }
-
-// aggregateData, err := h.getAggregateData(ctx, dbConn, filterGroups)
-// if err != nil {
-// h.logAndRespondError(c, "Failed to get statistics", err, http.StatusInternalServerError)
-// return
-// }
-
-// c.JSON(http.StatusOK, gin.H{
-// "message": "Statistik patient berhasil diambil",
-// "data": aggregateData,
-// })
-// }
-
-// SearchPatientAdvanced provides advanced search capabilities
-// func (h *PatientHandler) SearchPatientAdvanced(c *gin.Context) {
-// ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second)
-// defer cancel()
-
-// // Parse complex search parameters
-// searchQuery := c.Query("norm")
-// if searchQuery == "" {
-// // If no search query provided, return all records with default sorting
-// query := queryUtils.DynamicQuery{
-// From: "master.ms_patient",
-// Aliases: "mp",
-// Fields: []queryUtils.SelectField{
-// {Expression: "mp.id", Alias: "id"},
-// {Expression: "mp.name", Alias: "name"},
-// {Expression: "mp.medical_record_number", Alias: "medical_record_number"},
-// {Expression: "mp.phone_number", Alias: "phone_number"},
-// {Expression: "mp.gender", Alias: "gender"},
-// {Expression: "mp.birth_date", Alias: "birth_date"},
-// {Expression: "mp.address", Alias: "address"},
-// {Expression: "mp.active", Alias: "active"},
-// },
-// Filters: []queryUtils.FilterGroup{{
-// Filters: []queryUtils.DynamicFilter{
-// {Column: "mp.active", Operator: queryUtils.OpEqual, Value: true},
-// },
-// LogicOp: "AND",
-// }},
-// Sort: []queryUtils.SortField{{
-// Column: "mp.id",
-// Order: "ASC",
-// }},
-// Limit: 20,
-// Offset: 0,
-// }
-
-// // Parse pagination if provided
-// if limit := c.Query("limit"); limit != "" {
-// if l, err := strconv.Atoi(limit); err == nil && l > 0 && l <= 100 {
-// query.Limit = l
-// }
-// }
-
-// if offset := c.Query("offset"); offset != "" {
-// if o, err := strconv.Atoi(offset); err == nil && o >= 0 {
-// query.Offset = o
-// }
-// }
-
-// // Get database connection
-// dbConn, err := h.db.GetSQLXDB("db_antrean")
-// if err != nil {
-// h.logAndRespondError(c, "Database connection failed", err, http.StatusInternalServerError)
-// return
-// }
-
-// // Execute query to get all records
-// var results []map[string]interface{}
-// err = h.queryBuilder.ExecuteQuery(ctx, dbConn, query, &results)
-// if err != nil {
-// h.logAndRespondError(c, "Failed to fetch data", err, http.StatusInternalServerError)
-// return
-// }
-
-// patients := h.processQueryResults(results)
-// total, err := h.getTotalCount(ctx, dbConn, query)
-// if err != nil {
-// h.logAndRespondError(c, "Failed to get total count", err, http.StatusInternalServerError)
-// return
-// }
-
-// // Build response
-// meta := h.calculateMeta(query.Limit, query.Offset, total)
-// response := patientModels.PatientGetResponse{
-// Message: "All records retrieved (no search query provided)",
-// Data: patients,
-// Meta: meta,
-// }
-
-// c.JSON(http.StatusOK, response)
-// return
-// }
-
-// // Build dynamic query for search
-// filters := []queryUtils.DynamicFilter{
-// {Column: "mp.medical_record_number", Operator: queryUtils.OpContains, Value: searchQuery},
-// {Column: "mp.active", Operator: queryUtils.OpEqual, Value: true},
-// }
-
-// query := queryUtils.DynamicQuery{
-// From: "master.ms_patient",
-// Aliases: "mp",
-// Fields: []queryUtils.SelectField{
-// {Expression: "mp.id", Alias: "id"},
-// {Expression: "mp.name", Alias: "name"},
-// {Expression: "mp.medical_record_number", Alias: "medical_record_number"},
-// {Expression: "mp.phone_number", Alias: "phone_number"},
-// {Expression: "mp.gender", Alias: "gender"},
-// {Expression: "mp.birth_date", Alias: "birth_date"},
-// {Expression: "mp.address", Alias: "address"},
-// {Expression: "mp.active", Alias: "active"},
-// },
-// Filters: []queryUtils.FilterGroup{{
-// Filters: filters,
-// LogicOp: "AND",
-// }},
-// Sort: []queryUtils.SortField{{
-// Column: "mp.id",
-// Order: "ASC",
-// }},
-// Limit: 20,
-// Offset: 0,
-// }
-
-// // Parse pagination if provided
-// if limit := c.Query("limit"); limit != "" {
-// if l, err := strconv.Atoi(limit); err == nil && l > 0 && l <= 100 {
-// query.Limit = l
-// }
-// }
-// if offset := c.Query("offset"); offset != "" {
-// if o, err := strconv.Atoi(offset); err == nil && o >= 0 {
-// query.Offset = o
-// }
-// }
-
-// // Get database connection
-// dbConn, err := h.db.GetSQLXDB("db_antrean")
-// if err != nil {
-// h.logAndRespondError(c, "Database connection failed", err, http.StatusInternalServerError)
-// return
-// }
-
-// // Execute search
-// var results []map[string]interface{}
-// err = h.queryBuilder.ExecuteQuery(ctx, dbConn, query, &results)
-// if err != nil {
-// h.logAndRespondError(c, "Search failed", err, http.StatusInternalServerError)
-// return
-// }
-
-// patients := h.processQueryResults(results)
-// total, err := h.getTotalCount(ctx, dbConn, query)
-// if err != nil {
-// h.logAndRespondError(c, "Failed to get total count", err, http.StatusInternalServerError)
-// return
-// }
-
-// // Build response
-// meta := h.calculateMeta(query.Limit, query.Offset, total)
-// response := patientModels.PatientGetResponse{
-// Message: fmt.Sprintf("Search results for '%s'", searchQuery),
-// Data: patients,
-// Meta: meta,
-// }
-
-// c.JSON(http.StatusOK, response)
-// }
-
-// =============================================================================
-// HELPER FUNCTIONS
-// =============================================================================
-
+// processQueryResults processes the flat query results into a structured nested format
func (h *PatientHandler) processQueryResults(results []map[string]interface{}) []patientModels.Patient {
- patients := make([]patientModels.Patient, 0, len(results))
+ patientsMap := make(map[int64]*patientModels.Patient)
+ order := make([]int64, 0, len(results))
for _, result := range results {
- patient := patientModels.Patient{
- ID: getInt64(result, "id"),
- Name: getNullString(result, "name"),
- MedicalRecordNumber: getNullString(result, "medical_record_number"),
- PhoneNumber: getNullString(result, "phone_number"),
- Gender: getNullString(result, "gender"),
- BirthDate: getNullTime(result, "birth_date"),
- Address: getNullString(result, "address"),
- Active: getNullBool(result, "active"),
- FKSdProvinsiID: getNullableInt32(result, "fk_sd_provinsi_id"),
- FKSdKabupatenKotaID: getNullableInt32(result, "fk_sd_kabupaten_kota_id"),
- FKSdKecamatanID: getNullableInt32(result, "fk_sd_kecamatan_id"),
- FKSdKelurahanID: getNullableInt32(result, "fk_sd_kelurahan_id"),
- DsSdProvinsi: getNullString(result, "ds_sd_provinsi"),
- DsSdKabupatenKota: getNullString(result, "ds_sd_kabupaten_kota"),
- DsSdKecamatan: getNullString(result, "ds_sd_kecamatan"),
- DsSdKelurahan: getNullString(result, "ds_sd_kelurahan"),
+ patientID := getInt64(result, "id")
+
+ patient, exists := patientsMap[patientID]
+ if !exists {
+ patient = &patientModels.Patient{
+ ID: patientID,
+ Name: getNullString(result, "name"),
+ MedicalRecordNumber: getNullString(result, "medical_record_number"),
+ PhoneNumber: getNullString(result, "phone_number"),
+ Gender: getNullString(result, "gender"),
+ BirthDate: getNullTime(result, "birth_date"),
+ Address: getNullString(result, "address"),
+ Active: getNullBool(result, "active"),
+ FKSdProvinsiID: getNullableInt32(result, "fk_sd_provinsi_id"),
+ FKSdKabupatenKotaID: getNullableInt32(result, "fk_sd_kabupaten_kota_id"),
+ FKSdKecamatanID: getNullableInt32(result, "fk_sd_kecamatan_id"),
+ FKSdKelurahanID: getNullableInt32(result, "fk_sd_kelurahan_id"),
+ DsSdProvinsi: getNullString(result, "ds_sd_provinsi"),
+ DsSdKabupatenKota: getNullString(result, "ds_sd_kabupaten_kota"),
+ DsSdKecamatan: getNullString(result, "ds_sd_kecamatan"),
+ DsSdKelurahan: getNullString(result, "ds_sd_kelurahan"),
+ Attachments: []patientModels.PatientAttachment{},
+ PaymentTypes: []patientModels.PatientPaymentType{},
+ }
+ patientsMap[patientID] = patient
+ order = append(order, patientID)
+ }
+
+ // Process and add attachment if it exists
+ if attachmentID := getInt64(result, "attachment_id"); attachmentID != 0 {
+ if !h.hasAttachment(patient, attachmentID) {
+ patient.Attachments = append(patient.Attachments, patientModels.PatientAttachment{
+ ID: attachmentID,
+ Name: getNullString(result, "attachment_name"),
+ FileName: getNullString(result, "attachment_file_name"),
+ Directory: getNullString(result, "attachment_directory"),
+ Active: getNullBool(result, "attachment_active"),
+ FKMsPatientID: getNullableInt32(result, "fk_ms_patient_id"),
+ })
+ }
+ }
+
+ // Process and add payment type if it exists
+ if paymentTypeID := getInt64(result, "payment_type_id"); paymentTypeID != 0 {
+ if !h.hasPaymentType(patient, paymentTypeID) {
+ patient.PaymentTypes = append(patient.PaymentTypes, patientModels.PatientPaymentType{
+ ID: paymentTypeID,
+ Name: getNullString(result, "payment_type_name"),
+ Number: getNullString(result, "payment_type_number"),
+ Active: getNullBool(result, "payment_type_active"),
+ FKMsPatientID: getNullableInt32(result, "fk_ms_patient_id"),
+ FKRefPaymentType: getNullableInt32(result, "fk_ref_payment_type"),
+ })
+ }
+ }
+ }
+
+ // Convert map to slice while preserving order
+ patients := make([]patientModels.Patient, 0, len(patientsMap))
+ for _, id := range order {
+ if p, ok := patientsMap[id]; ok {
+ patients = append(patients, *p)
}
- patients = append(patients, patient)
}
return patients
}
-// Helper functions for extracting values from map[string]interface{}
-func getInt64(m map[string]interface{}, key string) int64 {
- if val, ok := m[key]; ok {
- switch v := val.(type) {
- case int64:
- return v
- case int:
- return int64(v)
- case float64:
- return int64(v)
+// hasAttachment checks if an attachment already exists in the patient's slice
+func (h *PatientHandler) hasAttachment(patient *patientModels.Patient, attachmentID int64) bool {
+ for _, att := range patient.Attachments {
+ if att.ID == attachmentID {
+ return true
}
}
- return 0
+ return false
}
-func getString(m map[string]interface{}, key string) string {
- if val, ok := m[key]; ok {
- if v, ok := val.(string); ok {
- return v
+// hasPaymentType checks if a payment type already exists in the patient's slice
+func (h *PatientHandler) hasPaymentType(patient *patientModels.Patient, paymentTypeID int64) bool {
+ for _, pt := range patient.PaymentTypes {
+ if pt.ID == paymentTypeID {
+ return true
}
}
- return ""
-}
-
-func getNullString(m map[string]interface{}, key string) sql.NullString {
- if val, ok := m[key]; ok {
- if ns, ok := val.(sql.NullString); ok {
- return ns
- }
- if s, ok := val.(string); ok {
- return sql.NullString{String: s, Valid: true}
- }
- }
- return sql.NullString{Valid: false}
-}
-
-func getNullableInt32(m map[string]interface{}, key string) models.NullableInt32 {
- if val, ok := m[key]; ok {
- if v, ok := val.(models.NullableInt32); ok {
- return v
- }
- }
- return models.NullableInt32{}
-}
-
-func getNullBool(m map[string]interface{}, key string) sql.NullBool {
- if val, ok := m[key]; ok {
- if v, ok := val.(sql.NullBool); ok {
- return v
- }
- }
- return sql.NullBool{}
-}
-
-func getNullTime(m map[string]interface{}, key string) sql.NullTime {
- if val, ok := m[key]; ok {
- if v, ok := val.(sql.NullTime); ok {
- return v
- }
- }
- return sql.NullTime{}
+ return false
}
+// getTotalCount gets the total count of records matching the query
func (h *PatientHandler) getTotalCount(ctx context.Context, dbConn *sqlx.DB, query queryUtils.DynamicQuery) (int, error) {
countQuery := queryUtils.DynamicQuery{
From: query.From,
@@ -1114,13 +623,7 @@ func (h *PatientHandler) getTotalCount(ctx context.Context, dbConn *sqlx.DB, que
return int(count), nil
}
-func (h *PatientHandler) invalidateRelatedCache() {
- h.cache.DeleteByPrefix("patient:search:")
- h.cache.DeleteByPrefix("patient:dynamic:")
- h.cache.DeleteByPrefix("patient:stats:")
- h.cache.DeleteByPrefix("patient:id:")
-}
-
+// getAggregateData gets aggregate data for the patients
func (h *PatientHandler) getAggregateData(ctx context.Context, dbConn *sqlx.DB, filterGroups []queryUtils.FilterGroup) (*models.AggregateData, error) {
aggregate := &models.AggregateData{
ByStatus: make(map[string]int),
@@ -1260,11 +763,13 @@ func (h *PatientHandler) getAggregateData(ctx context.Context, dbConn *sqlx.DB,
return aggregate, nil
}
+// logAndRespondError logs an error and sends an error response
func (h *PatientHandler) logAndRespondError(c *gin.Context, message string, err error, statusCode int) {
logger.Error(message, map[string]interface{}{"error": err.Error(), "status_code": statusCode})
h.respondError(c, message, err, statusCode)
}
+// respondError sends an error response
func (h *PatientHandler) respondError(c *gin.Context, message string, err error, statusCode int) {
errorMessage := message
if gin.Mode() == gin.ReleaseMode {
@@ -1273,6 +778,7 @@ func (h *PatientHandler) respondError(c *gin.Context, message string, err error,
c.JSON(statusCode, models.ErrorResponse{Error: errorMessage, Code: statusCode, Message: err.Error(), Timestamp: time.Now()})
}
+// calculateMeta calculates pagination metadata
func (h *PatientHandler) calculateMeta(limit, offset, total int) models.MetaResponse {
totalPages, currentPage := 0, 1
if limit > 0 {
@@ -1284,3 +790,71 @@ func (h *PatientHandler) calculateMeta(limit, offset, total int) models.MetaResp
CurrentPage: currentPage, HasNext: offset+limit < total, HasPrev: offset > 0,
}
}
+
+// =============================================================================
+// UTILITY FUNCTIONS (DATA EXTRACTION)
+// =============================================================================
+
+// getInt64 safely extracts an int64 from a map[string]interface{}
+func getInt64(m map[string]interface{}, key string) int64 {
+ if val, ok := m[key]; ok {
+ switch v := val.(type) {
+ case int64:
+ return v
+ case int:
+ return int64(v)
+ case float64:
+ return int64(v)
+ }
+ }
+ return 0
+}
+
+// getNullString safely extracts a sql.NullString from a map[string]interface{}
+func getNullString(m map[string]interface{}, key string) sql.NullString {
+ if val, ok := m[key]; ok {
+ if ns, ok := val.(sql.NullString); ok {
+ return ns
+ }
+ if s, ok := val.(string); ok {
+ return sql.NullString{String: s, Valid: true}
+ }
+ }
+ return sql.NullString{Valid: false}
+}
+
+// getNullableInt32 safely extracts a models.NullableInt32 from a map[string]interface{}
+func getNullableInt32(m map[string]interface{}, key string) models.NullableInt32 {
+ if val, ok := m[key]; ok {
+ if v, ok := val.(models.NullableInt32); ok {
+ return v
+ }
+ }
+ return models.NullableInt32{}
+}
+
+// getNullBool safely extracts a sql.NullBool from a map[string]interface{}
+func getNullBool(m map[string]interface{}, key string) sql.NullBool {
+ if val, ok := m[key]; ok {
+ if nb, ok := val.(sql.NullBool); ok {
+ return nb
+ }
+ if b, ok := val.(bool); ok {
+ return sql.NullBool{Bool: b, Valid: true}
+ }
+ }
+ return sql.NullBool{Valid: false}
+}
+
+// getNullTime safely extracts a sql.NullTime from a map[string]interface{}
+func getNullTime(m map[string]interface{}, key string) sql.NullTime {
+ if val, ok := m[key]; ok {
+ if nt, ok := val.(sql.NullTime); ok {
+ return nt
+ }
+ if t, ok := val.(time.Time); ok {
+ return sql.NullTime{Time: t, Valid: true}
+ }
+ }
+ return sql.NullTime{Valid: false}
+}
diff --git a/internal/handlers/websocket/websocket.go b/internal/handlers/websocket/websocket.go
new file mode 100644
index 0000000..798f842
--- /dev/null
+++ b/internal/handlers/websocket/websocket.go
@@ -0,0 +1,205 @@
+package websocket
+
+import (
+ "api-service/internal/config"
+ ws "api-service/internal/services/websocket"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "time"
+
+ "github.com/gin-gonic/gin"
+ "github.com/gorilla/websocket"
+)
+
+// WebSocketHandler menangani koneksi WebSocket
+type WebSocketHandler struct {
+ hub *ws.Hub
+ broadcaster *ws.Broadcaster
+ config config.WebSocketConfig
+ upgrader websocket.Upgrader
+ monitoringManager *ws.MonitoringManager
+}
+
+// NewWebSocketHandler membuat handler WebSocket baru
+func NewWebSocketHandler(hub *ws.Hub, broadcaster *ws.Broadcaster, config config.WebSocketConfig) *WebSocketHandler {
+ return &WebSocketHandler{
+ hub: hub,
+ broadcaster: broadcaster,
+ config: config,
+ monitoringManager: ws.NewMonitoringManager(hub),
+ upgrader: websocket.Upgrader{
+ ReadBufferSize: config.ReadBufferSize,
+ WriteBufferSize: config.WriteBufferSize,
+ CheckOrigin: func(r *http.Request) bool {
+ // Dalam production, implementasikan validasi origin yang proper
+ return true
+ },
+ },
+ }
+}
+
+// HandleWebSocket menangani upgrade koneksi ke WebSocket
+func (h *WebSocketHandler) HandleWebSocket(c *gin.Context) {
+ // Ambil parameter dari query atau header
+ clientID := c.Query("client_id")
+ if clientID == "" {
+ clientID = fmt.Sprintf("client_%d", time.Now().UnixNano())
+ }
+
+ staticID := c.Query("static_id")
+ userID := c.Query("user_id")
+ room := c.Query("room")
+ ipAddress := c.ClientIP()
+
+ // Upgrade koneksi HTTP ke WebSocket
+ conn, err := h.upgrader.Upgrade(c.Writer, c.Request, nil)
+ if err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{
+ "error": "Failed to upgrade connection",
+ "details": err.Error(),
+ })
+ return
+ }
+
+ // Buat klien WebSocket baru
+ client := ws.NewClient(clientID, staticID, userID, room, ipAddress, conn, h.hub, h.config)
+
+ // Daftarkan klien ke hub
+ h.hub.RegisterChannel() <- client
+
+ // Jalankan goroutine untuk membaca dan menulis
+ go client.ReadPump()
+ go client.WritePump()
+}
+
+// GetWebSocketStats mengembalikan statistik WebSocket
+func (h *WebSocketHandler) GetWebSocketStats(c *gin.Context) {
+ stats := h.hub.GetStats()
+ c.JSON(http.StatusOK, stats)
+}
+
+// TestWebSocketConnection endpoint untuk test koneksi WebSocket
+func (h *WebSocketHandler) TestWebSocketConnection(c *gin.Context) {
+ c.JSON(http.StatusOK, gin.H{
+ "message": "WebSocket service is running",
+ "status": "active",
+ "endpoint": "/api/v1/ws",
+ "parameters": gin.H{
+ "client_id": "optional, auto-generated if not provided",
+ "static_id": "optional, for persistent client identification",
+ "user_id": "optional, for user identification",
+ "room": "optional, for room-based messaging",
+ },
+ "example": "ws://meninjar.dev.rssa.id:8070/api/v1/ws?client_id=test_client&room=test_room",
+ "timestamp": time.Now().Unix(),
+ })
+}
+
+// GetDetailedStats mengembalikan statistik detail WebSocket
+func (h *WebSocketHandler) GetDetailedStats(c *gin.Context) {
+ detailedStats := h.monitoringManager.GetDetailedStats()
+ c.JSON(http.StatusOK, gin.H{
+ "admin_stats": detailedStats,
+ "timestamp": time.Now().Unix(),
+ })
+}
+
+// DisconnectClient memutuskan koneksi klien tertentu
+func (h *WebSocketHandler) DisconnectClient(c *gin.Context) {
+ clientID := c.Param("clientId")
+ success := h.monitoringManager.DisconnectClient(clientID)
+ c.JSON(http.StatusOK, gin.H{
+ "status": "force disconnect attempted",
+ "client_id": clientID,
+ "success": success,
+ "timestamp": time.Now().Unix(),
+ })
+}
+
+// CleanupInactiveClients membersihkan klien tidak aktif
+func (h *WebSocketHandler) CleanupInactiveClients(c *gin.Context) {
+ var req struct {
+ InactiveMinutes int `json:"inactive_minutes"`
+ Force bool `json:"force"`
+ }
+ if err := c.ShouldBindJSON(&req); err != nil {
+ req.InactiveMinutes = 10
+ req.Force = false
+ }
+
+ cleanedCount := h.monitoringManager.CleanupInactiveClients(time.Duration(req.InactiveMinutes) * time.Minute)
+ c.JSON(http.StatusOK, gin.H{
+ "status": "admin cleanup completed",
+ "cleaned_clients": cleanedCount,
+ "inactive_minutes": req.InactiveMinutes,
+ "force": req.Force,
+ "timestamp": time.Now().Unix(),
+ })
+}
+
+// SendMessageToClient forwards a message to a specific connected client via an HTTP POST request.
+// This version normalizes the data and uses the custom broadcaster method for clean delivery.
+func (h *WebSocketHandler) SendMessageToClient(c *gin.Context) {
+ // Define a flexible struct to parse the incoming HTTP request body
+ var req struct {
+ Data interface{} `json:"data"`
+ ToClient string `json:"to_client"`
+ Type string `json:"type"`
+ }
+
+ // Parse the JSON from the HTTP request body
+ if err := c.ShouldBindJSON(&req); err != nil {
+ c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
+ return
+ }
+
+ // Normalize data into map[string]interface{} for consistency
+ var dataMap map[string]interface{}
+ switch v := req.Data.(type) {
+ case map[string]interface{}:
+ dataMap = v
+ case string:
+ // If data is a JSON string, try to unmarshal it
+ if err := json.Unmarshal([]byte(v), &dataMap); err != nil {
+ // If unmarshaling fails, treat it as a raw string
+ dataMap = map[string]interface{}{"raw": v}
+ }
+ default:
+ // For any other type, wrap it in a map
+ dataMap = map[string]interface{}{"data": v}
+ }
+
+ // Get the target client ID, checking the body first, then the query parameter
+ to := req.ToClient
+ if to == "" {
+ to = c.Query("to")
+ }
+ if to == "" {
+ c.JSON(http.StatusBadRequest, gin.H{"error": "target client id required (field 'to' or query param 'to')"})
+ return
+ }
+
+ msgType := req.Type
+ if msgType == "" {
+ msgType = "direct_message"
+ }
+
+ // Use the existing broadcaster instance from the Hub.
+ // DO NOT create a new broadcaster on every request.
+ h.broadcaster.CustomBroadcastClientToClient(
+ "server", // fromClientID, indicating the message is from the server itself
+ to, // toClientID
+ msgType, // messageType, as specified in the request
+ dataMap, // data payload, already normalized
+ )
+
+ // Respond with a detailed confirmation
+ c.JSON(http.StatusOK, gin.H{
+ "status": "sent",
+ "to_client": to,
+ "type": msgType,
+ "data": dataMap,
+ "timestamp": time.Now().Unix(),
+ })
+}
diff --git a/internal/models/pages/rol_pages.go b/internal/models/pages/rol_pages.go
index 5832eb7..72dd458 100644
--- a/internal/models/pages/rol_pages.go
+++ b/internal/models/pages/rol_pages.go
@@ -247,8 +247,8 @@ type PagesUpdateResponse struct {
// Update request
type PagesUpdateRequest struct {
- IDs *int `json:"id" validate:"omitempty"` // used when updating via JSON array (bulk)
- ID *int `json:"-" validate:"omitempty"` // required for single update via URL param
+ IDs *int `json:"id" validate:"omitempty"` // used when updating via JSON array (bulk)
+ ID *int `json:"-" validate:"omitempty,min=1"` // required for single update via URL param
// Status string `json:"status" validate:"required,oneof=draft active inactive"`
Name *string `json:"name" validate:"omitempty,min=1,max=20"`
Icon *string `json:"icon" validate:"omitempty,min=1,max=100"`
diff --git a/internal/models/patient/ms_patient.go b/internal/models/patient/ms_patient.go
index 9001241..d687ab2 100644
--- a/internal/models/patient/ms_patient.go
+++ b/internal/models/patient/ms_patient.go
@@ -106,6 +106,26 @@ type Patient struct {
DsSdKabupatenKota sql.NullString `json:"ds_sd_kabupaten_kota,omitempty" db:"ds_sd_kabupaten_kota"`
DsSdKecamatan sql.NullString `json:"ds_sd_kecamatan,omitempty" db:"ds_sd_kecamatan"`
DsSdKelurahan sql.NullString `json:"ds_sd_kelurahan,omitempty" db:"ds_sd_kelurahan"`
+ Attachments []PatientAttachment `json:"attachments,omitempty"`
+ PaymentTypes []PatientPaymentType `json:"payment_types,omitempty"`
+}
+
+type PatientPaymentType struct {
+ ID int64 `json:"id" db:"id"`
+ Name sql.NullString `json:"name,omitempty" db:"name"`
+ Number sql.NullString `json:"number,omitempty" db:"number"`
+ Active sql.NullBool `json:"active,omitempty" db:"active"`
+ FKMsPatientID models.NullableInt32 `json:"fk_ms_patient_id,omitempty" db:"fk_ms_patient_id"`
+ FKRefPaymentType models.NullableInt32 `json:"fk_ref_payment_type,omitempty" db:"fk_ref_payment_type"`
+}
+
+type PatientAttachment struct {
+ ID int64 `json:"id" db:"id"`
+ Name sql.NullString `json:"name,omitempty" db:"name"`
+ FileName sql.NullString `json:"file_name,omitempty" db:"file_name"`
+ Directory sql.NullString `json:"directory,omitempty" db:"directory"`
+ Active sql.NullBool `json:"active,omitempty" db:"active"`
+ FKMsPatientID models.NullableInt32 `json:"fk_ms_patient_id,omitempty" db:"fk_ms_patient_id"`
}
// Custom JSON marshaling untuk Patient agar NULL values tidak muncul di response
@@ -186,6 +206,71 @@ func (r Patient) MarshalJSON() ([]byte, error) {
return json.Marshal(aux)
}
+func (r PatientPaymentType) MarshalJSON() ([]byte, error) {
+ type Alias PatientPaymentType
+ aux := &struct {
+ *Alias
+ Name *string `json:"name,omitempty"`
+ Number *string `json:"number,omitempty"`
+ Active *bool `json:"active,omitempty"`
+ FKMsPatientID *int `json:"fk_ms_patient_id,omitempty"`
+ FKRefPaymentType *int `json:"fk_ref_payment_type,omitempty"`
+ }{
+ Alias: (*Alias)(&r),
+ }
+
+ if r.Name.Valid {
+ aux.Name = &r.Name.String
+ }
+ if r.Number.Valid {
+ aux.Number = &r.Number.String
+ }
+ if r.Active.Valid {
+ aux.Active = &r.Active.Bool
+ }
+ if r.FKMsPatientID.Valid {
+ fkmp := int(r.FKMsPatientID.Int32)
+ aux.FKMsPatientID = &fkmp
+ }
+ if r.FKRefPaymentType.Valid {
+ fkrpt := int(r.FKRefPaymentType.Int32)
+ aux.FKRefPaymentType = &fkrpt
+ }
+ return json.Marshal(aux)
+}
+
+func (r PatientAttachment) MarshalJSON() ([]byte, error) {
+ type Alias PatientAttachment
+ aux := &struct {
+ *Alias
+ Name *string `json:"name,omitempty"`
+ FileName *string `json:"file_name,omitempty"`
+ Directory *string `json:"directory,omitempty"`
+ Active *bool `json:"active,omitempty"`
+ FKMsPatientID *int `json:"fk_ms_patient_id,omitempty"`
+ }{
+ Alias: (*Alias)(&r),
+ }
+
+ if r.Name.Valid {
+ aux.Name = &r.Name.String
+ }
+ if r.FileName.Valid {
+ aux.FileName = &r.FileName.String
+ }
+ if r.Directory.Valid {
+ aux.Directory = &r.Directory.String
+ }
+ if r.Active.Valid {
+ aux.Active = &r.Active.Bool
+ }
+ if r.FKMsPatientID.Valid {
+ fkmp := int(r.FKMsPatientID.Int32)
+ aux.FKMsPatientID = &fkmp
+ }
+ return json.Marshal(aux)
+}
+
// Helper methods untuk mendapatkan nilai yang aman
func (r *Patient) GetName() string {
if r.Name.Valid {
@@ -210,26 +295,29 @@ type PatientGetResponse struct {
// Request struct untuk create
type PatientCreateRequest struct {
- ID *int `json:"id"`
- Name *string `json:"name" validate:"min=1,max=100"`
- MedicalRecordNumber *string `json:"medical_record_number" validate:"min=1,max=20"`
- PhoneNumber *string `json:"phone_number" validate:"min=1,max=20"`
- Gender *string `json:"gender" validate:"max=1"`
- BirthDate *time.Time `json:"birth_date"`
- Address *string `json:"address" validate:"min=1,max=255"`
- Active *bool `json:"active"`
- FKSdProvinsiID *int32 `json:"fk_sd_provinsi_id"`
- FKSdKabupatenKotaID *int32 `json:"fk_sd_kabupaten_kota_id"`
- FKSdKecamatanID *int32 `json:"fk_sd_kecamatan_id"`
- FKSdKelurahanID *int32 `json:"fk_sd_kelurahan_id"`
- DsSdProvinsi *string `json:"ds_sd_provinsi" validate:"min=1,max=255"`
- DsSdKabupatenKota *string `json:"ds_sd_kabupaten_kota" validate:"min=1,max=255"`
- DsSdKecamatan *string `json:"ds_sd_kecamatan" validate:"min=1,max=255"`
- DsSdKelurahan *string `json:"ds_sd_kelurahan" validate:"min=1,max=255"`
+ ID *int `json:"id"`
+ Name *string `json:"name" validate:"min=1,max=100"`
+ MedicalRecordNumber *string `json:"medical_record_number" validate:"min=1,max=20"`
+ PhoneNumber *string `json:"phone_number" validate:"min=1,max=20"`
+ Gender *string `json:"gender" validate:"max=1"`
+ BirthDate *time.Time `json:"birth_date"`
+ Address *string `json:"address" validate:"min=1,max=255"`
+ Active *bool `json:"active"`
+ FKSdProvinsiID *int32 `json:"fk_sd_provinsi_id"`
+ FKSdKabupatenKotaID *int32 `json:"fk_sd_kabupaten_kota_id"`
+ FKSdKecamatanID *int32 `json:"fk_sd_kecamatan_id"`
+ FKSdKelurahanID *int32 `json:"fk_sd_kelurahan_id"`
+ DsSdProvinsi *string `json:"ds_sd_provinsi" validate:"min=1,max=255"`
+ DsSdKabupatenKota *string `json:"ds_sd_kabupaten_kota" validate:"min=1,max=255"`
+ DsSdKecamatan *string `json:"ds_sd_kecamatan" validate:"min=1,max=255"`
+ DsSdKelurahan *string `json:"ds_sd_kelurahan" validate:"min=1,max=255"`
+ Attachments []PatientAttachmentCreateRequest `json:"attachments,omitempty"`
+ Payments []PatientPaymentTypeCreateRequest `json:"payment_types,omitempty"`
}
type PatientPostRequest struct {
- ID int64 `json:"id" validate:"required,min=1"`
+ // ID int64 `json:"id" validate:"required,min=1"`
+ MedicalRecordNumber string `json:"medical_record_number" validate:"required,min=1"`
}
// Response struct untuk create
@@ -240,22 +328,56 @@ type PatientCreateResponse struct {
// Update request
type PatientUpdateRequest struct {
- ID *int `json:"id" validate:"required,min=1"`
- Name *string `json:"name" validate:"min=1,max=100"`
- MedicalRecordNumber *string `json:"medical_record_number" validate:"min=1,max=20"`
- PhoneNumber *string `json:"phone_number" validate:"min=1,max=20"`
- Gender *string `json:"gender" validate:"max=1"`
- BirthDate *time.Time `json:"birth_date"`
- Address *string `json:"address" validate:"min=1,max=255"`
- Active *bool `json:"active"`
- FKSdProvinsiID *int32 `json:"fk_sd_provinsi_id"`
- FKSdKabupatenKotaID *int32 `json:"fk_sd_kabupaten_kota_id"`
- FKSdKecamatanID *int32 `json:"fk_sd_kecamatan_id"`
- FKSdKelurahanID *int32 `json:"fk_sd_kelurahan_id"`
- DsSdProvinsi *string `json:"ds_sd_provinsi" validate:"max=255"`
- DsSdKabupatenKota *string `json:"ds_sd_kabupaten_kota" validate:"max=255"`
- DsSdKecamatan *string `json:"ds_sd_kecamatan" validate:"max=255"`
- DsSdKelurahan *string `json:"ds_sd_kelurahan" validate:"max=255"`
+ ID *int `json:"-" validate:"required,min=1"`
+ Name *string `json:"name" validate:"min=1,max=100"`
+ MedicalRecordNumber *string `json:"medical_record_number" validate:"min=1,max=20"`
+ PhoneNumber *string `json:"phone_number" validate:"min=1,max=20"`
+ Gender *string `json:"gender" validate:"max=1"`
+ BirthDate *time.Time `json:"birth_date"`
+ Address *string `json:"address" validate:"min=1,max=255"`
+ Active *bool `json:"active"`
+ FKSdProvinsiID *int32 `json:"fk_sd_provinsi_id"`
+ FKSdKabupatenKotaID *int32 `json:"fk_sd_kabupaten_kota_id"`
+ FKSdKecamatanID *int32 `json:"fk_sd_kecamatan_id"`
+ FKSdKelurahanID *int32 `json:"fk_sd_kelurahan_id"`
+ DsSdProvinsi *string `json:"ds_sd_provinsi" validate:"max=255"`
+ DsSdKabupatenKota *string `json:"ds_sd_kabupaten_kota" validate:"max=255"`
+ DsSdKecamatan *string `json:"ds_sd_kecamatan" validate:"max=255"`
+ DsSdKelurahan *string `json:"ds_sd_kelurahan" validate:"max=255"`
+ Attachments []PatientAttachmentCreateRequest `json:"attachments,omitempty"`
+ Payments []PatientPaymentTypeCreateRequest `json:"payment_types,omitempty"`
+}
+
+type PatientAttachmentCreateRequest struct {
+ // ID *int `json:"id,omitempty"`
+ Name *string `json:"name" validate:"omitempty,min=1,max=20"`
+ FileName *string `json:"file_name" validate:"omitempty,min=1,max=20"`
+ Directory *string `json:"directory" validate:"omitempty,min=1,max=255"`
+ Active *bool `json:"active" validate:"omitempty"`
+}
+
+type PatientPaymentTypeCreateRequest struct {
+ // ID *int `json:"id,omitempty"`
+ Name *string `json:"name" validate:"omitempty,min=1,max=20"`
+ Number *string `json:"number" validate:"omitempty,min=1,max=20"`
+ Active *bool `json:"active" validate:"omitempty"`
+ FkRefPaymentType *int `json:"fk_ref_payment_type" validate:"omitempty,min=1"`
+}
+
+type PatientAttachmentUpdateRequest struct {
+ ID *int `json:"id" validate:"required"`
+ Name *string `json:"name" validate:"omitempty,min=1,max=20"`
+ FileName *string `json:"file_name" validate:"omitempty,min=1,max=20"`
+ Directory *string `json:"directory" validate:"omitempty,min=1,max=255"`
+ Active *bool `json:"active" validate:"omitempty"`
+}
+
+type PatientPaymentTypeUpdateRequest struct {
+ ID *int `json:"id" validate:"required"`
+ Name *string `json:"name" validate:"omitempty,min=1,max=20"`
+ Number *string `json:"number" validate:"omitempty,min=1,max=20"`
+ Active *bool `json:"active" validate:"omitempty"`
+ FkRefPaymentType *int `json:"fk_ref_payment_type" validate:"omitempty,min=1"`
}
// Response struct untuk update
diff --git a/internal/routes/v1/routes.go b/internal/routes/v1/routes.go
index e3957f1..c30b86f 100644
--- a/internal/routes/v1/routes.go
+++ b/internal/routes/v1/routes.go
@@ -4,15 +4,14 @@ import (
"api-service/internal/config"
"api-service/internal/database"
authHandlers "api-service/internal/handlers/auth"
- componentRolcomponentHandlers "api-service/internal/handlers/component"
healthcheckHandlers "api-service/internal/handlers/healthcheck"
pagesRolpagesHandlers "api-service/internal/handlers/pages"
pasienPasienHandlers "api-service/internal/handlers/pasien"
patientMspatientHandlers "api-service/internal/handlers/patient"
- permissionRolpermissionHandlers "api-service/internal/handlers/permission"
- retribusiHandlers "api-service/internal/handlers/retribusi"
+ websocketHandlers "api-service/internal/handlers/websocket"
"api-service/internal/middleware"
services "api-service/internal/services/auth"
+ websocketServices "api-service/internal/services/websocket"
"api-service/pkg/logger"
"net/http"
"strings"
@@ -86,16 +85,18 @@ func RegisterRoutes(cfg *config.Config) *gin.Engine {
})
sistem.GET("/info", func(c *gin.Context) {
c.JSON(200, gin.H{
- "service": "API Service v1.0.0",
- "websocket_active": true,
- "databases": dbService.ListDBs(),
- "timestamp": time.Now().Unix(),
+ "service": "API Service v1.0.0",
+ "websocket_active": true,
+ "connected_clients": 0,
+ "databases": dbService.ListDBs(),
+ "timestamp": time.Now().Unix(),
})
})
}
// --- API v1 GROUP ---
v1 := apiGroup.Group("/v1")
+
{
// =============================================================================
// PUBLIC ROUTES (No Authentication Required)
@@ -110,22 +111,22 @@ func RegisterRoutes(cfg *config.Config) *gin.Engine {
v1.POST("/token/generate", tokenHandler.GenerateToken)
v1.POST("/token/generate-direct", tokenHandler.GenerateTokenDirect)
- retribusiHandler := retribusiHandlers.NewRetribusiHandler()
- retribusiGroup := v1.Group("/retribusi")
- {
- retribusiGroup.GET("", retribusiHandler.GetRetribusi)
- retribusiGroup.GET("/dynamic", retribusiHandler.GetRetribusiDynamic)
- retribusiGroup.GET("/id/:id", retribusiHandler.GetRetribusiByID)
- retribusiGroup.POST("", func(c *gin.Context) {
- retribusiHandler.CreateRetribusi(c)
- })
- retribusiGroup.PUT("/id/:id", func(c *gin.Context) {
- retribusiHandler.UpdateRetribusi(c)
- })
- retribusiGroup.DELETE("/id/:id", func(c *gin.Context) {
- retribusiHandler.DeleteRetribusi(c)
- })
- }
+ // retribusiHandler := retribusiHandlers.NewRetribusiHandler()
+ // retribusiGroup := v1.Group("/retribusi")
+ // {
+ // retribusiGroup.GET("", retribusiHandler.GetRetribusi)
+ // retribusiGroup.GET("/dynamic", retribusiHandler.GetRetribusiDynamic)
+ // retribusiGroup.GET("/id/:id", retribusiHandler.GetRetribusiByID)
+ // retribusiGroup.POST("", func(c *gin.Context) {
+ // retribusiHandler.CreateRetribusi(c)
+ // })
+ // retribusiGroup.PUT("/id/:id", func(c *gin.Context) {
+ // retribusiHandler.UpdateRetribusi(c)
+ // })
+ // retribusiGroup.DELETE("/id/:id", func(c *gin.Context) {
+ // retribusiHandler.DeleteRetribusi(c)
+ // })
+ // }
// Pasien endpoints
pasienPasienHandler := pasienPasienHandlers.NewPasienHandler()
pasienPasienGroup := v1.Group("/pasien")
@@ -151,34 +152,55 @@ func RegisterRoutes(cfg *config.Config) *gin.Engine {
pagesRolpagesGroup.DELETE("/:id", pagesRolpagesHandler.DeleteRol_pages)
}
+ // Initialize WebSocket hub with database service
+ websocketHub := websocketServices.NewHub(cfg.WebSocket)
+ go websocketHub.Run() // Start WebSocket hub in background
+
+ // -- Start broadcaster (needed for server -> client messaging) --
+ broadcaster := websocketServices.NewBroadcaster(websocketHub)
+ broadcaster.StartServerBroadcasters()
+
+ // Initialize WebSocket handler
+ websocketHandler := websocketHandlers.NewWebSocketHandler(websocketHub, broadcaster, cfg.WebSocket)
+
+ // WebSocket routes
+ v1.GET("/ws", websocketHandler.HandleWebSocket)
+ v1.GET("/ws/test", websocketHandler.TestWebSocketConnection)
+ v1.GET("/ws/stats", websocketHandler.GetWebSocketStats)
+
+ // Public endpoint to send message to a specific client (no auth)
+ v1.POST("/ws", websocketHandler.SendMessageToClient)
+
// Rol_component endpoints
- componentRolcomponentHandler := componentRolcomponentHandlers.NewRol_componentHandler()
- componentRolcomponentGroup := v1.Group("/component")
- {
- componentRolcomponentGroup.GET("/", componentRolcomponentHandler.GetRol_components)
- componentRolcomponentGroup.POST("/", componentRolcomponentHandler.CreateRol_component)
- componentRolcomponentGroup.PUT("/:id", componentRolcomponentHandler.UpdateRol_component)
- componentRolcomponentGroup.DELETE("/:id", componentRolcomponentHandler.DeleteRol_component)
- }
+ // componentRolcomponentHandler := componentRolcomponentHandlers.NewRol_componentHandler()
+ // componentRolcomponentGroup := v1.Group("/component")
+ // {
+ // componentRolcomponentGroup.GET("/", componentRolcomponentHandler.GetRol_components)
+ // componentRolcomponentGroup.POST("/", componentRolcomponentHandler.CreateRol_component)
+ // componentRolcomponentGroup.PUT("/:id", componentRolcomponentHandler.UpdateRol_component)
+ // componentRolcomponentGroup.DELETE("/:id", componentRolcomponentHandler.DeleteRol_component)
+ // }
// Rol_permission endpoints
- permissionRolpermissionHandler := permissionRolpermissionHandlers.NewRol_permissionHandler()
- permissionRolpermissionGroup := v1.Group("/permission")
- {
- permissionRolpermissionGroup.GET("/", permissionRolpermissionHandler.GetRol_permissions)
- permissionRolpermissionGroup.POST("/", permissionRolpermissionHandler.CreateRol_permission)
- permissionRolpermissionGroup.PUT("/:id", permissionRolpermissionHandler.UpdateRol_permission)
- permissionRolpermissionGroup.DELETE("/:id", permissionRolpermissionHandler.DeleteRol_permission)
- }
+ // permissionRolpermissionHandler := permissionRolpermissionHandlers.NewRol_permissionHandler()
+ // permissionRolpermissionGroup := v1.Group("/permission")
+ // {
+ // permissionRolpermissionGroup.GET("/", permissionRolpermissionHandler.GetRol_permissions)
+ // permissionRolpermissionGroup.POST("/", permissionRolpermissionHandler.CreateRol_permission)
+ // permissionRolpermissionGroup.PUT("/:id", permissionRolpermissionHandler.UpdateRol_permission)
+ // permissionRolpermissionGroup.DELETE("/:id", permissionRolpermissionHandler.DeleteRol_permission)
+ // }
// Ms_patient endpoints
patientMspatientHandler := patientMspatientHandlers.NewPatientHandler()
patientMspatientGroup := v1.Group("/patient")
{
- patientMspatientGroup.GET("/", patientMspatientHandler.GetMs_patient)
- patientMspatientGroup.POST("/", patientMspatientHandler.CreateMs_patient)
- patientMspatientGroup.PUT("/:medical_record_number", patientMspatientHandler.UpdateMs_patient)
- patientMspatientGroup.DELETE("/:medical_record_number", patientMspatientHandler.DeleteMs_patient)
+ // patientMspatientGroup.GET("/", patientMspatientHandler.GetMs_patient)
+ // patientMspatientGroup.POST("/", patientMspatientHandler.CreateMs_patient)
+ // patientMspatientGroup.PUT("/:medical_record_number", patientMspatientHandler.UpdateMs_patient)
+ // patientMspatientGroup.DELETE("/:medical_record_number", patientMspatientHandler.DeleteMs_patient)
+ patientMspatientGroup.GET("/", patientMspatientHandler.GetPatient)
+ patientMspatientGroup.POST("/detail", patientMspatientHandler.GetPatientByIDPost)
}
// =============================================================================
diff --git a/internal/services/websocket/broadcaster.go b/internal/services/websocket/broadcaster.go
new file mode 100644
index 0000000..807d158
--- /dev/null
+++ b/internal/services/websocket/broadcaster.go
@@ -0,0 +1,219 @@
+package websocket
+
+import (
+ "time"
+)
+
+// Broadcaster mengelola broadcasting pesan
+type Broadcaster struct {
+ hub *Hub
+}
+
+// NewBroadcaster membuat broadcaster baru
+func NewBroadcaster(hub *Hub) *Broadcaster {
+ return &Broadcaster{hub: hub}
+}
+
+// StartServerBroadcasters memulai broadcaster server
+func (b *Broadcaster) StartServerBroadcasters() {
+ // Heartbeat broadcaster
+ // go b.startHeartbeatBroadcaster()
+
+ // System notification broadcaster
+ go b.startSystemNotificationBroadcaster()
+
+ // Data stream broadcaster
+ // go b.startDataStreamBroadcaster()
+}
+
+// startHeartbeatBroadcaster memulai broadcaster heartbeat
+func (b *Broadcaster) startHeartbeatBroadcaster() {
+ ticker := time.NewTicker(30 * time.Second)
+ defer ticker.Stop()
+
+ for {
+ select {
+ case <-ticker.C:
+ b.hub.mu.RLock()
+ connectedClients := len(b.hub.clients)
+ uniqueIPs := len(b.hub.clientsByIP)
+ staticClients := len(b.hub.clientsByStatic)
+ b.hub.mu.RUnlock()
+
+ b.BroadcastMessage("server_heartbeat", map[string]interface{}{
+ "message": "Server heartbeat",
+ "connected_clients": connectedClients,
+ "unique_ips": uniqueIPs,
+ "static_clients": staticClients,
+ "timestamp": time.Now().Unix(),
+ "server_id": b.hub.config.ServerID,
+ })
+ case <-b.hub.ctx.Done():
+ return
+ }
+ }
+}
+
+// startSystemNotificationBroadcaster memulai broadcaster notifikasi sistem
+func (b *Broadcaster) startSystemNotificationBroadcaster() {
+ ticker := time.NewTicker(5 * time.Minute)
+ defer ticker.Stop()
+
+ for {
+ select {
+ case <-ticker.C:
+ dbHealth := b.hub.dbService.Health()
+ b.BroadcastMessage("system_status", map[string]interface{}{
+ "type": "system_notification",
+ "database": dbHealth,
+ "timestamp": time.Now().Unix(),
+ "uptime": time.Since(b.hub.startTime).String(),
+ })
+ case <-b.hub.ctx.Done():
+ return
+ }
+ }
+}
+
+// startDataStreamBroadcaster memulai broadcaster aliran data
+func (b *Broadcaster) startDataStreamBroadcaster() {
+ ticker := time.NewTicker(10 * time.Second)
+ defer ticker.Stop()
+ counter := 0
+
+ for {
+ select {
+ case <-ticker.C:
+ counter++
+ b.BroadcastMessage("data_stream", map[string]interface{}{
+ "id": counter,
+ "value": counter * 10,
+ "timestamp": time.Now().Unix(),
+ "type": "real_time_data",
+ })
+ case <-b.hub.ctx.Done():
+ return
+ }
+ }
+}
+
+// BroadcastMessage mengirim pesan ke semua klien
+func (b *Broadcaster) BroadcastMessage(messageType string, data interface{}) {
+ msg := NewWebSocketMessage(MessageType(messageType), data, "", "")
+
+ select {
+ case b.hub.messageQueue <- msg:
+ default:
+ // Antrian penuh, abaikan pesan
+ }
+}
+
+// BroadcastToRoom mengirim pesan ke ruangan tertentu
+func (b *Broadcaster) BroadcastToRoom(room string, messageType string, data interface{}) {
+ msg := NewWebSocketMessage(
+ MessageType(messageType),
+ map[string]interface{}{
+ "room": room,
+ "data": data,
+ },
+ "",
+ room,
+ )
+
+ select {
+ case b.hub.messageQueue <- msg:
+ default:
+ // Antrian penuh, abaikan pesan
+ }
+}
+
+// SendToClient mengirim pesan ke klien tertentu
+func (b *Broadcaster) SendToClient(clientID string, messageType string, data interface{}) {
+ msg := NewWebSocketMessage(MessageType(messageType), data, clientID, "")
+
+ select {
+ case b.hub.messageQueue <- msg:
+ default:
+ // Antrian penuh, abaikan pesan
+ }
+}
+
+// SendToClientByStaticID mengirim pesan ke klien berdasarkan ID statis
+func (b *Broadcaster) SendToClientByStaticID(staticID string, messageType string, data interface{}) bool {
+ b.hub.mu.RLock()
+ client, exists := b.hub.clientsByStatic[staticID]
+ b.hub.mu.RUnlock()
+
+ if !exists {
+ return false
+ }
+
+ b.SendToClient(client.ID, messageType, data)
+ return true
+}
+
+// BroadcastToIP mengirim pesan ke semua klien dari IP tertentu
+func (b *Broadcaster) BroadcastToIP(ipAddress string, messageType string, data interface{}) int {
+ b.hub.mu.RLock()
+ clients := b.hub.clientsByIP[ipAddress]
+ b.hub.mu.RUnlock()
+
+ count := 0
+ for _, client := range clients {
+ b.SendToClient(client.ID, messageType, data)
+ count++
+ }
+
+ return count
+}
+
+// BroadcastClientToClient mengirim pesan dari satu klien ke klien lain
+func (b *Broadcaster) BroadcastClientToClient(fromClientID, toClientID string, messageType string, data interface{}) {
+ message := NewWebSocketMessage(MessageType(messageType), map[string]interface{}{
+ "from_client_id": fromClientID,
+ "data": data,
+ }, toClientID, "")
+ b.hub.broadcast <- message
+}
+
+// BroadcastServerToClient mengirim pesan dari server ke klien tertentu
+func (b *Broadcaster) BroadcastServerToClient(clientID string, messageType string, data interface{}) {
+ message := NewWebSocketMessage(MessageType(messageType), data, clientID, "")
+ b.hub.broadcast <- message
+}
+
+// BroadcastServerToRoom mengirim pesan dari server ke ruangan tertentu
+func (b *Broadcaster) BroadcastServerToRoom(room string, messageType string, data interface{}) {
+ message := NewWebSocketMessage(MessageType(messageType), data, "", room)
+ b.hub.broadcast <- message
+}
+
+// BroadcastServerToAll mengirim pesan dari server ke semua klien
+func (b *Broadcaster) BroadcastServerToAll(messageType string, data interface{}) {
+ message := NewWebSocketMessage(MessageType(messageType), data, "", "")
+ b.hub.broadcast <- message
+}
+
+// CustomBroadcastClientToClient sends a message from one client to another.
+// It intelligently adds the 'from_client_id' to the payload to avoid unnecessary nesting.
+// If the payload is a map, the ID is added directly. Otherwise, the payload is wrapped.
+func (b *Broadcaster) CustomBroadcastClientToClient(from, to, msgType string, data interface{}) {
+ // Create the message with the data directly.
+ msg := NewWebSocketMessage(MessageType(msgType), data, to, "")
+
+ // Ensure from_client_id is available at the same level as the payload.
+ // If the payload is a map[string]interface{}, add the key directly.
+ // If not, wrap it once as "data" to avoid losing information.
+ if m, ok := msg.Data.(map[string]interface{}); ok {
+ m["from_client_id"] = from
+ msg.Data = m
+ } else {
+ msg.Data = map[string]interface{}{
+ "data": msg.Data,
+ "from_client_id": from,
+ }
+ }
+
+ // Send the message to the hub for delivery.
+ b.hub.broadcast <- msg
+}
diff --git a/internal/services/websocket/client.go b/internal/services/websocket/client.go
new file mode 100644
index 0000000..96ed7ca
--- /dev/null
+++ b/internal/services/websocket/client.go
@@ -0,0 +1,728 @@
+package websocket
+
+import (
+ "api-service/internal/config"
+ "context"
+ "encoding/json"
+ "fmt"
+ "sync"
+ "time"
+
+ "github.com/google/uuid"
+ "github.com/gorilla/websocket"
+)
+
+// Client mewakili koneksi klien WebSocket
+type Client struct {
+ // Identifikasi
+ ID string
+ StaticID string
+ UserID string
+ Room string
+
+ // Koneksi
+ IPAddress string
+ Conn *websocket.Conn
+ Send chan WebSocketMessage
+
+ // Hub
+ Hub *Hub
+
+ // Context
+ ctx context.Context
+ cancel context.CancelFunc
+
+ // Status
+ lastPing time.Time
+ lastPong time.Time
+ connectedAt time.Time
+ isActive bool
+
+ // Sinkronisasi
+ mu sync.RWMutex
+}
+
+// NewClient membuat klien baru
+func NewClient(
+ id, staticID, userID, room, ipAddress string,
+ conn *websocket.Conn,
+ hub *Hub,
+ config config.WebSocketConfig,
+) *Client {
+ ctx, cancel := context.WithCancel(hub.ctx)
+
+ return &Client{
+ ID: id,
+ StaticID: staticID,
+ UserID: userID,
+ Room: room,
+ IPAddress: ipAddress,
+ Conn: conn,
+ Send: make(chan WebSocketMessage, config.ChannelBufferSize),
+ Hub: hub,
+ ctx: ctx,
+ cancel: cancel,
+ lastPing: time.Now(),
+ connectedAt: time.Now(),
+ isActive: true,
+ }
+}
+
+// readPup menangani pembacaan pesan dari klien
+func (c *Client) readPump() {
+ defer func() {
+ c.Hub.unregister <- c
+ c.Conn.Close()
+ }()
+
+ // Konfigurasi koneksi
+ c.Conn.SetReadLimit(int64(c.Hub.config.MaxMessageSize))
+ c.resetReadDeadline()
+
+ // Setup ping/pong handlers
+ c.Conn.SetPingHandler(func(message string) error {
+ c.resetReadDeadline()
+ return c.Conn.WriteControl(websocket.PongMessage, []byte(message), time.Now().Add(c.Hub.config.WriteTimeout))
+ })
+
+ c.Conn.SetPongHandler(func(message string) error {
+ c.mu.Lock()
+ c.lastPong = time.Now()
+ c.isActive = true
+ c.mu.Unlock()
+ c.resetReadDeadline()
+ return nil
+ })
+
+ for {
+ select {
+ case <-c.ctx.Done():
+ return
+ default:
+ _, message, err := c.Conn.ReadMessage()
+ if err != nil {
+ if websocket.IsUnexpectedCloseError(err,
+ websocket.CloseGoingAway,
+ websocket.CloseAbnormalClosure,
+ websocket.CloseNormalClosure) {
+ c.Hub.errorCount++
+ }
+ return
+ }
+
+ // Reset deadline setiap kali ada pesan masuk
+ c.resetReadDeadline()
+ c.updateLastActivity()
+
+ // Parse pesan
+ var msg WebSocketMessage
+ if err := json.Unmarshal(message, &msg); err != nil {
+ c.sendErrorResponse("Invalid message format", err.Error())
+ continue
+ }
+
+ // Set metadata pesan
+ msg.Timestamp = time.Now()
+ msg.ClientID = c.ID
+ if msg.MessageID == "" {
+ msg.MessageID = uuid.New().String()
+ }
+
+ // Proses pesan menggunakan registry
+ c.handleMessage(msg)
+ }
+ }
+}
+
+// writePump menangani pengiriman pesan ke klien
+func (c *Client) writePump() {
+ ticker := time.NewTicker(c.Hub.config.PingInterval)
+ defer func() {
+ ticker.Stop()
+ c.Conn.Close()
+ }()
+
+ for {
+ select {
+ case message, ok := <-c.Send:
+ c.Conn.SetWriteDeadline(time.Now().Add(c.Hub.config.WriteTimeout))
+ if !ok {
+ c.Conn.WriteMessage(websocket.CloseMessage, []byte{})
+ return
+ }
+
+ if err := c.Conn.WriteJSON(message); err != nil {
+ c.Hub.errorCount++
+ return
+ }
+
+ case <-ticker.C:
+ // Kirim ping dan periksa respons
+ if err := c.sendPing(); err != nil {
+ c.Hub.errorCount++
+ return
+ }
+
+ // Periksa timeout pong
+ if c.isPongTimeout() {
+ return
+ }
+
+ case <-c.ctx.Done():
+ return
+ }
+ }
+}
+
+// handleMessage memproses pesan masuk
+func (c *Client) handleMessage(msg WebSocketMessage) {
+ // Dapatkan handler dari registry
+ handler, exists := c.Hub.messageRegistry.GetHandler(msg.Type)
+ if !exists {
+ // Handler tidak ditemukan, gunakan handler default
+ c.handleDefaultMessage(msg)
+ return
+ }
+
+ // Jalankan handler
+ if err := handler.HandleMessage(c, msg); err != nil {
+ c.sendErrorResponse("Error handling message", err.Error())
+ c.Hub.errorCount++
+ }
+}
+
+// handleDefaultMessage menangani pesan tanpa handler khusus
+func (c *Client) handleDefaultMessage(msg WebSocketMessage) {
+ switch msg.Type {
+ case "broadcast":
+ c.Hub.broadcast <- msg
+ c.sendDirectResponse("broadcast_sent", "Message broadcasted to all clients")
+
+ case "direct_message":
+ c.handleDirectMessage(msg)
+
+ case "ping":
+ c.handlePing(msg)
+
+ case "pong":
+ // Pong sudah ditangani di level koneksi
+ break
+
+ case "heartbeat":
+ c.handleHeartbeat(msg)
+
+ case "connection_test":
+ c.handleConnectionTest(msg)
+
+ case "get_online_users":
+ c.sendOnlineUsers()
+
+ case "join_room":
+ c.handleJoinRoom(msg)
+
+ case "leave_room":
+ c.handleLeaveRoom(msg)
+
+ case "get_room_info":
+ c.handleGetRoomInfo(msg)
+
+ case "database_query", "db_query":
+ c.handleDatabaseQuery(msg)
+
+ case "db_insert":
+ c.handleDatabaseInsert(msg)
+
+ case "db_custom_query":
+ c.handleDatabaseCustomQuery(msg)
+
+ case "get_stats":
+ c.handleGetStats(msg)
+
+ case "get_server_stats":
+ c.handleGetServerStats(msg)
+
+ case "get_system_health":
+ c.handleGetSystemHealth(msg)
+
+ case "admin_kick_client":
+ c.handleAdminKickClient(msg)
+
+ case "admin_kill_server":
+ c.handleAdminKillServer(msg)
+
+ case "admin_clear_logs":
+ c.handleAdminClearLogs(msg)
+
+ default:
+ c.sendDirectResponse("message_received", fmt.Sprintf("Message received: %v", msg.Data))
+ c.Hub.broadcast <- msg
+ }
+}
+
+// Metode helper lainnya...
+func (c *Client) resetReadDeadline() {
+ c.Conn.SetReadDeadline(time.Now().Add(c.Hub.config.ReadTimeout))
+}
+
+func (c *Client) updateLastActivity() {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ c.lastPing = time.Now()
+ c.isActive = true
+}
+
+func (c *Client) sendPing() error {
+ c.Conn.SetWriteDeadline(time.Now().Add(c.Hub.config.WriteTimeout))
+ if err := c.Conn.WriteMessage(websocket.PingMessage, nil); err != nil {
+ return err
+ }
+
+ c.mu.Lock()
+ c.lastPing = time.Now()
+ c.mu.Unlock()
+
+ return nil
+}
+
+func (c *Client) isPongTimeout() bool {
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+
+ lastActivity := c.lastPong
+ if lastActivity.IsZero() {
+ lastActivity = c.lastPing
+ }
+
+ return time.Since(lastActivity) > c.Hub.config.PongTimeout
+}
+
+func (c *Client) isClientActive() bool {
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+ return c.isActive && time.Since(c.lastPing) < c.Hub.config.PongTimeout
+}
+
+func (c *Client) sendDirectResponse(messageType string, data interface{}) {
+ response := NewWebSocketMessage(MessageType(messageType), data, c.ID, c.Room)
+
+ select {
+ case c.Send <- response:
+ default:
+ // Channel penuh, abaikan pesan
+ }
+}
+
+func (c *Client) sendErrorResponse(error, details string) {
+ c.sendDirectResponse("error", map[string]interface{}{
+ "error": error,
+ "details": details,
+ })
+}
+
+func (c *Client) gracefulClose() {
+ c.mu.Lock()
+ c.isActive = false
+ c.mu.Unlock()
+
+ // Kirim pesan close
+ c.Conn.SetWriteDeadline(time.Now().Add(c.Hub.config.WriteTimeout))
+ c.Conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
+
+ // Batalkan context
+ c.cancel()
+}
+
+// ReadPump mengekspos metode readPump untuk handler
+func (c *Client) ReadPump() {
+ c.readPump()
+}
+
+// WritePump mengekspos metode writePump untuk handler
+func (c *Client) WritePump() {
+ c.writePump()
+}
+
+// handleDirectMessage menangani pesan direct message
+func (c *Client) handleDirectMessage(msg WebSocketMessage) {
+ data, ok := msg.Data.(map[string]interface{})
+ if !ok {
+ c.sendErrorResponse("Invalid direct message format", "Data must be an object")
+ return
+ }
+
+ targetClientID, ok := data["target_client_id"].(string)
+ if !ok || targetClientID == "" {
+ c.sendErrorResponse("Invalid target client ID", "target_client_id is required")
+ return
+ }
+
+ message, ok := data["message"].(string)
+ if !ok || message == "" {
+ c.sendErrorResponse("Invalid message content", "message is required")
+ return
+ }
+
+ // Buat pesan direct message
+ directMsg := NewWebSocketMessage(DirectMessage, map[string]interface{}{
+ "from_client_id": c.ID,
+ "from_user_id": c.UserID,
+ "message": message,
+ "timestamp": msg.Timestamp,
+ }, targetClientID, "")
+
+ // Kirim ke target client
+ select {
+ case c.Hub.broadcast <- directMsg:
+ c.sendDirectResponse("direct_message_sent", map[string]interface{}{
+ "target_client_id": targetClientID,
+ "message": message,
+ })
+ default:
+ c.sendErrorResponse("Failed to send direct message", "Message queue is full")
+ }
+}
+
+// handlePing menangani ping message
+func (c *Client) handlePing(msg WebSocketMessage) {
+ // Kirim pong response
+ pongMsg := NewWebSocketMessage(PongMessage, map[string]interface{}{
+ "timestamp": msg.Timestamp.Unix(),
+ "client_id": c.ID,
+ }, c.ID, "")
+
+ select {
+ case c.Send <- pongMsg:
+ default:
+ // Channel penuh, abaikan
+ }
+}
+
+// handleHeartbeat menangani heartbeat message
+func (c *Client) handleHeartbeat(msg WebSocketMessage) {
+ // Kirim heartbeat acknowledgment
+ heartbeatAck := NewWebSocketMessage(MessageType("heartbeat_ack"), map[string]interface{}{
+ "timestamp": time.Now().Unix(),
+ "client_uptime": time.Since(c.connectedAt).Seconds(),
+ "server_uptime": time.Since(c.Hub.startTime).Seconds(),
+ "client_id": c.ID,
+ }, c.ID, "")
+
+ select {
+ case c.Send <- heartbeatAck:
+ default:
+ // Channel penuh, abaikan
+ }
+}
+
+// handleConnectionTest menangani connection test
+func (c *Client) handleConnectionTest(msg WebSocketMessage) {
+ // Kirim connection test result
+ testResult := NewWebSocketMessage(MessageType("connection_test_result"), map[string]interface{}{
+ "timestamp": time.Now().Unix(),
+ "client_id": c.ID,
+ "connection_status": "healthy",
+ "latency_ms": 0, // Could be calculated if ping timestamp is provided
+ "uptime_seconds": time.Since(c.connectedAt).Seconds(),
+ }, c.ID, "")
+
+ select {
+ case c.Send <- testResult:
+ default:
+ // Channel penuh, abaikan
+ }
+}
+
+// handleJoinRoom menangani join room
+func (c *Client) handleJoinRoom(msg WebSocketMessage) {
+ data, ok := msg.Data.(map[string]interface{})
+ if !ok {
+ c.sendErrorResponse("Invalid join room format", "Data must be an object")
+ return
+ }
+
+ roomName, ok := data["room"].(string)
+ if !ok || roomName == "" {
+ c.sendErrorResponse("Invalid room name", "room is required")
+ return
+ }
+
+ // Update client room
+ oldRoom := c.Room
+ c.Room = roomName
+
+ // Update hub room mapping
+ c.Hub.mu.Lock()
+ if oldRoom != "" {
+ if roomClients, exists := c.Hub.rooms[oldRoom]; exists {
+ delete(roomClients, c)
+ if len(roomClients) == 0 {
+ delete(c.Hub.rooms, oldRoom)
+ }
+ }
+ }
+
+ if c.Hub.rooms[roomName] == nil {
+ c.Hub.rooms[roomName] = make(map[*Client]bool)
+ }
+ c.Hub.rooms[roomName][c] = true
+ c.Hub.mu.Unlock()
+
+ // Log activity
+ c.Hub.logActivity("client_join_room", c.ID, fmt.Sprintf("Room: %s", roomName))
+
+ // Kirim response
+ c.sendDirectResponse("room_joined", map[string]interface{}{
+ "room": roomName,
+ "previous_room": oldRoom,
+ })
+}
+
+// handleLeaveRoom menangani leave room
+func (c *Client) handleLeaveRoom(msg WebSocketMessage) {
+ oldRoom := c.Room
+
+ if oldRoom == "" {
+ c.sendErrorResponse("Not in any room", "Client is not currently in a room")
+ return
+ }
+
+ // Update hub room mapping
+ c.Hub.mu.Lock()
+ if roomClients, exists := c.Hub.rooms[oldRoom]; exists {
+ delete(roomClients, c)
+ if len(roomClients) == 0 {
+ delete(c.Hub.rooms, oldRoom)
+ }
+ }
+ c.Hub.mu.Unlock()
+
+ // Clear client room
+ c.Room = ""
+
+ // Log activity
+ c.Hub.logActivity("client_leave_room", c.ID, fmt.Sprintf("Room: %s", oldRoom))
+
+ // Kirim response
+ c.sendDirectResponse("room_left", map[string]interface{}{
+ "room": oldRoom,
+ })
+}
+
+// handleGetRoomInfo menangani get room info
+func (c *Client) handleGetRoomInfo(msg WebSocketMessage) {
+ c.Hub.mu.RLock()
+ defer c.Hub.mu.RUnlock()
+
+ roomInfo := make(map[string]interface{})
+
+ // Info ruangan saat ini
+ if c.Room != "" {
+ if roomClients, exists := c.Hub.rooms[c.Room]; exists {
+ clientIDs := make([]string, 0, len(roomClients))
+ for client := range roomClients {
+ clientIDs = append(clientIDs, client.ID)
+ }
+ roomInfo["current_room"] = map[string]interface{}{
+ "name": c.Room,
+ "client_count": len(roomClients),
+ "clients": clientIDs,
+ }
+ }
+ }
+
+ // Info semua ruangan
+ allRooms := make(map[string]int)
+ for roomName, clients := range c.Hub.rooms {
+ allRooms[roomName] = len(clients)
+ }
+ roomInfo["all_rooms"] = allRooms
+ roomInfo["total_rooms"] = len(c.Hub.rooms)
+
+ c.sendDirectResponse("room_info", roomInfo)
+}
+
+// handleDatabaseInsert menangani database insert
+func (c *Client) handleDatabaseInsert(msg WebSocketMessage) {
+ data, ok := msg.Data.(map[string]interface{})
+ if !ok {
+ c.sendErrorResponse("Invalid database insert format", "Data must be an object")
+ return
+ }
+
+ table, ok := data["table"].(string)
+ if !ok || table == "" {
+ c.sendErrorResponse("Invalid table name", "table is required")
+ return
+ }
+
+ insertData, ok := data["data"].(map[string]interface{})
+ if !ok {
+ c.sendErrorResponse("Invalid insert data", "data must be an object")
+ return
+ }
+
+ // For now, just acknowledge the insert request
+ // In a real implementation, you would perform the actual database insert
+ c.sendDirectResponse("db_insert_result", map[string]interface{}{
+ "table": table,
+ "status": "acknowledged",
+ "message": "Insert request received (not implemented)",
+ "data": insertData, // Use the variable to avoid unused error
+ })
+}
+
+// handleDatabaseCustomQuery menangani custom database query
+func (c *Client) handleDatabaseCustomQuery(msg WebSocketMessage) {
+ data, ok := msg.Data.(map[string]interface{})
+ if !ok {
+ c.sendErrorResponse("Invalid database query format", "Data must be an object")
+ return
+ }
+
+ database, ok := data["database"].(string)
+ if !ok || database == "" {
+ database = "default"
+ }
+
+ query, ok := data["query"].(string)
+ if !ok || query == "" {
+ c.sendErrorResponse("Invalid query", "query is required")
+ return
+ }
+
+ // For now, just acknowledge the query request
+ // In a real implementation, you would execute the query
+ c.sendDirectResponse("db_query_result", map[string]interface{}{
+ "database": database,
+ "query": query,
+ "status": "acknowledged",
+ "message": "Query request received (not implemented)",
+ })
+}
+
+// handleGetStats menangani get stats
+func (c *Client) handleGetStats(msg WebSocketMessage) {
+ stats := c.Hub.GetStats()
+ c.sendDirectResponse("stats", stats)
+}
+
+// handleGetServerStats menangani get server stats
+func (c *Client) handleGetServerStats(msg WebSocketMessage) {
+ // Create monitoring manager instance
+ monitoringManager := NewMonitoringManager(c.Hub)
+ detailedStats := monitoringManager.GetDetailedStats()
+ c.sendDirectResponse("server_stats", detailedStats)
+}
+
+// handleGetSystemHealth menangani get system health
+func (c *Client) handleGetSystemHealth(msg WebSocketMessage) {
+ systemHealth := make(map[string]interface{})
+ if c.Hub.dbService != nil {
+ systemHealth["databases"] = c.Hub.dbService.Health()
+ systemHealth["available_dbs"] = c.Hub.dbService.ListDBs()
+ }
+ systemHealth["websocket_status"] = "healthy"
+ systemHealth["uptime_seconds"] = time.Since(c.Hub.startTime).Seconds()
+
+ c.sendDirectResponse("system_health", systemHealth)
+}
+
+// handleAdminKickClient menangani admin kick client
+func (c *Client) handleAdminKickClient(msg WebSocketMessage) {
+ // This should be protected by authentication, but for now just acknowledge
+ data, ok := msg.Data.(map[string]interface{})
+ if !ok {
+ c.sendErrorResponse("Invalid admin command format", "Data must be an object")
+ return
+ }
+
+ targetClientID, ok := data["client_id"].(string)
+ if !ok || targetClientID == "" {
+ c.sendErrorResponse("Invalid target client ID", "client_id is required")
+ return
+ }
+
+ // For now, just acknowledge the kick request
+ // In a real implementation, you would check admin permissions and kick the client
+ c.sendDirectResponse("admin_command_result", map[string]interface{}{
+ "command": "kick_client",
+ "target_client_id": targetClientID,
+ "status": "acknowledged",
+ "message": "Kick request received (not implemented)",
+ })
+}
+
+// handleAdminKillServer menangani admin kill server
+func (c *Client) handleAdminKillServer(msg WebSocketMessage) {
+ // This should be protected by authentication, but for now just acknowledge
+ c.sendDirectResponse("admin_command_result", map[string]interface{}{
+ "command": "kill_server",
+ "status": "acknowledged",
+ "message": "Kill server request received (not implemented - would require admin auth)",
+ })
+}
+
+// handleAdminClearLogs menangani admin clear logs
+func (c *Client) handleAdminClearLogs(msg WebSocketMessage) {
+ // This should be protected by authentication, but for now just acknowledge
+ c.sendDirectResponse("admin_command_result", map[string]interface{}{
+ "command": "clear_logs",
+ "status": "acknowledged",
+ "message": "Clear logs request received (not implemented - would require admin auth)",
+ })
+}
+
+// Implementasi metode lainnya...
+func (c *Client) handleDatabaseQuery(msg WebSocketMessage) {
+ // Implementasi yang sama seperti sebelumnya
+ data, ok := msg.Data.(map[string]interface{})
+ if !ok {
+ c.sendErrorResponse("Invalid database query format", "Data must be an object")
+ return
+ }
+
+ table, ok := data["table"].(string)
+ if !ok || table == "" {
+ c.sendErrorResponse("Invalid table name", "table is required")
+ return
+ }
+
+ // For now, just acknowledge the query request
+ c.sendDirectResponse("db_query_result", map[string]interface{}{
+ "table": table,
+ "status": "acknowledged",
+ "message": "Query request received (not implemented)",
+ })
+}
+
+func (c *Client) sendOnlineUsers() {
+ c.Hub.mu.RLock()
+ defer c.Hub.mu.RUnlock()
+
+ users := make([]map[string]interface{}, 0, len(c.Hub.clients))
+ for client := range c.Hub.clients {
+ user := map[string]interface{}{
+ "id": client.ID,
+ "static_id": client.StaticID,
+ "user_id": client.UserID,
+ "room": client.Room,
+ "ip_address": client.IPAddress,
+ "connected_at": client.connectedAt,
+ "last_ping": client.lastPing,
+ "last_pong": client.lastPong,
+ "is_active": client.isClientActive(),
+ }
+ users = append(users, user)
+ }
+
+ response := NewWebSocketMessage(OnlineUsersMessage, map[string]interface{}{
+ "users": users,
+ "count": len(users),
+ }, c.ID, "")
+
+ select {
+ case c.Send <- response:
+ default:
+ // Channel penuh, abaikan
+ }
+}
diff --git a/internal/services/websocket/handlers.go b/internal/services/websocket/handlers.go
new file mode 100644
index 0000000..62051bd
--- /dev/null
+++ b/internal/services/websocket/handlers.go
@@ -0,0 +1,621 @@
+package websocket
+
+import (
+ "context"
+ "fmt"
+ "strings"
+ "time"
+)
+
+// DatabaseHandler menangani operasi database
+type DatabaseHandler struct {
+ hub *Hub
+}
+
+func NewDatabaseHandler(hub *Hub) *DatabaseHandler {
+ return &DatabaseHandler{hub: hub}
+}
+
+func (h *DatabaseHandler) HandleMessage(client *Client, message WebSocketMessage) error {
+ switch message.Type {
+ case DatabaseInsertMessage:
+ return h.handleDatabaseInsert(client, message)
+ case DatabaseQueryMessage:
+ return h.handleDatabaseQuery(client, message)
+ case DatabaseCustomQueryMessage:
+ return h.handleDatabaseCustomQuery(client, message)
+ default:
+ return fmt.Errorf("unsupported database message type: %s", message.Type)
+ }
+}
+
+func (h *DatabaseHandler) MessageType() MessageType {
+ return DatabaseInsertMessage // Primary type for registration
+}
+
+func (h *DatabaseHandler) handleDatabaseInsert(client *Client, message WebSocketMessage) error {
+ data, ok := message.Data.(map[string]interface{})
+ if !ok {
+ client.sendErrorResponse("Invalid database insert format", "Data must be an object")
+ return nil
+ }
+
+ table, ok := data["table"].(string)
+ if !ok || table == "" {
+ client.sendErrorResponse("Invalid table name", "table is required")
+ return nil
+ }
+
+ insertData, ok := data["data"].(map[string]interface{})
+ if !ok {
+ client.sendErrorResponse("Invalid insert data", "data must be an object")
+ return nil
+ }
+
+ // Perform actual database insert
+ if h.hub.dbService != nil {
+ // Get database connection
+ db, err := h.hub.GetDatabaseConnection("postgres_satudata")
+ if err != nil {
+ client.sendErrorResponse("Database connection error", err.Error())
+ return nil
+ }
+
+ // Build insert query
+ columns := make([]string, 0, len(insertData))
+ values := make([]interface{}, 0, len(insertData))
+ placeholders := make([]string, 0, len(insertData))
+
+ i := 1
+ for col, val := range insertData {
+ columns = append(columns, col)
+ values = append(values, val)
+ placeholders = append(placeholders, fmt.Sprintf("$%d", i))
+ i++
+ }
+
+ query := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)",
+ table,
+ strings.Join(columns, ", "),
+ strings.Join(placeholders, ", "))
+
+ // Execute insert
+ ctx, cancel := context.WithTimeout(client.ctx, 30*time.Second)
+ defer cancel()
+
+ result, err := db.ExecContext(ctx, query, values...)
+ if err != nil {
+ client.sendErrorResponse("Database insert error", err.Error())
+ return nil
+ }
+
+ rowsAffected, _ := result.RowsAffected()
+ client.sendDirectResponse("db_insert_result", map[string]interface{}{
+ "table": table,
+ "status": "success",
+ "rows_affected": rowsAffected,
+ "message": "Data inserted successfully",
+ })
+ } else {
+ client.sendErrorResponse("Database service not available", "Database service is not initialized")
+ }
+
+ return nil
+}
+
+func (h *DatabaseHandler) handleDatabaseQuery(client *Client, message WebSocketMessage) error {
+ data, ok := message.Data.(map[string]interface{})
+ if !ok {
+ client.sendErrorResponse("Invalid database query format", "Data must be an object")
+ return nil
+ }
+
+ table, ok := data["table"].(string)
+ if !ok || table == "" {
+ client.sendErrorResponse("Invalid table name", "table is required")
+ return nil
+ }
+
+ // Execute query
+ results, err := h.hub.ExecuteDatabaseQuery("postgres_satudata", fmt.Sprintf("SELECT * FROM %s LIMIT 100", table))
+ if err != nil {
+ client.sendErrorResponse("Database query error", err.Error())
+ return nil
+ }
+
+ client.sendDirectResponse("db_query_result", map[string]interface{}{
+ "table": table,
+ "status": "success",
+ "results": results,
+ "count": len(results),
+ })
+
+ return nil
+}
+
+func (h *DatabaseHandler) handleDatabaseCustomQuery(client *Client, message WebSocketMessage) error {
+ data, ok := message.Data.(map[string]interface{})
+ if !ok {
+ client.sendErrorResponse("Invalid database query format", "Data must be an object")
+ return nil
+ }
+
+ database, ok := data["database"].(string)
+ if !ok || database == "" {
+ database = "postgres_satudata"
+ }
+
+ query, ok := data["query"].(string)
+ if !ok || query == "" {
+ client.sendErrorResponse("Invalid query", "query is required")
+ return nil
+ }
+
+ // Execute custom query
+ results, err := h.hub.ExecuteDatabaseQuery(database, query)
+ if err != nil {
+ client.sendErrorResponse("Database query error", err.Error())
+ return nil
+ }
+
+ client.sendDirectResponse("db_query_result", map[string]interface{}{
+ "database": database,
+ "query": query,
+ "status": "success",
+ "results": results,
+ "count": len(results),
+ })
+
+ return nil
+}
+
+// AdminHandler menangani operasi admin
+type AdminHandler struct {
+ hub *Hub
+}
+
+func NewAdminHandler(hub *Hub) *AdminHandler {
+ return &AdminHandler{hub: hub}
+}
+
+func (h *AdminHandler) HandleMessage(client *Client, message WebSocketMessage) error {
+ switch message.Type {
+ case AdminKickClientMessage:
+ return h.handleAdminKickClient(client, message)
+ case AdminKillServerMessage:
+ return h.handleAdminKillServer(client, message)
+ case AdminClearLogsMessage:
+ return h.handleAdminClearLogs(client, message)
+ default:
+ return fmt.Errorf("unsupported admin message type: %s", message.Type)
+ }
+}
+
+func (h *AdminHandler) MessageType() MessageType {
+ return AdminKickClientMessage // Primary type for registration
+}
+
+func (h *AdminHandler) handleAdminKickClient(client *Client, message WebSocketMessage) error {
+ data, ok := message.Data.(map[string]interface{})
+ if !ok {
+ client.sendErrorResponse("Invalid admin command format", "Data must be an object")
+ return nil
+ }
+
+ targetClientID, ok := data["client_id"].(string)
+ if !ok || targetClientID == "" {
+ client.sendErrorResponse("Invalid target client ID", "client_id is required")
+ return nil
+ }
+
+ // Check if target client exists
+ h.hub.mu.RLock()
+ targetClient, exists := h.hub.clientsByID[targetClientID]
+ h.hub.mu.RUnlock()
+
+ if !exists {
+ client.sendErrorResponse("Client not found", fmt.Sprintf("Client %s not found", targetClientID))
+ return nil
+ }
+
+ // Log activity
+ h.hub.logActivity("admin_kick_client", client.ID, fmt.Sprintf("Kicked client: %s", targetClientID))
+
+ // Disconnect the target client
+ targetClient.cancel()
+ targetClient.Conn.Close()
+
+ client.sendDirectResponse("admin_command_result", map[string]interface{}{
+ "command": "kick_client",
+ "target_client_id": targetClientID,
+ "status": "success",
+ "message": "Client kicked successfully",
+ })
+
+ return nil
+}
+
+func (h *AdminHandler) handleAdminKillServer(client *Client, message WebSocketMessage) error {
+ // Log activity
+ h.hub.logActivity("admin_kill_server", client.ID, "Server kill signal received")
+
+ // For testing purposes, just acknowledge (don't actually kill server)
+ client.sendDirectResponse("admin_command_result", map[string]interface{}{
+ "command": "kill_server",
+ "status": "acknowledged",
+ "message": "Kill server signal received (test mode - server not actually killed)",
+ })
+
+ return nil
+}
+
+func (h *AdminHandler) handleAdminClearLogs(client *Client, message WebSocketMessage) error {
+ // Clear activity logs
+ h.hub.activityMu.Lock()
+ h.hub.activityLog = make([]ActivityLog, 0, h.hub.config.ActivityLogSize)
+ h.hub.activityMu.Unlock()
+
+ // Log the clear action
+ h.hub.logActivity("admin_clear_logs", client.ID, "Activity logs cleared")
+
+ client.sendDirectResponse("admin_command_result", map[string]interface{}{
+ "command": "clear_logs",
+ "status": "success",
+ "message": "Server logs cleared successfully",
+ })
+
+ return nil
+}
+
+// RoomHandler menangani operasi ruangan
+type RoomHandler struct {
+ hub *Hub
+}
+
+func NewRoomHandler(hub *Hub) *RoomHandler {
+ return &RoomHandler{hub: hub}
+}
+
+func (h *RoomHandler) HandleMessage(client *Client, message WebSocketMessage) error {
+ switch message.Type {
+ case JoinRoomMessage:
+ return h.handleJoinRoom(client, message)
+ case LeaveRoomMessage:
+ return h.handleLeaveRoom(client, message)
+ case GetRoomInfoMessage:
+ return h.handleGetRoomInfo(client, message)
+ default:
+ return fmt.Errorf("unsupported room message type: %s", message.Type)
+ }
+}
+
+func (h *RoomHandler) MessageType() MessageType {
+ return JoinRoomMessage // Primary type for registration
+}
+
+func (h *RoomHandler) handleJoinRoom(client *Client, message WebSocketMessage) error {
+ data, ok := message.Data.(map[string]interface{})
+ if !ok {
+ client.sendErrorResponse("Invalid join room format", "Data must be an object")
+ return nil
+ }
+
+ roomName, ok := data["room"].(string)
+ if !ok || roomName == "" {
+ client.sendErrorResponse("Invalid room name", "room is required")
+ return nil
+ }
+
+ // Update client room
+ oldRoom := client.Room
+ client.Room = roomName
+
+ // Update hub room mapping
+ h.hub.mu.Lock()
+ if oldRoom != "" {
+ if roomClients, exists := h.hub.rooms[oldRoom]; exists {
+ delete(roomClients, client)
+ if len(roomClients) == 0 {
+ delete(h.hub.rooms, oldRoom)
+ }
+ }
+ }
+
+ if h.hub.rooms[roomName] == nil {
+ h.hub.rooms[roomName] = make(map[*Client]bool)
+ }
+ h.hub.rooms[roomName][client] = true
+ h.hub.mu.Unlock()
+
+ // Log activity
+ h.hub.logActivity("client_join_room", client.ID, fmt.Sprintf("Room: %s", roomName))
+
+ // Notify other clients in the room
+ h.hub.broadcaster.BroadcastServerToRoom(roomName, "user_joined_room", map[string]interface{}{
+ "client_id": client.ID,
+ "user_id": client.UserID,
+ "room": roomName,
+ "joined_at": time.Now().Unix(),
+ })
+
+ // Send response
+ client.sendDirectResponse("room_joined", map[string]interface{}{
+ "room": roomName,
+ "previous_room": oldRoom,
+ })
+
+ return nil
+}
+
+func (h *RoomHandler) handleLeaveRoom(client *Client, message WebSocketMessage) error {
+ oldRoom := client.Room
+
+ if oldRoom == "" {
+ client.sendErrorResponse("Not in any room", "Client is not currently in a room")
+ return nil
+ }
+
+ // Update hub room mapping
+ h.hub.mu.Lock()
+ if roomClients, exists := h.hub.rooms[oldRoom]; exists {
+ delete(roomClients, client)
+ if len(roomClients) == 0 {
+ delete(h.hub.rooms, oldRoom)
+ }
+ }
+ h.hub.mu.Unlock()
+
+ // Clear client room
+ client.Room = ""
+
+ // Log activity
+ h.hub.logActivity("client_leave_room", client.ID, fmt.Sprintf("Room: %s", oldRoom))
+
+ // Notify other clients in the room
+ h.hub.broadcaster.BroadcastServerToRoom(oldRoom, "user_left_room", map[string]interface{}{
+ "client_id": client.ID,
+ "user_id": client.UserID,
+ "room": oldRoom,
+ "left_at": time.Now().Unix(),
+ })
+
+ // Send response
+ client.sendDirectResponse("room_left", map[string]interface{}{
+ "room": oldRoom,
+ })
+
+ return nil
+}
+
+func (h *RoomHandler) handleGetRoomInfo(client *Client, message WebSocketMessage) error {
+ h.hub.mu.RLock()
+ defer h.hub.mu.RUnlock()
+
+ roomInfo := make(map[string]interface{})
+
+ // Info ruangan saat ini
+ if client.Room != "" {
+ if roomClients, exists := h.hub.rooms[client.Room]; exists {
+ clientIDs := make([]string, 0, len(roomClients))
+ for client := range roomClients {
+ clientIDs = append(clientIDs, client.ID)
+ }
+ roomInfo["current_room"] = map[string]interface{}{
+ "name": client.Room,
+ "client_count": len(roomClients),
+ "clients": clientIDs,
+ }
+ }
+ }
+
+ // Info semua ruangan
+ allRooms := make(map[string]int)
+ for roomName, clients := range h.hub.rooms {
+ allRooms[roomName] = len(clients)
+ }
+ roomInfo["all_rooms"] = allRooms
+ roomInfo["total_rooms"] = len(h.hub.rooms)
+
+ client.sendDirectResponse("room_info", roomInfo)
+
+ return nil
+}
+
+// MonitoringHandler menangani operasi monitoring
+type MonitoringHandler struct {
+ hub *Hub
+}
+
+func NewMonitoringHandler(hub *Hub) *MonitoringHandler {
+ return &MonitoringHandler{hub: hub}
+}
+
+func (h *MonitoringHandler) HandleMessage(client *Client, message WebSocketMessage) error {
+ switch message.Type {
+ case GetStatsMessage:
+ return h.handleGetStats(client, message)
+ case GetServerStatsMessage:
+ return h.handleGetServerStats(client, message)
+ case GetSystemHealthMessage:
+ return h.handleGetSystemHealth(client, message)
+ default:
+ return fmt.Errorf("unsupported monitoring message type: %s", message.Type)
+ }
+}
+
+func (h *MonitoringHandler) MessageType() MessageType {
+ return GetStatsMessage // Primary type for registration
+}
+
+func (h *MonitoringHandler) handleGetStats(client *Client, message WebSocketMessage) error {
+ stats := h.hub.GetStats()
+ client.sendDirectResponse("stats", stats)
+ return nil
+}
+
+func (h *MonitoringHandler) handleGetServerStats(client *Client, message WebSocketMessage) error {
+ // Create monitoring manager instance
+ monitoringManager := NewMonitoringManager(h.hub)
+ detailedStats := monitoringManager.GetDetailedStats()
+ client.sendDirectResponse("server_stats", detailedStats)
+ return nil
+}
+
+func (h *MonitoringHandler) handleGetSystemHealth(client *Client, message WebSocketMessage) error {
+ systemHealth := make(map[string]interface{})
+ if h.hub.dbService != nil {
+ systemHealth["databases"] = h.hub.dbService.Health()
+ systemHealth["available_dbs"] = h.hub.dbService.ListDBs()
+ }
+ systemHealth["websocket_status"] = "healthy"
+ systemHealth["uptime_seconds"] = time.Since(h.hub.startTime).Seconds()
+
+ client.sendDirectResponse("system_health", systemHealth)
+ return nil
+}
+
+// ConnectionHandler menangani operasi koneksi
+type ConnectionHandler struct {
+ hub *Hub
+}
+
+func NewConnectionHandler(hub *Hub) *ConnectionHandler {
+ return &ConnectionHandler{hub: hub}
+}
+
+func (h *ConnectionHandler) HandleMessage(client *Client, message WebSocketMessage) error {
+ switch message.Type {
+ case PingMessage:
+ return h.handlePing(client, message)
+ case PongMessage:
+ return h.handlePong(client, message)
+ case HeartbeatMessage:
+ return h.handleHeartbeat(client, message)
+ case ConnectionTestMessage:
+ return h.handleConnectionTest(client, message)
+ case OnlineUsersMessage:
+ return h.handleGetOnlineUsers(client, message)
+ default:
+ return fmt.Errorf("unsupported connection message type: %s", message.Type)
+ }
+}
+
+func (h *ConnectionHandler) MessageType() MessageType {
+ return PingMessage // Primary type for registration
+}
+
+func (h *ConnectionHandler) handlePing(client *Client, message WebSocketMessage) error {
+ // Send pong response
+ pongMsg := NewWebSocketMessage(PongMessage, map[string]interface{}{
+ "timestamp": message.Timestamp.Unix(),
+ "client_id": client.ID,
+ }, client.ID, "")
+
+ select {
+ case client.Send <- pongMsg:
+ default:
+ // Channel penuh, abaikan
+ }
+
+ return nil
+}
+
+func (h *ConnectionHandler) handlePong(client *Client, message WebSocketMessage) error {
+ // Pong sudah ditangani di level koneksi, tapi kita bisa log aktivitas
+ h.hub.logActivity("pong_received", client.ID, "Pong message received")
+ return nil
+}
+
+func (h *ConnectionHandler) handleHeartbeat(client *Client, message WebSocketMessage) error {
+ // Send heartbeat acknowledgment
+ heartbeatAck := NewWebSocketMessage(MessageType("heartbeat_ack"), map[string]interface{}{
+ "timestamp": time.Now().Unix(),
+ "client_uptime": time.Since(client.connectedAt).Seconds(),
+ "server_uptime": time.Since(h.hub.startTime).Seconds(),
+ "client_id": client.ID,
+ }, client.ID, "")
+
+ select {
+ case client.Send <- heartbeatAck:
+ default:
+ // Channel penuh, abaikan
+ }
+
+ return nil
+}
+
+func (h *ConnectionHandler) handleConnectionTest(client *Client, message WebSocketMessage) error {
+ // Send connection test result
+ testResult := NewWebSocketMessage(MessageType("connection_test_result"), map[string]interface{}{
+ "timestamp": time.Now().Unix(),
+ "client_id": client.ID,
+ "connection_status": "healthy",
+ "latency_ms": 0, // Could be calculated if ping timestamp is provided
+ "uptime_seconds": time.Since(client.connectedAt).Seconds(),
+ }, client.ID, "")
+
+ select {
+ case client.Send <- testResult:
+ default:
+ // Channel penuh, abaikan
+ }
+
+ return nil
+}
+
+func (h *ConnectionHandler) handleGetOnlineUsers(client *Client, message WebSocketMessage) error {
+ h.hub.mu.RLock()
+ defer h.hub.mu.RUnlock()
+
+ users := make([]map[string]interface{}, 0, len(h.hub.clients))
+ for client := range h.hub.clients {
+ user := map[string]interface{}{
+ "id": client.ID,
+ "static_id": client.StaticID,
+ "user_id": client.UserID,
+ "room": client.Room,
+ "ip_address": client.IPAddress,
+ "connected_at": client.connectedAt,
+ "last_ping": client.lastPing,
+ "last_pong": client.lastPong,
+ "is_active": client.isClientActive(),
+ }
+ users = append(users, user)
+ }
+
+ response := NewWebSocketMessage(OnlineUsersMessage, map[string]interface{}{
+ "users": users,
+ "count": len(users),
+ }, client.ID, "")
+
+ select {
+ case client.Send <- response:
+ default:
+ // Channel penuh, abaikan
+ }
+
+ return nil
+}
+
+// SetupDefaultHandlers sets up all default message handlers
+func SetupDefaultHandlers(registry *MessageRegistry, hub *Hub) {
+ // Register database handler
+ dbHandler := NewDatabaseHandler(hub)
+ registry.RegisterHandler(dbHandler)
+
+ // Register admin handler
+ adminHandler := NewAdminHandler(hub)
+ registry.RegisterHandler(adminHandler)
+
+ // Register room handler
+ roomHandler := NewRoomHandler(hub)
+ registry.RegisterHandler(roomHandler)
+
+ // Register monitoring handler
+ monitoringHandler := NewMonitoringHandler(hub)
+ registry.RegisterHandler(monitoringHandler)
+
+ // Register connection handler
+ connectionHandler := NewConnectionHandler(hub)
+ registry.RegisterHandler(connectionHandler)
+}
diff --git a/internal/services/websocket/hub.go b/internal/services/websocket/hub.go
new file mode 100644
index 0000000..95c01a9
--- /dev/null
+++ b/internal/services/websocket/hub.go
@@ -0,0 +1,471 @@
+package websocket
+
+import (
+ "api-service/internal/config"
+ "api-service/internal/database"
+ "context"
+ "database/sql"
+ "encoding/json"
+ "fmt"
+ "sync"
+ "time"
+)
+
+// Hub mengelola semua klien WebSocket
+type Hub struct {
+ // Konfigurasi
+ config config.WebSocketConfig
+
+ // Klien
+ clients map[*Client]bool
+ clientsByID map[string]*Client
+ clientsByIP map[string][]*Client
+ clientsByStatic map[string]*Client
+
+ // Ruangan
+ rooms map[string]map[*Client]bool
+
+ // Channel komunikasi
+ broadcast chan WebSocketMessage
+ register chan *Client
+ unregister chan *Client
+ messageQueue chan WebSocketMessage
+
+ // Sinkronisasi
+ mu sync.RWMutex
+
+ // Context
+ ctx context.Context
+ cancel context.CancelFunc
+
+ // Layanan eksternal
+ dbService database.Service
+
+ // Monitoring
+ startTime time.Time
+ messageCount int64
+ errorCount int64
+ activityLog []ActivityLog
+ activityMu sync.RWMutex
+
+ // Registry handler pesan
+ messageRegistry *MessageRegistry
+ broadcaster *Broadcaster
+}
+
+// ActivityLog menyimpan log aktivitas
+type ActivityLog struct {
+ Timestamp time.Time `json:"timestamp"`
+ Event string `json:"event"`
+ ClientID string `json:"client_id"`
+ Details string `json:"details"`
+}
+
+// DatabaseService mendefinisikan interface untuk layanan database
+type DatabaseService interface {
+ Health() map[string]interface{}
+ ListDBs() []string
+ ListenForChanges(ctx context.Context, dbName string, channels []string, callback func(channel, payload string)) error
+ NotifyChange(dbName, channel, payload string) error
+ GetDB(name string) (*sql.DB, error)
+ GetPrimaryDB(name string) (*sql.DB, error)
+}
+
+// Global database service instance
+var (
+ dbService database.Service
+ once sync.Once
+)
+
+// Initialize the database connection
+func init() {
+ once.Do(func() {
+ dbService = database.New(config.LoadConfig())
+ if dbService == nil {
+ panic("Failed to initialize database connection")
+ }
+ })
+}
+
+// NewHub membuat hub baru dengan konfigurasi yang diberikan
+func NewHub(config config.WebSocketConfig) *Hub {
+ ctx, cancel := context.WithCancel(context.Background())
+
+ hub := &Hub{
+
+ config: config,
+ clients: make(map[*Client]bool),
+ clientsByID: make(map[string]*Client),
+ clientsByIP: make(map[string][]*Client),
+ clientsByStatic: make(map[string]*Client),
+ rooms: make(map[string]map[*Client]bool),
+ broadcast: make(chan WebSocketMessage, 1000),
+ register: make(chan *Client),
+ unregister: make(chan *Client),
+ messageQueue: make(chan WebSocketMessage, config.MessageQueueSize),
+ ctx: ctx,
+ cancel: cancel,
+ dbService: dbService,
+ startTime: time.Now(),
+ activityLog: make([]ActivityLog, 0, config.ActivityLogSize),
+ messageRegistry: NewMessageRegistry(),
+ }
+
+ // Setup default message handlers
+ // SetupDefaultHandlers(hub.messageRegistry)
+
+ // Setup database change listeners
+ hub.setupDatabaseListeners()
+
+ return hub
+}
+
+// Run menjalankan loop utama hub
+func (h *Hub) Run() {
+ // Start queue workers
+ for i := 0; i < h.config.QueueWorkers; i++ {
+ go h.queueWorker(i)
+ }
+
+ for {
+ select {
+ case client := <-h.register:
+ h.registerClient(client)
+
+ case client := <-h.unregister:
+ h.unregisterClient(client)
+
+ case message := <-h.broadcast:
+ h.messageCount++
+ h.broadcastToClients(message)
+
+ case <-h.ctx.Done():
+ return
+ }
+ }
+}
+
+// queueWorker memproses pesan dari antrian
+func (h *Hub) queueWorker(workerID int) {
+ for {
+ select {
+ case message := <-h.messageQueue:
+ h.broadcast <- message
+ case <-h.ctx.Done():
+ return
+ }
+ }
+}
+
+// registerClient mendaftarkan klien baru
+func (h *Hub) registerClient(client *Client) {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ // Register di peta klien utama
+ h.clients[client] = true
+
+ // Register berdasarkan ID
+ h.clientsByID[client.ID] = client
+
+ // Register berdasarkan ID statis
+ if client.StaticID != "" {
+ h.clientsByStatic[client.StaticID] = client
+ }
+
+ // Register berdasarkan IP
+ if h.clientsByIP[client.IPAddress] == nil {
+ h.clientsByIP[client.IPAddress] = make([]*Client, 0)
+ }
+ h.clientsByIP[client.IPAddress] = append(h.clientsByIP[client.IPAddress], client)
+
+ // Register di ruangan
+ if client.Room != "" {
+ if h.rooms[client.Room] == nil {
+ h.rooms[client.Room] = make(map[*Client]bool)
+ }
+ h.rooms[client.Room][client] = true
+ }
+
+ // Log aktivitas
+ h.logActivity("client_connected", client.ID,
+ fmt.Sprintf("IP: %s, Static: %s, Room: %s", client.IPAddress, client.StaticID, client.Room))
+
+ // --- MODIFIED: Send a detailed welcome message to the new client ---
+
+ // Determine the type of ID for the client's information
+ idType := "generated" // Default type
+ if client.StaticID != "" {
+ idType = "static"
+ } else if client.UserID != "" {
+ idType = "user"
+ }
+
+ welcomeMsg := NewWebSocketMessage(WelcomeMessage, map[string]interface{}{
+ "message": "Welcome to the WebSocket server!",
+ "client_id": client.ID,
+ "static_id": client.StaticID,
+ "user_id": client.UserID,
+ "ip_address": client.IPAddress,
+ "room": client.Room,
+ "id_type": idType, // "generated", "static", or "user"
+ }, client.ID, "")
+
+ select {
+ case client.Send <- welcomeMsg:
+ // Message sent successfully
+ default:
+ // Channel is full, unlikely for a new client
+ }
+}
+
+// unregisterClient menghapus klien
+func (h *Hub) unregisterClient(client *Client) {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ if _, ok := h.clients[client]; ok {
+ // Hapus dari peta klien utama
+ delete(h.clients, client)
+ close(client.Send)
+
+ // Hapus dari peta berdasarkan ID
+ delete(h.clientsByID, client.ID)
+
+ // Hapus dari peta berdasarkan ID statis
+ if client.StaticID != "" {
+ delete(h.clientsByStatic, client.StaticID)
+ }
+
+ // Hapus dari peta berdasarkan IP
+ if ipClients, exists := h.clientsByIP[client.IPAddress]; exists {
+ for i, c := range ipClients {
+ if c == client {
+ h.clientsByIP[client.IPAddress] = append(ipClients[:i], ipClients[i+1:]...)
+ break
+ }
+ }
+ // Jika tidak ada lagi klien dari IP ini, hapus entri IP
+ if len(h.clientsByIP[client.IPAddress]) == 0 {
+ delete(h.clientsByIP, client.IPAddress)
+ }
+ }
+
+ // Hapus dari ruangan
+ if client.Room != "" {
+ if room, exists := h.rooms[client.Room]; exists {
+ delete(room, client)
+ if len(room) == 0 {
+ delete(h.rooms, client.Room)
+ }
+ }
+ }
+ }
+
+ // Log aktivitas
+ h.logActivity("client_disconnected", client.ID,
+ fmt.Sprintf("IP: %s, Duration: %v", client.IPAddress, time.Since(client.connectedAt)))
+
+ client.cancel()
+}
+
+// broadcastToClients mengirim pesan ke klien yang sesuai
+func (h *Hub) broadcastToClients(message WebSocketMessage) {
+ h.mu.RLock()
+ defer h.mu.RUnlock()
+
+ if message.ClientID != "" {
+ // Kirim ke klien tertentu
+ if client, exists := h.clientsByID[message.ClientID]; exists {
+ select {
+ case client.Send <- message:
+ default:
+ go func() {
+ h.unregister <- client
+ }()
+ }
+ }
+ return
+ }
+
+ // Periksa apakah ini pesan ruangan
+ if message.Room != "" {
+ if room, roomExists := h.rooms[message.Room]; roomExists {
+ for client := range room {
+ select {
+ case client.Send <- message:
+ default:
+ go func(c *Client) {
+ h.unregister <- c
+ }(client)
+ }
+ }
+ }
+ return
+ }
+
+ // Broadcast ke semua klien
+ for client := range h.clients {
+ select {
+ case client.Send <- message:
+ default:
+ go func(c *Client) {
+ h.unregister <- c
+ }(client)
+ }
+ }
+}
+
+// logActivity mencatat aktivitas
+func (h *Hub) logActivity(event, clientID, details string) {
+ h.activityMu.Lock()
+ defer h.activityMu.Unlock()
+
+ activity := ActivityLog{
+ Timestamp: time.Now(),
+ Event: event,
+ ClientID: clientID,
+ Details: details,
+ }
+
+ h.activityLog = append(h.activityLog, activity)
+
+ // Pertahankan hanya aktivitas terakhir sesuai konfigurasi
+ if len(h.activityLog) > h.config.ActivityLogSize {
+ h.activityLog = h.activityLog[1:]
+ }
+}
+
+// GetConfig mengembalikan konfigurasi hub
+func (h *Hub) GetConfig() config.WebSocketConfig {
+ return h.config
+}
+
+// GetMessageRegistry mengembalikan registry pesan
+func (h *Hub) GetMessageRegistry() *MessageRegistry {
+ return h.messageRegistry
+}
+
+// RegisterChannel mengembalikan channel register untuk handler
+func (h *Hub) RegisterChannel() chan *Client {
+ return h.register
+}
+
+// GetStats mengembalikan statistik hub
+func (h *Hub) GetStats() map[string]interface{} {
+ h.mu.RLock()
+ defer h.mu.RUnlock()
+
+ return map[string]interface{}{
+ "connected_clients": len(h.clients),
+ "unique_ips": len(h.clientsByIP),
+ "static_clients": len(h.clientsByStatic),
+ "rooms": len(h.rooms),
+ "message_count": h.messageCount,
+ "error_count": h.errorCount,
+ "uptime": time.Since(h.startTime).String(),
+ "server_id": h.config.ServerID,
+ "timestamp": time.Now().Unix(),
+ }
+}
+
+// setupDatabaseListeners sets up database change listeners for real-time updates
+func (h *Hub) setupDatabaseListeners() {
+ // Listen for changes on retribusi table
+ channels := []string{"retribusi_changes", "data_changes"}
+
+ err := h.dbService.ListenForChanges(h.ctx, "postgres_satudata", channels, func(channel, payload string) {
+ h.handleDatabaseChange(channel, payload)
+ })
+
+ if err != nil {
+ h.logActivity("database_listener_error", "", fmt.Sprintf("Failed to setup listeners: %v", err))
+ } else {
+ h.logActivity("database_listener_started", "", "Database change listeners initialized")
+ }
+}
+
+// handleDatabaseChange processes database change notifications
+func (h *Hub) handleDatabaseChange(channel, payload string) {
+ h.logActivity("database_change", "", fmt.Sprintf("Channel: %s, Payload: %s", channel, payload))
+
+ // Parse the payload to determine what changed
+ var changeData map[string]interface{}
+ if err := json.Unmarshal([]byte(payload), &changeData); err != nil {
+ h.logActivity("database_change_parse_error", "", fmt.Sprintf("Failed to parse payload: %v", err))
+ return
+ }
+
+ // Create WebSocket message for broadcasting
+ message := WebSocketMessage{
+ Type: DatabaseChangeMessage,
+ Data: changeData,
+ ClientID: "",
+ Room: "data_updates", // Broadcast to data_updates room
+ }
+
+ // Broadcast the change to all connected clients in the data_updates room
+ h.broadcast <- message
+}
+
+// GetDatabaseConnection returns a database connection for the specified database
+func (h *Hub) GetDatabaseConnection(dbName string) (*sql.DB, error) {
+ return h.dbService.GetDB(dbName)
+}
+
+// ExecuteDatabaseQuery executes a database query and returns results
+func (h *Hub) ExecuteDatabaseQuery(dbName, query string, args ...interface{}) ([]map[string]interface{}, error) {
+ db, err := h.GetDatabaseConnection(dbName)
+ if err != nil {
+ return nil, fmt.Errorf("failed to get database connection: %w", err)
+ }
+
+ ctx, cancel := context.WithTimeout(h.ctx, 30*time.Second)
+ defer cancel()
+
+ rows, err := db.QueryContext(ctx, query, args...)
+ if err != nil {
+ return nil, fmt.Errorf("failed to execute query: %w", err)
+ }
+ defer rows.Close()
+
+ columns, err := rows.Columns()
+ if err != nil {
+ return nil, fmt.Errorf("failed to get columns: %w", err)
+ }
+
+ var results []map[string]interface{}
+
+ for rows.Next() {
+ values := make([]interface{}, len(columns))
+ valuePtrs := make([]interface{}, len(columns))
+ for i := range values {
+ valuePtrs[i] = &values[i]
+ }
+
+ if err := rows.Scan(valuePtrs...); err != nil {
+ return nil, fmt.Errorf("failed to scan row: %w", err)
+ }
+
+ row := make(map[string]interface{})
+ for i, col := range columns {
+ val := values[i]
+ if b, ok := val.([]byte); ok {
+ val = string(b)
+ }
+ row[col] = val
+ }
+ results = append(results, row)
+ }
+
+ if err := rows.Err(); err != nil {
+ return nil, fmt.Errorf("rows iteration error: %w", err)
+ }
+
+ return results, nil
+}
+
+// NotifyDatabaseChange sends a notification to the database for real-time updates
+func (h *Hub) NotifyDatabaseChange(dbName, channel, payload string) error {
+ return h.dbService.NotifyChange(dbName, channel, payload)
+}
diff --git a/internal/services/websocket/message.go b/internal/services/websocket/message.go
new file mode 100644
index 0000000..9952b3e
--- /dev/null
+++ b/internal/services/websocket/message.go
@@ -0,0 +1,109 @@
+package websocket
+
+import (
+ "time"
+
+ "github.com/google/uuid"
+)
+
+// MessageType mendefinisikan tipe-tipe pesan yang valid
+type MessageType string
+
+const (
+ // Pesan koneksi
+ WelcomeMessage MessageType = "welcome"
+ ErrorMessage MessageType = "error"
+ DisconnectMessage MessageType = "disconnect"
+
+ // Pesan kontrol
+ PingMessage MessageType = "ping"
+ PongMessage MessageType = "pong"
+ HeartbeatMessage MessageType = "heartbeat"
+ ConnectionTestMessage MessageType = "connection_test"
+
+ // Pesan informasi
+ ServerInfoMessage MessageType = "server_info"
+ ClientInfoMessage MessageType = "client_info"
+ OnlineUsersMessage MessageType = "online_users"
+
+ // Pesan komunikasi
+ DirectMessage MessageType = "direct_message"
+ RoomMessage MessageType = "room_message"
+ BroadcastMessage MessageType = "broadcast"
+
+ // Pesan database
+ DatabaseQueryMessage MessageType = "database_query"
+ DatabaseChangeMessage MessageType = "database_change"
+ DatabaseInsertMessage MessageType = "db_insert"
+ DatabaseCustomQueryMessage MessageType = "db_custom_query"
+
+ // Pesan monitoring
+ SystemStatusMessage MessageType = "system_status"
+ DataStreamMessage MessageType = "data_stream"
+
+ // Pesan room management
+ JoinRoomMessage MessageType = "join_room"
+ LeaveRoomMessage MessageType = "leave_room"
+ GetRoomInfoMessage MessageType = "get_room_info"
+
+ // Pesan admin
+ AdminKickClientMessage MessageType = "admin_kick_client"
+ AdminKillServerMessage MessageType = "admin_kill_server"
+ GetServerStatsMessage MessageType = "get_server_stats"
+ GetSystemHealthMessage MessageType = "get_system_health"
+ AdminClearLogsMessage MessageType = "admin_clear_logs"
+
+ // Pesan utility
+ GetStatsMessage MessageType = "get_stats"
+)
+
+// WebSocketMessage menyimpan struktur pesan WebSocket
+type WebSocketMessage struct {
+ Type MessageType `json:"type"`
+ Data interface{} `json:"data"`
+ Timestamp time.Time `json:"timestamp"`
+ ClientID string `json:"client_id,omitempty"`
+ MessageID string `json:"message_id,omitempty"`
+ Room string `json:"room,omitempty"`
+}
+
+// NewWebSocketMessage membuat pesan WebSocket baru
+func NewWebSocketMessage(msgType MessageType, data interface{}, clientID, room string) WebSocketMessage {
+ return WebSocketMessage{
+ Type: msgType,
+ Data: data,
+ Timestamp: time.Now(),
+ ClientID: clientID,
+ MessageID: uuid.New().String(),
+ Room: room,
+ }
+}
+
+// MessageHandler mendefinisikan interface untuk handler pesan
+type MessageHandler interface {
+ HandleMessage(client *Client, message WebSocketMessage) error
+ MessageType() MessageType
+}
+
+// MessageRegistry menyimpan registry untuk handler pesan
+type MessageRegistry struct {
+ handlers map[MessageType]MessageHandler
+}
+
+// NewMessageRegistry membuat registry pesan baru
+func NewMessageRegistry() *MessageRegistry {
+ return &MessageRegistry{
+ handlers: make(map[MessageType]MessageHandler),
+ }
+}
+
+// RegisterHandler mendaftarkan handler untuk tipe pesan tertentu
+func (r *MessageRegistry) RegisterHandler(handler MessageHandler) {
+ r.handlers[handler.MessageType()] = handler
+}
+
+// GetHandler mendapatkan handler untuk tipe pesan tertentu
+func (r *MessageRegistry) GetHandler(msgType MessageType) (MessageHandler, bool) {
+ handler, exists := r.handlers[msgType]
+ return handler, exists
+}
diff --git a/internal/services/websocket/monitor.go b/internal/services/websocket/monitor.go
new file mode 100644
index 0000000..ec9c8f6
--- /dev/null
+++ b/internal/services/websocket/monitor.go
@@ -0,0 +1,211 @@
+package websocket
+
+import (
+ "fmt"
+ "time"
+)
+
+// DetailedStats menyimpan statistik detail WebSocket
+type DetailedStats struct {
+ ConnectedClients int `json:"connected_clients"`
+ UniqueIPs int `json:"unique_ips"`
+ StaticClients int `json:"static_clients"`
+ ActiveRooms int `json:"active_rooms"`
+ IPDistribution map[string]int `json:"ip_distribution"`
+ RoomDistribution map[string]int `json:"room_distribution"`
+ MessageQueueSize int `json:"message_queue_size"`
+ QueueWorkers int `json:"queue_workers"`
+ Uptime time.Duration `json:"uptime_seconds"`
+ Timestamp int64 `json:"timestamp"`
+}
+
+// ClientInfo menyimpan informasi klien
+type ClientInfo struct {
+ ID string `json:"id"`
+ StaticID string `json:"static_id"`
+ IPAddress string `json:"ip_address"`
+ UserID string `json:"user_id"`
+ Room string `json:"room"`
+ ConnectedAt time.Time `json:"connected_at"`
+ LastPing time.Time `json:"last_ping"`
+ LastPong time.Time `json:"last_pong"`
+ IsActive bool `json:"is_active"`
+}
+
+// MonitoringData menyimpan data monitoring lengkap
+type MonitoringData struct {
+ Stats DetailedStats `json:"stats"`
+ RecentActivity []ActivityLog `json:"recent_activity"`
+ SystemHealth map[string]interface{} `json:"system_health"`
+ Performance PerformanceMetrics `json:"performance"`
+}
+
+// PerformanceMetrics menyimpan metrik performa
+type PerformanceMetrics struct {
+ MessagesPerSecond float64 `json:"messages_per_second"`
+ AverageLatency float64 `json:"average_latency_ms"`
+ ErrorRate float64 `json:"error_rate_percent"`
+ MemoryUsage int64 `json:"memory_usage_bytes"`
+}
+
+// MonitoringManager mengelola monitoring WebSocket
+type MonitoringManager struct {
+ hub *Hub
+}
+
+// NewMonitoringManager membuat manajer monitoring baru
+func NewMonitoringManager(hub *Hub) *MonitoringManager {
+ return &MonitoringManager{hub: hub}
+}
+
+// GetDetailedStats mengembalikan statistik detail
+func (m *MonitoringManager) GetDetailedStats() DetailedStats {
+ m.hub.mu.RLock()
+ defer m.hub.mu.RUnlock()
+
+ // Hitung distribusi IP
+ ipDistribution := make(map[string]int)
+ for ip, clients := range m.hub.clientsByIP {
+ ipDistribution[ip] = len(clients)
+ }
+
+ // Hitung distribusi ruangan
+ roomDistribution := make(map[string]int)
+ for room, clients := range m.hub.rooms {
+ roomDistribution[room] = len(clients)
+ }
+
+ return DetailedStats{
+ ConnectedClients: len(m.hub.clients),
+ UniqueIPs: len(m.hub.clientsByIP),
+ StaticClients: len(m.hub.clientsByStatic),
+ ActiveRooms: len(m.hub.rooms),
+ IPDistribution: ipDistribution,
+ RoomDistribution: roomDistribution,
+ MessageQueueSize: len(m.hub.messageQueue),
+ QueueWorkers: m.hub.config.QueueWorkers,
+ Uptime: time.Since(m.hub.startTime),
+ Timestamp: time.Now().Unix(),
+ }
+}
+
+// GetAllClients mengembalikan semua klien yang terhubung
+func (m *MonitoringManager) GetAllClients() []ClientInfo {
+ m.hub.mu.RLock()
+ defer m.hub.mu.RUnlock()
+
+ var clients []ClientInfo
+ for client := range m.hub.clients {
+ clientInfo := ClientInfo{
+ ID: client.ID,
+ StaticID: client.StaticID,
+ IPAddress: client.IPAddress,
+ UserID: client.UserID,
+ Room: client.Room,
+ ConnectedAt: client.connectedAt,
+ LastPing: client.lastPing,
+ LastPong: client.lastPong,
+ IsActive: client.isClientActive(),
+ }
+ clients = append(clients, clientInfo)
+ }
+
+ return clients
+}
+
+// GetMonitoringData mengembalikan data monitoring lengkap
+func (m *MonitoringManager) GetMonitoringData() MonitoringData {
+ stats := m.GetDetailedStats()
+
+ m.hub.activityMu.RLock()
+ recentActivity := make([]ActivityLog, 0)
+ // Dapatkan 100 aktivitas terakhir
+ start := len(m.hub.activityLog) - 100
+ if start < 0 {
+ start = 0
+ }
+ for i := start; i < len(m.hub.activityLog); i++ {
+ recentActivity = append(recentActivity, m.hub.activityLog[i])
+ }
+ m.hub.activityMu.RUnlock()
+
+ // Dapatkan kesehatan sistem dari layanan database
+ systemHealth := make(map[string]interface{})
+ if m.hub.dbService != nil {
+ systemHealth["databases"] = m.hub.dbService.Health()
+ systemHealth["available_dbs"] = m.hub.dbService.ListDBs()
+ }
+ systemHealth["websocket_status"] = "healthy"
+ systemHealth["uptime_seconds"] = time.Since(m.hub.startTime).Seconds()
+
+ // Hitung metrik performa
+ uptime := time.Since(m.hub.startTime)
+ var messagesPerSecond float64
+ var errorRate float64
+
+ if uptime.Seconds() > 0 {
+ messagesPerSecond = float64(m.hub.messageCount) / uptime.Seconds()
+ }
+
+ if m.hub.messageCount > 0 {
+ errorRate = (float64(m.hub.errorCount) / float64(m.hub.messageCount)) * 100
+ }
+
+ performance := PerformanceMetrics{
+ MessagesPerSecond: messagesPerSecond,
+ AverageLatency: 2.5, // Nilai mock - implementasi pelacakan latensi aktual
+ ErrorRate: errorRate,
+ MemoryUsage: 0, // Nilai mock - implementasi pelacakan memori aktual
+ }
+
+ return MonitoringData{
+ Stats: stats,
+ RecentActivity: recentActivity,
+ SystemHealth: systemHealth,
+ Performance: performance,
+ }
+}
+
+// CleanupInactiveClients membersihkan klien tidak aktif
+func (m *MonitoringManager) CleanupInactiveClients(inactiveTimeout time.Duration) int {
+ m.hub.mu.RLock()
+ var inactiveClients []*Client
+ cutoff := time.Now().Add(-inactiveTimeout)
+
+ for client := range m.hub.clients {
+ if client.lastPing.Before(cutoff) {
+ inactiveClients = append(inactiveClients, client)
+ }
+ }
+ m.hub.mu.RUnlock()
+
+ // Putuskan koneksi klien tidak aktif
+ for _, client := range inactiveClients {
+ m.hub.logActivity("cleanup_disconnect", client.ID,
+ fmt.Sprintf("Inactive for %v", time.Since(client.lastPing)))
+ client.cancel()
+ client.Conn.Close()
+ }
+
+ return len(inactiveClients)
+}
+
+// DisconnectClient memutuskan koneksi klien tertentu
+func (m *MonitoringManager) DisconnectClient(clientID string) bool {
+ m.hub.mu.RLock()
+ client, exists := m.hub.clientsByID[clientID]
+ m.hub.mu.RUnlock()
+
+ if !exists {
+ return false
+ }
+
+ // Log aktivitas
+ m.hub.logActivity("force_disconnect", clientID, "Client disconnected by admin")
+
+ // Batalkan context dan tutup koneksi
+ client.cancel()
+ client.Conn.Close()
+
+ return true
+}