diff --git a/src/Pages/GlobalConfigurations/Authorization/APITokens/CreateAPIToken.tsx b/src/Pages/GlobalConfigurations/Authorization/APITokens/CreateAPIToken.tsx index 8f9c149c1f..f63a35ff8a 100644 --- a/src/Pages/GlobalConfigurations/Authorization/APITokens/CreateAPIToken.tsx +++ b/src/Pages/GlobalConfigurations/Authorization/APITokens/CreateAPIToken.tsx @@ -102,6 +102,8 @@ const CreateAPIToken = ({ userRoleGroups, isSaveDisabled, allowManageAllAccess, + observabilityPermission, + setObservabilityPermission, } = usePermissionConfiguration() const [customDate, setCustomDate] = useState(dayjs().add(1, 'day').toDate()) const [tokenResponse, setTokenResponse] = useState({ @@ -180,7 +182,15 @@ const CreateAPIToken = ({ } const handleGenerateAPIToken = async () => { - if (!validateDirectPermissionForm(directPermission, setDirectPermission, allowManageAllAccess).isValid) { + if ( + !validateDirectPermissionForm( + directPermission, + setDirectPermission, + observabilityPermission, + setObservabilityPermission, + allowManageAllAccess, + ).isValid + ) { return } @@ -226,6 +236,7 @@ const CreateAPIToken = ({ k8sPermission, permissionType, userGroups: [], + observabilityPermission, canManageAllAccess: allowManageAllAccess, ...getDefaultUserStatusAndTimeout(), }) diff --git a/src/Pages/GlobalConfigurations/Authorization/APITokens/EditAPIToken.tsx b/src/Pages/GlobalConfigurations/Authorization/APITokens/EditAPIToken.tsx index 08996a41f5..1731861e5e 100644 --- a/src/Pages/GlobalConfigurations/Authorization/APITokens/EditAPIToken.tsx +++ b/src/Pages/GlobalConfigurations/Authorization/APITokens/EditAPIToken.tsx @@ -83,6 +83,8 @@ const EditAPIToken = ({ userRoleGroups, isSaveDisabled, allowManageAllAccess, + observabilityPermission, + setObservabilityPermission, } = usePermissionConfiguration() const navigate = useNavigate() @@ -106,7 +108,15 @@ const EditAPIToken = ({ } const handleUpdatedToken = async (tokenId) => { - if (!validateDirectPermissionForm(directPermission, setDirectPermission, allowManageAllAccess).isValid) { + if ( + !validateDirectPermissionForm( + directPermission, + setDirectPermission, + observabilityPermission, + setObservabilityPermission, + allowManageAllAccess, + ).isValid + ) { return } @@ -135,6 +145,7 @@ const EditAPIToken = ({ permissionType, userGroups: [], canManageAllAccess: allowManageAllAccess, + observabilityPermission, ...getDefaultUserStatusAndTimeout(), }) diff --git a/src/Pages/GlobalConfigurations/Authorization/PermissionGroups/AddEdit/PermissionGroupForm.tsx b/src/Pages/GlobalConfigurations/Authorization/PermissionGroups/AddEdit/PermissionGroupForm.tsx index 08ccda1110..992d42550d 100644 --- a/src/Pages/GlobalConfigurations/Authorization/PermissionGroups/AddEdit/PermissionGroupForm.tsx +++ b/src/Pages/GlobalConfigurations/Authorization/PermissionGroups/AddEdit/PermissionGroupForm.tsx @@ -60,6 +60,8 @@ const PermissionGroupForm = ({ isAddMode }: { isAddMode: boolean }) => { data: permissionGroup, isSaveDisabled, allowManageAllAccess, + observabilityPermission, + setObservabilityPermission, } = usePermissionConfiguration() const _permissionGroup = permissionGroup as PermissionGroup @@ -103,7 +105,13 @@ const PermissionGroupForm = ({ isAddMode }: { isAddMode: boolean }) => { } if ( !isSuperAdminPermission && - !validateDirectPermissionForm(directPermission, setDirectPermission, allowManageAllAccess).isValid + !validateDirectPermissionForm( + directPermission, + setDirectPermission, + observabilityPermission, + setObservabilityPermission, + allowManageAllAccess, + ).isValid ) { return } @@ -114,6 +122,7 @@ const PermissionGroupForm = ({ isAddMode }: { isAddMode: boolean }) => { directPermission, serverMode, chartPermission, + observabilityPermission, }) const payload: PermissionGroupCreateOrUpdatePayload = { diff --git a/src/Pages/GlobalConfigurations/Authorization/Shared/components/AppPermissions/AppPermissions.component.tsx b/src/Pages/GlobalConfigurations/Authorization/Shared/components/AppPermissions/AppPermissions.component.tsx index 6761433760..9b4ef13b58 100644 --- a/src/Pages/GlobalConfigurations/Authorization/Shared/components/AppPermissions/AppPermissions.component.tsx +++ b/src/Pages/GlobalConfigurations/Authorization/Shared/components/AppPermissions/AppPermissions.component.tsx @@ -26,6 +26,7 @@ import { GenericSectionErrorState, logExceptionToSentry, mapByKey, + ObservabilityPermissionFilter, ReactSelectInputAction, showError, stringComparatorBySortOrder, @@ -34,6 +35,7 @@ import { useMainContext, } from '@devtron-labs/devtron-fe-common-lib' +import { importComponentFromFELibrary } from '@Components/common' import { getUserAccessAllWorkflows, getUserAccessChartGroups, @@ -74,11 +76,15 @@ import { getRoleConfigForRoleFilter, } from './utils' +const ObservabilityPermissions = importComponentFromFELibrary('ObservabilityPermissions', null, 'function') + const AppPermissions = () => { const { serverMode } = useMainContext() const { directPermission, setDirectPermission, + observabilityPermission, + setObservabilityPermission, setChartPermission, setK8sPermission, currentK8sPermissionRef, @@ -656,6 +662,21 @@ const AppPermissions = () => { setK8sPermission(_k8sPermission) } + // Observability Permissions + const _observabilityPermission: ObservabilityPermissionFilter[] = (roleFilters ?? []) + .filter((roleFilter) => roleFilter.entity === EntityTypes.OBSERVABILITY) + .map(({ action, entityName, tenant, status, timeToLive }) => ({ + action: action as ActionTypes.ADMIN | ActionTypes.VIEW, + tenant: { label: tenant, value: tenant }, + entityName: entityName?.split(',')?.map((entity) => ({ value: entity, label: entity })) || [], + status, + timeToLive, + })) + + if (_observabilityPermission.length) { + setObservabilityPermission(_observabilityPermission) + } + setIsLoading(false) } @@ -921,6 +942,8 @@ const AppPermissions = () => { const { accessTypeToErrorMap: _accessTypeToErrorMap } = validateDirectPermissionForm( directPermission, setDirectPermission, + observabilityPermission, + setObservabilityPermission, allowManageAllAccess, false, ) @@ -1026,6 +1049,17 @@ const AppPermissions = () => { {isNonEAMode && ( } /> )} + {ObservabilityPermissions && ( + + } + /> + )} diff --git a/src/Pages/GlobalConfigurations/Authorization/Shared/components/PermissionConfigurationForm/PermissionConfigurationFormProvider.tsx b/src/Pages/GlobalConfigurations/Authorization/Shared/components/PermissionConfigurationForm/PermissionConfigurationFormProvider.tsx index dcf6f59f9c..c7784aff8d 100644 --- a/src/Pages/GlobalConfigurations/Authorization/Shared/components/PermissionConfigurationForm/PermissionConfigurationFormProvider.tsx +++ b/src/Pages/GlobalConfigurations/Authorization/Shared/components/PermissionConfigurationForm/PermissionConfigurationFormProvider.tsx @@ -16,7 +16,13 @@ import React, { createContext, ReactNode, useContext, useEffect, useMemo, useRef, useState } from 'react' -import { ActionTypes, EntityTypes, useGetUserRoles, UserStatus } from '@devtron-labs/devtron-fe-common-lib' +import { + ActionTypes, + EntityTypes, + ObservabilityPermissionFilter, + useGetUserRoles, + UserStatus, +} from '@devtron-labs/devtron-fe-common-lib' import { importComponentFromFELibrary } from '../../../../../../components/common' import { PermissionType } from '../../../constants' @@ -60,6 +66,7 @@ export const PermissionConfigurationFormProvider = ({ ...getDefaultStatusAndTimeout(), }) const [k8sPermission, setK8sPermission] = useState([]) + const [observabilityPermission, setObservabilityPermission] = useState([]) const currentK8sPermissionRef = useRef([]) const [userRoleGroups, _setUserRoleGroups] = useState([]) @@ -123,6 +130,8 @@ export const PermissionConfigurationFormProvider = ({ setDirectPermission, chartPermission, setChartPermission, + observabilityPermission, + setObservabilityPermission, k8sPermission, setK8sPermission, currentK8sPermissionRef, @@ -148,6 +157,8 @@ export const PermissionConfigurationFormProvider = ({ setDirectPermission, chartPermission, setChartPermission, + observabilityPermission, + setObservabilityPermission, k8sPermission, setK8sPermission, currentK8sPermissionRef, diff --git a/src/Pages/GlobalConfigurations/Authorization/Shared/components/PermissionConfigurationForm/types.ts b/src/Pages/GlobalConfigurations/Authorization/Shared/components/PermissionConfigurationForm/types.ts index 9d089bdffc..013878c64e 100644 --- a/src/Pages/GlobalConfigurations/Authorization/Shared/components/PermissionConfigurationForm/types.ts +++ b/src/Pages/GlobalConfigurations/Authorization/Shared/components/PermissionConfigurationForm/types.ts @@ -16,6 +16,8 @@ import React from 'react' +import { ObservabilityPermissionFilter } from '@devtron-labs/devtron-fe-common-lib' + import { PermissionType } from '../../../constants' import { ChartGroupPermissionsFilter, @@ -52,6 +54,8 @@ export interface PermissionConfigurationFormContext { k8sPermission?: K8sPermissionFilter[] setK8sPermission?: React.Dispatch> currentK8sPermissionRef?: React.MutableRefObject + observabilityPermission: ObservabilityPermissionFilter[] + setObservabilityPermission: React.Dispatch> /** * Flag to control if status should be shown in the form * @@ -82,6 +86,6 @@ export interface PermissionConfigurationFormContext { } export type AccessTypeToErrorMapType = Record< - PermissionConfigurationFormContext['directPermission'][number]['accessType'], + PermissionConfigurationFormContext['directPermission'][number]['accessType'] | 'observability', boolean > diff --git a/src/Pages/GlobalConfigurations/Authorization/UserPermissions/AddEdit/UserForm.tsx b/src/Pages/GlobalConfigurations/Authorization/UserPermissions/AddEdit/UserForm.tsx index 56885e569b..ed053d104b 100644 --- a/src/Pages/GlobalConfigurations/Authorization/UserPermissions/AddEdit/UserForm.tsx +++ b/src/Pages/GlobalConfigurations/Authorization/UserPermissions/AddEdit/UserForm.tsx @@ -81,6 +81,8 @@ const UserForm = ({ isAddMode }: { isAddMode: boolean }) => { showStatus, isSaveDisabled, allowManageAllAccess, + observabilityPermission, + setObservabilityPermission, } = usePermissionConfiguration() const _userData = userData as User @@ -135,7 +137,13 @@ const UserForm = ({ isAddMode }: { isAddMode: boolean }) => { const handleSubmit = async () => { if ( !validateForm() || - !validateDirectPermissionForm(directPermission, setDirectPermission, allowManageAllAccess).isValid + !validateDirectPermissionForm( + directPermission, + setDirectPermission, + observabilityPermission, + setObservabilityPermission, + allowManageAllAccess, + ).isValid ) { return } @@ -153,6 +161,7 @@ const UserForm = ({ isAddMode }: { isAddMode: boolean }) => { permissionType, userGroups: selectedUserGroups, canManageAllAccess: allowManageAllAccess, + observabilityPermission, ...getDefaultUserStatusAndTimeout(), }) diff --git a/src/Pages/GlobalConfigurations/Authorization/constants.ts b/src/Pages/GlobalConfigurations/Authorization/constants.ts index 0858315231..39a0be3b55 100644 --- a/src/Pages/GlobalConfigurations/Authorization/constants.ts +++ b/src/Pages/GlobalConfigurations/Authorization/constants.ts @@ -60,4 +60,5 @@ export const DEFAULT_ACCESS_TYPE_TO_ERROR_MAP: AccessTypeToErrorMapType = { [ACCESS_TYPE_MAP.DEVTRON_APPS]: false, [ACCESS_TYPE_MAP.HELM_APPS]: false, [ACCESS_TYPE_MAP.JOBS]: false, + observability: false, } as const diff --git a/src/Pages/GlobalConfigurations/Authorization/types.ts b/src/Pages/GlobalConfigurations/Authorization/types.ts index 70c3c5ff39..23f1a0239c 100644 --- a/src/Pages/GlobalConfigurations/Authorization/types.ts +++ b/src/Pages/GlobalConfigurations/Authorization/types.ts @@ -25,6 +25,7 @@ import { DeleteConfirmationModalProps, EntityTypes, K8sResourceListPayloadType, + ObservabilityPermissionFilter, OptionType, ResourceKindType, UserGroupDTO, @@ -51,7 +52,12 @@ export interface UserAndGroupPermissionsWrapProps { type PermissionStatusAndTimeout = Pick export interface APIRoleFilterDto { - entity: EntityTypes.DIRECT | EntityTypes.CHART_GROUP | EntityTypes.CLUSTER | EntityTypes.JOB + entity: + | EntityTypes.DIRECT + | EntityTypes.CHART_GROUP + | EntityTypes.CLUSTER + | EntityTypes.JOB + | EntityTypes.OBSERVABILITY team?: string entityName?: string environment?: string @@ -72,6 +78,7 @@ export interface APIRoleFilterDto { // eslint-disable-next-line @typescript-eslint/no-explicit-any resource?: any workflow?: string + tenant?: string status: UserStatusDto timeoutWindowExpression: string /** @@ -277,7 +284,7 @@ interface RoleFilter { export interface DirectPermissionsRoleFilter extends RoleFilter, PermissionStatusAndTimeout { entity: EntityTypes.DIRECT | EntityTypes.JOB - accessType: ACCESS_TYPE_MAP.DEVTRON_APPS | ACCESS_TYPE_MAP.HELM_APPS | ACCESS_TYPE_MAP.JOBS + accessType: ACCESS_TYPE_MAP team: OptionType entityName: OptionType[] entityNameError?: string @@ -319,6 +326,7 @@ export interface CreateUserPermissionPayloadParams chartPermission: ChartGroupPermissionsFilter k8sPermission: K8sPermissionFilter[] permissionType: PermissionType + observabilityPermission: ObservabilityPermissionFilter[] } export interface DeleteUserPermissionProps diff --git a/src/Pages/GlobalConfigurations/Authorization/utils.ts b/src/Pages/GlobalConfigurations/Authorization/utils.ts index 067e7db88a..83b39185e5 100644 --- a/src/Pages/GlobalConfigurations/Authorization/utils.ts +++ b/src/Pages/GlobalConfigurations/Authorization/utils.ts @@ -77,6 +77,10 @@ const getPermissionActionValue: (roleConfig: UserRoleConfig) => string = importC 'function', ) +const validateObservabilityPermissions: ({ observabilityPermission, setObservabilityPermission }) => { + isValid: boolean +} = importComponentFromFELibrary('validateObservabilityPermissions', null, 'function') + const DEPLOYMENT_APPROVER_ROLE_VALUE = importComponentFromFELibrary('DEPLOYMENT_APPROVER_ROLE_VALUE', null, 'function') const getKeyForRoleFilter = ({ entity, team, environment, accessType, entityName, workflow }: APIRoleFilterDto) => @@ -388,9 +392,15 @@ export const getRolesAndAccessRoles = ({ chartPermission, serverMode, canManageAllAccess, + observabilityPermission, }: Pick< CreateUserPermissionPayloadParams, - 'chartPermission' | 'directPermission' | 'serverMode' | 'k8sPermission' | 'canManageAllAccess' + | 'chartPermission' + | 'directPermission' + | 'serverMode' + | 'k8sPermission' + | 'canManageAllAccess' + | 'observabilityPermission' >) => { const filteredDirectPermissions = directPermission.filter( (permission) => permission.team?.value && permission.environment.length && permission.entityName.length, @@ -411,6 +421,16 @@ export const getRolesAndAccessRoles = ({ namespace: getCommaSeparatedNamespaceList(permission.namespace), resource: getSelectedPermissionValues(permission.resource), })), + ...observabilityPermission + .filter((permission) => !!permission.tenant?.value) + .map(({ action, entityName, tenant, status, timeToLive }) => ({ + entity: EntityTypes.OBSERVABILITY as APIRoleFilter['entity'], + action, + entityName: entityName.map((entity) => entity.value).join(','), + tenant: tenant.value, + status, + timeToLive, + })), ] if (serverMode !== SERVER_MODE.EA_ONLY) { @@ -448,6 +468,7 @@ export const createUserPermissionPayload = ({ timeToLive, userGroups, canManageAllAccess, + observabilityPermission, }: CreateUserPermissionPayloadParams): UserCreateOrUpdateParamsType => { const { roleFilters, accessRoleFilters } = getRolesAndAccessRoles({ directPermission, @@ -455,6 +476,7 @@ export const createUserPermissionPayload = ({ chartPermission, serverMode, canManageAllAccess, + observabilityPermission, }) return { @@ -475,6 +497,8 @@ export const createUserPermissionPayload = ({ export const validateDirectPermissionForm = ( directPermission: PermissionConfigurationFormContext['directPermission'], setDirectPermission: PermissionConfigurationFormContext['setDirectPermission'], + observabilityPermission: PermissionConfigurationFormContext['observabilityPermission'], + setObservabilityPermission: PermissionConfigurationFormContext['setObservabilityPermission'], allowManageAllAccess: boolean, showErrorToast: boolean = true, ): { @@ -534,17 +558,27 @@ export const validateDirectPermissionForm = ( [], ) - const isFormValid = Object.values(accessTypeToErrorMap).every((val) => !val) + const { isValid: areObservabilityPermissionsValid } = validateObservabilityPermissions?.({ + observabilityPermission, + setObservabilityPermission, + }) ?? { isValid: true } - if (!isFormValid && showErrorToast) { - ToastManager.showToast({ - variant: ToastVariantType.error, - description: REQUIRED_FIELDS_MISSING, - }) + const isFormValid = Object.values(accessTypeToErrorMap).every((val) => !val) && areObservabilityPermissionsValid + + if (!isFormValid) { setDirectPermission(tempPermissions) + if (showErrorToast) { + ToastManager.showToast({ + variant: ToastVariantType.error, + description: REQUIRED_FIELDS_MISSING, + }) + } } - return { isValid: isFormValid, accessTypeToErrorMap } + return { + isValid: isFormValid, + accessTypeToErrorMap: { ...accessTypeToErrorMap, observability: !areObservabilityPermissionsValid }, + } } export const getWorkflowOptions = ( diff --git a/src/components/Navigation/constants.ts b/src/components/Navigation/constants.ts index f4e890c9be..ce428841ed 100644 --- a/src/components/Navigation/constants.ts +++ b/src/components/Navigation/constants.ts @@ -22,6 +22,12 @@ const RESOURCE_WATCHER_NAV_ITEM: NavigationItemType = importComponentFromFELibra 'function', ) +const OBSERVABILITY_NAV_ITEM: NavigationItemType = importComponentFromFELibrary( + 'OBSERVABILITY_NAV_ITEM', + null, + 'function', +) + const SECURITY_ENABLEMENT_NAV_ITEM: NavigationItemType = importComponentFromFELibrary( 'SECURITY_ENABLEMENT_NAV_ITEM', null, @@ -202,6 +208,7 @@ const NAVIGATION_LIST: NavigationGroupType[] = [ isAvailableInEA: true, }, ...(RESOURCE_WATCHER_NAV_ITEM ? [RESOURCE_WATCHER_NAV_ITEM] : []), + ...(OBSERVABILITY_NAV_ITEM ? [OBSERVABILITY_NAV_ITEM] : []), ], isAvailableInEA: true, }, diff --git a/src/components/app/details/appDetails/utils.tsx b/src/components/app/details/appDetails/utils.tsx index 8d3d3fda2d..f6fb9caf53 100644 --- a/src/components/app/details/appDetails/utils.tsx +++ b/src/components/app/details/appDetails/utils.tsx @@ -27,10 +27,10 @@ import { SelectPicker, SelectPickerProps, SelectPickerVariantType, - prefixZeroIfSingleDigit, AppEnvironment, SelectPickerOptionType, IconsProps, + getTimestampFromDateIfAvailable, DateTimePickerProps, } from '@devtron-labs/devtron-fe-common-lib' import { GetIFrameSrcParamsType, GrafanaPresetOptionHandlerType } from './types' @@ -302,25 +302,6 @@ export function addChartNameExtensionToBaseURL( return url } -// Need to send either the relative time like: now-5m or the timestamp to grafana -// Assuming format is 'DD-MM-YYYY hh:mm:ss' -const getTimestampFromDateIfAvailable = (dateString: string): string => { - try { - const [day, month, yearAndTime] = dateString.split('-') - const [year, time] = yearAndTime.split(' ') - const updatedTime = time - .split(':') - .map((item) => (['0', '00'].includes(item) ? '00' : prefixZeroIfSingleDigit(Number(item)))) - .join(':') - const formattedDate = `${year}-${prefixZeroIfSingleDigit(Number(month))}-${prefixZeroIfSingleDigit(Number(day))}T${updatedTime}` - const parsedDate = new Date(formattedDate).getTime() - - return isNaN(parsedDate) ? dateString : parsedDate.toString() - } catch { - return dateString - } -} - export function addQueryParamToGrafanaURL( url: string, appId: string | number, diff --git a/src/components/ciPipeline/Webhook/WebhookDetailsModal.tsx b/src/components/ciPipeline/Webhook/WebhookDetailsModal.tsx index 58f3177107..84b5b09e5d 100644 --- a/src/components/ciPipeline/Webhook/WebhookDetailsModal.tsx +++ b/src/components/ciPipeline/Webhook/WebhookDetailsModal.tsx @@ -243,6 +243,7 @@ export const WebhookDetailsModal = ({ close, isTemplateView }: WebhookDetailType k8sPermission: [], permissionType: PermissionType.SPECIFIC, userGroups: [], + observabilityPermission: [], ...getDefaultUserStatusAndTimeout(), }) const { result: userPermissionResponse } = await createOrUpdateUser({ diff --git a/src/components/common/navigation/NavigationRoutes.tsx b/src/components/common/navigation/NavigationRoutes.tsx index 5985505849..eff7ff021b 100644 --- a/src/components/common/navigation/NavigationRoutes.tsx +++ b/src/components/common/navigation/NavigationRoutes.tsx @@ -113,6 +113,7 @@ const SoftwareDistributionHubRenderProvider = importComponentFromFELibrary( null, 'function', ) +const Observability = importComponentFromFELibrary('Observability', null, 'function') const AskDevtronButton = importComponentFromFELibrary('AskDevtronButton', null, 'function') const migrateUserPreferences: (userPreferences: UserPreferencesType) => Promise = importComponentFromFELibrary('migrateUserPreferences', null, 'function') @@ -589,6 +590,15 @@ const NavigationRoutes = ({ reloadVersionConfig }: Readonly, ] : []), + ...(Observability + ? [ + } + />, + ] + : []), ...(serverMode === SERVER_MODE.FULL && window._env_.FEATURE_SOFTWARE_DISTRIBUTION_HUB_ENABLE && SoftwareDistributionHub diff --git a/yarn.lock b/yarn.lock index fed4550430..d0d5bff996 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1673,16 +1673,7 @@ __metadata: languageName: node linkType: hard -"@codemirror/state@npm:^6.0.0, @codemirror/state@npm:^6.1.1": - version: 6.6.0 - resolution: "@codemirror/state@npm:6.6.0" - dependencies: - "@marijn/find-cluster-break": "npm:^1.0.0" - checksum: 10c0/4e5d6ddd28fc642e8d749fe80a7dd278afd547e4d93c562eaab6f23bdf25bb12a94226db3efab6321d458c531eb6d357184809f3704aee419fe3230d53f16e24 - languageName: node - linkType: hard - -"@codemirror/state@npm:^6.4.0, @codemirror/state@npm:^6.5.0": +"@codemirror/state@npm:^6.0.0, @codemirror/state@npm:^6.1.1, @codemirror/state@npm:^6.4.0, @codemirror/state@npm:^6.5.0": version: 6.5.2 resolution: "@codemirror/state@npm:6.5.2" dependencies: @@ -1818,11 +1809,11 @@ __metadata: linkType: hard "@emnapi/runtime@npm:^1.2.0": - version: 1.9.1 - resolution: "@emnapi/runtime@npm:1.9.1" + version: 1.4.3 + resolution: "@emnapi/runtime@npm:1.4.3" dependencies: tslib: "npm:^2.4.0" - checksum: 10c0/750edca117e0363ab2de10622f8ee60e57d8690c2f29c49704813da5cd627c641798d7f3cb0d953c62fdc71688e02e333ddbf2c1204f38b47e3e40657332a6f5 + checksum: 10c0/3b7ab72d21cb4e034f07df80165265f85f445ef3f581d1bc87b67e5239428baa00200b68a7d5e37a0425c3a78320b541b07f76c5530f6f6f95336a6294ebf30b languageName: node linkType: hard